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