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  }