github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/net/net_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 package net 5 6 import ( 7 "context" 8 "fmt" 9 "net" 10 "os" 11 "syscall" 12 "unsafe" 13 14 "github.com/gofiber/fiber/v2/internal/gopsutil/common" 15 "golang.org/x/sys/windows" 16 ) 17 18 var ( 19 modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") 20 procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable") 21 procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable") 22 procGetIfEntry2 = modiphlpapi.NewProc("GetIfEntry2") 23 ) 24 25 const ( 26 TCPTableBasicListener = iota 27 TCPTableBasicConnections 28 TCPTableBasicAll 29 TCPTableOwnerPIDListener 30 TCPTableOwnerPIDConnections 31 TCPTableOwnerPIDAll 32 TCPTableOwnerModuleListener 33 TCPTableOwnerModuleConnections 34 TCPTableOwnerModuleAll 35 ) 36 37 type netConnectionKindType struct { 38 family uint32 39 sockType uint32 40 filename string 41 } 42 43 var kindTCP4 = netConnectionKindType{ 44 family: syscall.AF_INET, 45 sockType: syscall.SOCK_STREAM, 46 filename: "tcp", 47 } 48 var kindTCP6 = netConnectionKindType{ 49 family: syscall.AF_INET6, 50 sockType: syscall.SOCK_STREAM, 51 filename: "tcp6", 52 } 53 var kindUDP4 = netConnectionKindType{ 54 family: syscall.AF_INET, 55 sockType: syscall.SOCK_DGRAM, 56 filename: "udp", 57 } 58 var kindUDP6 = netConnectionKindType{ 59 family: syscall.AF_INET6, 60 sockType: syscall.SOCK_DGRAM, 61 filename: "udp6", 62 } 63 64 var netConnectionKindMap = map[string][]netConnectionKindType{ 65 "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6}, 66 "tcp": {kindTCP4, kindTCP6}, 67 "tcp4": {kindTCP4}, 68 "tcp6": {kindTCP6}, 69 "udp": {kindUDP4, kindUDP6}, 70 "udp4": {kindUDP4}, 71 "udp6": {kindUDP6}, 72 "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6}, 73 "inet4": {kindTCP4, kindUDP4}, 74 "inet6": {kindTCP6, kindUDP6}, 75 } 76 77 // https://github.com/microsoft/ethr/blob/aecdaf923970e5a9b4c461b4e2e3963d781ad2cc/plt_windows.go#L114-L170 78 type guid struct { 79 Data1 uint32 80 Data2 uint16 81 Data3 uint16 82 Data4 [8]byte 83 } 84 85 const ( 86 maxStringSize = 256 87 maxPhysAddressLength = 32 88 pad0for64_4for32 = 0 89 ) 90 91 type mibIfRow2 struct { 92 InterfaceLuid uint64 93 InterfaceIndex uint32 94 InterfaceGuid guid 95 Alias [maxStringSize + 1]uint16 96 Description [maxStringSize + 1]uint16 97 PhysicalAddressLength uint32 98 PhysicalAddress [maxPhysAddressLength]uint8 99 PermanentPhysicalAddress [maxPhysAddressLength]uint8 100 Mtu uint32 101 Type uint32 102 TunnelType uint32 103 MediaType uint32 104 PhysicalMediumType uint32 105 AccessType uint32 106 DirectionType uint32 107 InterfaceAndOperStatusFlags uint32 108 OperStatus uint32 109 AdminStatus uint32 110 MediaConnectState uint32 111 NetworkGuid guid 112 ConnectionType uint32 113 padding1 [pad0for64_4for32]byte 114 TransmitLinkSpeed uint64 115 ReceiveLinkSpeed uint64 116 InOctets uint64 117 InUcastPkts uint64 118 InNUcastPkts uint64 119 InDiscards uint64 120 InErrors uint64 121 InUnknownProtos uint64 122 InUcastOctets uint64 123 InMulticastOctets uint64 124 InBroadcastOctets uint64 125 OutOctets uint64 126 OutUcastPkts uint64 127 OutNUcastPkts uint64 128 OutDiscards uint64 129 OutErrors uint64 130 OutUcastOctets uint64 131 OutMulticastOctets uint64 132 OutBroadcastOctets uint64 133 OutQLen uint64 134 } 135 136 func IOCounters(pernic bool) ([]IOCountersStat, error) { 137 return IOCountersWithContext(context.Background(), pernic) 138 } 139 140 func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { 141 ifs, err := net.Interfaces() 142 if err != nil { 143 return nil, err 144 } 145 var counters []IOCountersStat 146 147 err = procGetIfEntry2.Find() 148 if err == nil { // Vista+, uint64 values (issue#693) 149 for _, ifi := range ifs { 150 c := IOCountersStat{ 151 Name: ifi.Name, 152 } 153 154 row := mibIfRow2{InterfaceIndex: uint32(ifi.Index)} 155 ret, _, err := procGetIfEntry2.Call(uintptr(unsafe.Pointer(&row))) 156 if ret != 0 { 157 return nil, os.NewSyscallError("GetIfEntry2", err) 158 } 159 c.BytesSent = uint64(row.OutOctets) 160 c.BytesRecv = uint64(row.InOctets) 161 c.PacketsSent = uint64(row.OutUcastPkts) 162 c.PacketsRecv = uint64(row.InUcastPkts) 163 c.Errin = uint64(row.InErrors) 164 c.Errout = uint64(row.OutErrors) 165 c.Dropin = uint64(row.InDiscards) 166 c.Dropout = uint64(row.OutDiscards) 167 168 counters = append(counters, c) 169 } 170 } else { // WinXP fallback, uint32 values 171 for _, ifi := range ifs { 172 c := IOCountersStat{ 173 Name: ifi.Name, 174 } 175 176 row := windows.MibIfRow{Index: uint32(ifi.Index)} 177 err = windows.GetIfEntry(&row) 178 if err != nil { 179 return nil, os.NewSyscallError("GetIfEntry", err) 180 } 181 c.BytesSent = uint64(row.OutOctets) 182 c.BytesRecv = uint64(row.InOctets) 183 c.PacketsSent = uint64(row.OutUcastPkts) 184 c.PacketsRecv = uint64(row.InUcastPkts) 185 c.Errin = uint64(row.InErrors) 186 c.Errout = uint64(row.OutErrors) 187 c.Dropin = uint64(row.InDiscards) 188 c.Dropout = uint64(row.OutDiscards) 189 190 counters = append(counters, c) 191 } 192 } 193 194 if !pernic { 195 return getIOCountersAll(counters) 196 } 197 return counters, nil 198 } 199 200 // NetIOCountersByFile is an method which is added just a compatibility for linux. 201 func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { 202 return IOCountersByFileWithContext(context.Background(), pernic, filename) 203 } 204 205 func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) { 206 return IOCounters(pernic) 207 } 208 209 // Return a list of network connections 210 // Available kind: 211 // 212 // reference to netConnectionKindMap 213 func Connections(kind string) ([]ConnectionStat, error) { 214 return ConnectionsWithContext(context.Background(), kind) 215 } 216 217 func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { 218 return ConnectionsPidWithContext(ctx, kind, 0) 219 } 220 221 // ConnectionsPid Return a list of network connections opened by a process 222 func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { 223 return ConnectionsPidWithContext(context.Background(), kind, pid) 224 } 225 226 func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { 227 tmap, ok := netConnectionKindMap[kind] 228 if !ok { 229 return nil, fmt.Errorf("invalid kind, %s", kind) 230 } 231 return getProcInet(tmap, pid) 232 } 233 234 func getProcInet(kinds []netConnectionKindType, pid int32) ([]ConnectionStat, error) { 235 stats := make([]ConnectionStat, 0) 236 237 for _, kind := range kinds { 238 s, err := getNetStatWithKind(kind) 239 if err != nil { 240 continue 241 } 242 243 if pid == 0 { 244 stats = append(stats, s...) 245 } else { 246 for _, ns := range s { 247 if ns.Pid != pid { 248 continue 249 } 250 stats = append(stats, ns) 251 } 252 } 253 } 254 255 return stats, nil 256 } 257 258 func getNetStatWithKind(kindType netConnectionKindType) ([]ConnectionStat, error) { 259 if kindType.filename == "" { 260 return nil, fmt.Errorf("kind filename must be required") 261 } 262 263 switch kindType.filename { 264 case kindTCP4.filename: 265 return getTCPConnections(kindTCP4.family) 266 case kindTCP6.filename: 267 return getTCPConnections(kindTCP6.family) 268 case kindUDP4.filename: 269 return getUDPConnections(kindUDP4.family) 270 case kindUDP6.filename: 271 return getUDPConnections(kindUDP6.family) 272 } 273 274 return nil, fmt.Errorf("invalid kind filename, %s", kindType.filename) 275 } 276 277 // Return a list of network connections opened returning at most `max` 278 // connections for each running process. 279 func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { 280 return ConnectionsMaxWithContext(context.Background(), kind, max) 281 } 282 283 func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { 284 return []ConnectionStat{}, common.ErrNotImplementedError 285 } 286 287 // Return a list of network connections opened, omitting `Uids`. 288 // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be 289 // removed from the API in the future. 290 func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) { 291 return ConnectionsWithoutUidsWithContext(context.Background(), kind) 292 } 293 294 func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { 295 return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0) 296 } 297 298 func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { 299 return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max) 300 } 301 302 func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) { 303 return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid) 304 } 305 306 func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { 307 return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0) 308 } 309 310 func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) { 311 return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max) 312 } 313 314 func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { 315 return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max) 316 } 317 318 func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { 319 return []ConnectionStat{}, common.ErrNotImplementedError 320 } 321 322 func FilterCounters() ([]FilterStat, error) { 323 return FilterCountersWithContext(context.Background()) 324 } 325 326 func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { 327 return nil, common.ErrNotImplementedError 328 } 329 330 func ConntrackStats(percpu bool) ([]ConntrackStat, error) { 331 return ConntrackStatsWithContext(context.Background(), percpu) 332 } 333 334 func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { 335 return nil, common.ErrNotImplementedError 336 } 337 338 // NetProtoCounters returns network statistics for the entire system 339 // If protocols is empty then all protocols are returned, otherwise 340 // just the protocols in the list are returned. 341 // Not Implemented for Windows 342 func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { 343 return ProtoCountersWithContext(context.Background(), protocols) 344 } 345 346 func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { 347 return nil, common.ErrNotImplementedError 348 } 349 350 func getTableUintptr(family uint32, buf []byte) uintptr { 351 var ( 352 pmibTCPTable pmibTCPTableOwnerPidAll 353 pmibTCP6Table pmibTCP6TableOwnerPidAll 354 355 p uintptr 356 ) 357 switch family { 358 case kindTCP4.family: 359 if len(buf) > 0 { 360 pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0])) 361 p = uintptr(unsafe.Pointer(pmibTCPTable)) 362 } else { 363 p = uintptr(unsafe.Pointer(pmibTCPTable)) 364 } 365 case kindTCP6.family: 366 if len(buf) > 0 { 367 pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0])) 368 p = uintptr(unsafe.Pointer(pmibTCP6Table)) 369 } else { 370 p = uintptr(unsafe.Pointer(pmibTCP6Table)) 371 } 372 } 373 return p 374 } 375 376 func getTableInfo(filename string, table interface{}) (index, step, length int) { 377 switch filename { 378 case kindTCP4.filename: 379 index = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).DwNumEntries)) 380 step = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).Table)) 381 length = int(table.(pmibTCPTableOwnerPidAll).DwNumEntries) 382 case kindTCP6.filename: 383 index = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).DwNumEntries)) 384 step = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).Table)) 385 length = int(table.(pmibTCP6TableOwnerPidAll).DwNumEntries) 386 case kindUDP4.filename: 387 index = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).DwNumEntries)) 388 step = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).Table)) 389 length = int(table.(pmibUDPTableOwnerPid).DwNumEntries) 390 case kindUDP6.filename: 391 index = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).DwNumEntries)) 392 step = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).Table)) 393 length = int(table.(pmibUDP6TableOwnerPid).DwNumEntries) 394 } 395 396 return 397 } 398 399 func getTCPConnections(family uint32) ([]ConnectionStat, error) { 400 var ( 401 p uintptr 402 buf []byte 403 size uint32 404 405 pmibTCPTable pmibTCPTableOwnerPidAll 406 pmibTCP6Table pmibTCP6TableOwnerPidAll 407 ) 408 409 if family == 0 { 410 return nil, fmt.Errorf("faimly must be required") 411 } 412 413 for { 414 switch family { 415 case kindTCP4.family: 416 if len(buf) > 0 { 417 pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0])) 418 p = uintptr(unsafe.Pointer(pmibTCPTable)) 419 } else { 420 p = uintptr(unsafe.Pointer(pmibTCPTable)) 421 } 422 case kindTCP6.family: 423 if len(buf) > 0 { 424 pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0])) 425 p = uintptr(unsafe.Pointer(pmibTCP6Table)) 426 } else { 427 p = uintptr(unsafe.Pointer(pmibTCP6Table)) 428 } 429 } 430 431 err := getExtendedTcpTable(p, 432 &size, 433 true, 434 family, 435 tcpTableOwnerPidAll, 436 0) 437 if err == nil { 438 break 439 } 440 if err != windows.ERROR_INSUFFICIENT_BUFFER { 441 return nil, err 442 } 443 buf = make([]byte, size) 444 } 445 446 var ( 447 index, step int 448 length int 449 ) 450 451 stats := make([]ConnectionStat, 0) 452 switch family { 453 case kindTCP4.family: 454 index, step, length = getTableInfo(kindTCP4.filename, pmibTCPTable) 455 case kindTCP6.family: 456 index, step, length = getTableInfo(kindTCP6.filename, pmibTCP6Table) 457 } 458 459 if length == 0 { 460 return nil, nil 461 } 462 463 for i := 0; i < length; i++ { 464 switch family { 465 case kindTCP4.family: 466 mibs := (*mibTCPRowOwnerPid)(unsafe.Pointer(&buf[index])) 467 ns := mibs.convertToConnectionStat() 468 stats = append(stats, ns) 469 case kindTCP6.family: 470 mibs := (*mibTCP6RowOwnerPid)(unsafe.Pointer(&buf[index])) 471 ns := mibs.convertToConnectionStat() 472 stats = append(stats, ns) 473 } 474 475 index += step 476 } 477 return stats, nil 478 } 479 480 func getUDPConnections(family uint32) ([]ConnectionStat, error) { 481 var ( 482 p uintptr 483 buf []byte 484 size uint32 485 486 pmibUDPTable pmibUDPTableOwnerPid 487 pmibUDP6Table pmibUDP6TableOwnerPid 488 ) 489 490 if family == 0 { 491 return nil, fmt.Errorf("faimly must be required") 492 } 493 494 for { 495 switch family { 496 case kindUDP4.family: 497 if len(buf) > 0 { 498 pmibUDPTable = (*mibUDPTableOwnerPid)(unsafe.Pointer(&buf[0])) 499 p = uintptr(unsafe.Pointer(pmibUDPTable)) 500 } else { 501 p = uintptr(unsafe.Pointer(pmibUDPTable)) 502 } 503 case kindUDP6.family: 504 if len(buf) > 0 { 505 pmibUDP6Table = (*mibUDP6TableOwnerPid)(unsafe.Pointer(&buf[0])) 506 p = uintptr(unsafe.Pointer(pmibUDP6Table)) 507 } else { 508 p = uintptr(unsafe.Pointer(pmibUDP6Table)) 509 } 510 } 511 512 err := getExtendedUdpTable( 513 p, 514 &size, 515 true, 516 family, 517 udpTableOwnerPid, 518 0, 519 ) 520 if err == nil { 521 break 522 } 523 if err != windows.ERROR_INSUFFICIENT_BUFFER { 524 return nil, err 525 } 526 buf = make([]byte, size) 527 } 528 529 var ( 530 index, step, length int 531 ) 532 533 stats := make([]ConnectionStat, 0) 534 switch family { 535 case kindUDP4.family: 536 index, step, length = getTableInfo(kindUDP4.filename, pmibUDPTable) 537 case kindUDP6.family: 538 index, step, length = getTableInfo(kindUDP6.filename, pmibUDP6Table) 539 } 540 541 if length == 0 { 542 return nil, nil 543 } 544 545 for i := 0; i < length; i++ { 546 switch family { 547 case kindUDP4.family: 548 mibs := (*mibUDPRowOwnerPid)(unsafe.Pointer(&buf[index])) 549 ns := mibs.convertToConnectionStat() 550 stats = append(stats, ns) 551 case kindUDP4.family: 552 mibs := (*mibUDP6RowOwnerPid)(unsafe.Pointer(&buf[index])) 553 ns := mibs.convertToConnectionStat() 554 stats = append(stats, ns) 555 } 556 557 index += step 558 } 559 return stats, nil 560 } 561 562 // tcpStatuses https://msdn.microsoft.com/en-us/library/windows/desktop/bb485761(v=vs.85).aspx 563 var tcpStatuses = map[mibTCPState]string{ 564 1: "CLOSED", 565 2: "LISTEN", 566 3: "SYN_SENT", 567 4: "SYN_RECEIVED", 568 5: "ESTABLISHED", 569 6: "FIN_WAIT_1", 570 7: "FIN_WAIT_2", 571 8: "CLOSE_WAIT", 572 9: "CLOSING", 573 10: "LAST_ACK", 574 11: "TIME_WAIT", 575 12: "DELETE", 576 } 577 578 func getExtendedTcpTable(pTcpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass tcpTableClass, reserved uint32) (errcode error) { 579 r1, _, _ := syscall.Syscall6(procGetExtendedTCPTable.Addr(), 6, pTcpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved)) 580 if r1 != 0 { 581 errcode = syscall.Errno(r1) 582 } 583 return 584 } 585 586 func getExtendedUdpTable(pUdpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) { 587 r1, _, _ := syscall.Syscall6(procGetExtendedUDPTable.Addr(), 6, pUdpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved)) 588 if r1 != 0 { 589 errcode = syscall.Errno(r1) 590 } 591 return 592 } 593 594 func getUintptrFromBool(b bool) uintptr { 595 if b { 596 return 1 597 } 598 return 0 599 } 600 601 const anySize = 1 602 603 // type MIB_TCP_STATE int32 604 type mibTCPState int32 605 606 type tcpTableClass int32 607 608 const ( 609 tcpTableBasicListener tcpTableClass = iota 610 tcpTableBasicConnections 611 tcpTableBasicAll 612 tcpTableOwnerPidListener 613 tcpTableOwnerPidConnections 614 tcpTableOwnerPidAll 615 tcpTableOwnerModuleListener 616 tcpTableOwnerModuleConnections 617 tcpTableOwnerModuleAll 618 ) 619 620 type udpTableClass int32 621 622 const ( 623 udpTableBasic udpTableClass = iota 624 udpTableOwnerPid 625 udpTableOwnerModule 626 ) 627 628 // TCP 629 630 type mibTCPRowOwnerPid struct { 631 DwState uint32 632 DwLocalAddr uint32 633 DwLocalPort uint32 634 DwRemoteAddr uint32 635 DwRemotePort uint32 636 DwOwningPid uint32 637 } 638 639 func (m *mibTCPRowOwnerPid) convertToConnectionStat() ConnectionStat { 640 ns := ConnectionStat{ 641 Family: kindTCP4.family, 642 Type: kindTCP4.sockType, 643 Laddr: Addr{ 644 IP: parseIPv4HexString(m.DwLocalAddr), 645 Port: uint32(decodePort(m.DwLocalPort)), 646 }, 647 Raddr: Addr{ 648 IP: parseIPv4HexString(m.DwRemoteAddr), 649 Port: uint32(decodePort(m.DwRemotePort)), 650 }, 651 Pid: int32(m.DwOwningPid), 652 Status: tcpStatuses[mibTCPState(m.DwState)], 653 } 654 655 return ns 656 } 657 658 type mibTCPTableOwnerPid struct { 659 DwNumEntries uint32 660 Table [anySize]mibTCPRowOwnerPid 661 } 662 663 type mibTCP6RowOwnerPid struct { 664 UcLocalAddr [16]byte 665 DwLocalScopeId uint32 666 DwLocalPort uint32 667 UcRemoteAddr [16]byte 668 DwRemoteScopeId uint32 669 DwRemotePort uint32 670 DwState uint32 671 DwOwningPid uint32 672 } 673 674 func (m *mibTCP6RowOwnerPid) convertToConnectionStat() ConnectionStat { 675 ns := ConnectionStat{ 676 Family: kindTCP6.family, 677 Type: kindTCP6.sockType, 678 Laddr: Addr{ 679 IP: parseIPv6HexString(m.UcLocalAddr), 680 Port: uint32(decodePort(m.DwLocalPort)), 681 }, 682 Raddr: Addr{ 683 IP: parseIPv6HexString(m.UcRemoteAddr), 684 Port: uint32(decodePort(m.DwRemotePort)), 685 }, 686 Pid: int32(m.DwOwningPid), 687 Status: tcpStatuses[mibTCPState(m.DwState)], 688 } 689 690 return ns 691 } 692 693 type mibTCP6TableOwnerPid struct { 694 DwNumEntries uint32 695 Table [anySize]mibTCP6RowOwnerPid 696 } 697 698 type pmibTCPTableOwnerPidAll *mibTCPTableOwnerPid 699 type pmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid 700 701 // UDP 702 703 type mibUDPRowOwnerPid struct { 704 DwLocalAddr uint32 705 DwLocalPort uint32 706 DwOwningPid uint32 707 } 708 709 func (m *mibUDPRowOwnerPid) convertToConnectionStat() ConnectionStat { 710 ns := ConnectionStat{ 711 Family: kindUDP4.family, 712 Type: kindUDP4.sockType, 713 Laddr: Addr{ 714 IP: parseIPv4HexString(m.DwLocalAddr), 715 Port: uint32(decodePort(m.DwLocalPort)), 716 }, 717 Pid: int32(m.DwOwningPid), 718 } 719 720 return ns 721 } 722 723 type mibUDPTableOwnerPid struct { 724 DwNumEntries uint32 725 Table [anySize]mibUDPRowOwnerPid 726 } 727 728 type mibUDP6RowOwnerPid struct { 729 UcLocalAddr [16]byte 730 DwLocalScopeId uint32 731 DwLocalPort uint32 732 DwOwningPid uint32 733 } 734 735 func (m *mibUDP6RowOwnerPid) convertToConnectionStat() ConnectionStat { 736 ns := ConnectionStat{ 737 Family: kindUDP6.family, 738 Type: kindUDP6.sockType, 739 Laddr: Addr{ 740 IP: parseIPv6HexString(m.UcLocalAddr), 741 Port: uint32(decodePort(m.DwLocalPort)), 742 }, 743 Pid: int32(m.DwOwningPid), 744 } 745 746 return ns 747 } 748 749 type mibUDP6TableOwnerPid struct { 750 DwNumEntries uint32 751 Table [anySize]mibUDP6RowOwnerPid 752 } 753 754 type pmibUDPTableOwnerPid *mibUDPTableOwnerPid 755 type pmibUDP6TableOwnerPid *mibUDP6TableOwnerPid 756 757 func decodePort(port uint32) uint16 { 758 return syscall.Ntohs(uint16(port)) 759 } 760 761 func parseIPv4HexString(addr uint32) string { 762 return fmt.Sprintf("%d.%d.%d.%d", addr&255, addr>>8&255, addr>>16&255, addr>>24&255) 763 } 764 765 func parseIPv6HexString(addr [16]byte) string { 766 var ret [16]byte 767 for i := 0; i < 16; i++ { 768 ret[i] = uint8(addr[i]) 769 } 770 771 // convert []byte to net.IP 772 ip := net.IP(ret[:]) 773 return ip.String() 774 }