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  }