...

Source file src/github.com/shirou/gopsutil/net/net_windows.go

Documentation: github.com/shirou/gopsutil/net

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

View as plain text