diff --git a/go.mod b/go.mod index 3e2bc9de..f3d0e255 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,9 @@ module github.com/jaypipes/ghw go 1.12 require ( + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d github.com/ghodss/yaml v1.0.0 + github.com/go-ole/go-ole v1.2.4 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jaypipes/pcidb v0.5.0 github.com/pkg/errors v0.8.0 diff --git a/go.sum b/go.sum index c37c2768..8833173f 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jaypipes/pcidb v0.5.0 h1:4W5gZ+G7QxydevI8/MmmKdnIPJpURqJ2JNXTzfLxF5c= diff --git a/net.go b/net.go index 3c66be7e..fbdd5e4a 100644 --- a/net.go +++ b/net.go @@ -10,6 +10,13 @@ import ( "fmt" ) +type NICConfiguration struct { + DHCPenabled bool `json:"dhcp_enabled"` + Gateway string `json:"gateway"` + IPv4 string `json:"ipv4"` + IPv6 string `json:"ipv6"` +} + type NICCapability struct { Name string `json:"name"` IsEnabled bool `json:"is_enabled"` @@ -17,10 +24,11 @@ type NICCapability struct { } type NIC struct { - Name string `json:"name"` - MacAddress string `json:"mac_address"` - IsVirtual bool `json:"is_virtual"` - Capabilities []*NICCapability `json:"capabilities"` + Name string `json:"name"` + MacAddress string `json:"mac_address"` + IsVirtual bool `json:"is_virtual"` + Capabilities []*NICCapability `json:"capabilities"` + Configurations []*NICConfiguration `json:"configurations"` // TODO(jaypipes): Add PCI field for accessing PCI device information // PCI *PCIDevice `json:"pci"` } diff --git a/net_stub.go b/net_stub.go index f5e5f2f9..a2f75c0f 100644 --- a/net_stub.go +++ b/net_stub.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!windows // Use and distribution licensed under the Apache license version 2. // // See the COPYING file in the root project directory for full text. diff --git a/net_windows.go b/net_windows.go new file mode 100644 index 00000000..170ba07c --- /dev/null +++ b/net_windows.go @@ -0,0 +1,143 @@ +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package ghw + +import ( + "strings" + + "github.com/StackExchange/wmi" +) + +const wqlNetworkAdapter = "SELECT Description, DeviceID, Index, InterfaceIndex, MACAddress, Manufacturer, Name, NetConnectionID, ProductName, ServiceName FROM Win32_NetworkAdapter" + +type win32NetworkAdapter struct { + Description string + DeviceID string + Index uint32 + InterfaceIndex uint32 + MACAddress string + Manufacturer string + Name string + NetConnectionID string + ProductName string + ServiceName string +} + +const wqlNetworkAdapterCnofiguration = "SELECT Caption, Description, DefaultIPGateway, DHCPEnabled, Index, InterfaceIndex, IPAddress FROM Win32_NetworkAdapterConfiguration" + +type win32NetworkAdapterConfiguration struct { + Caption string + Description string + DefaultIPGateway []string + DHCPEnabled bool + Index uint32 + InterfaceIndex uint32 + IPAddress []string +} + +const wqlIP4RouteTable = "SELECT Caption, Description, Destination, Information, InterfaceIndex, Mask, Metric1, Metric2, Metric3, Metric4, Metric5, Name, NextHop, Protocol, Status, Type FROM Win32_IP4RouteTable" + +type win32IP4RouteTable struct { + Caption string + Description string + Destination string + Information string + InterfaceIndex int32 + Mask string + Metric1 int32 + Metric2 int32 + Metric3 int32 + Metric4 int32 + Metric5 int32 + Name string + NextHop string + Protocol uint32 + Status string + Type uint32 +} + +func (ctx *context) netFillInfo(info *NetworkInfo) error { + // Getting info from WMI + var win32NetDescriptions []win32NetworkAdapter + if err := wmi.Query(wqlNetworkAdapter, &win32NetDescriptions); err != nil { + return err + } + + var win32NetConfigurationDescriptions []win32NetworkAdapterConfiguration + if err := wmi.Query(wqlNetworkAdapterCnofiguration, &win32NetConfigurationDescriptions); err != nil { + return err + } + + var win32IP4RouteTableDescriptions []win32IP4RouteTable + if err := wmi.Query(wqlIP4RouteTable, &win32IP4RouteTableDescriptions); err != nil { + return err + } + + info.NICs = ctx.nics(win32NetDescriptions, win32NetConfigurationDescriptions, win32IP4RouteTableDescriptions) + return nil +} + +func (ctx *context) nics(win32NetDescriptions []win32NetworkAdapter, win32NetConfigurationDescriptions []win32NetworkAdapterConfiguration, win32IP4RouteTableDescriptions []win32IP4RouteTable) []*NIC { + // Converting into standard structures + nics := make([]*NIC, 0) + for _, nicDescription := range win32NetDescriptions { + nic := &NIC{ + Name: ctx.netDeviceName(nicDescription), + MacAddress: nicDescription.MACAddress, + IsVirtual: false, + Capabilities: []*NICCapability{}, + } + // Building NIC configurations + for _, configDescription := range win32NetConfigurationDescriptions { + // Looking for configurations + if nicDescription.InterfaceIndex == configDescription.InterfaceIndex { + ipv4, ipv6 := ctx.netConfigIP(configDescription.IPAddress) + var configuration = &NICConfiguration{ + DHCPenabled: configDescription.DHCPEnabled, + IPv4: ipv4, + IPv6: ipv6, + } + // Looking for gateway + for _, routeDescription := range win32IP4RouteTableDescriptions { + if nicDescription.InterfaceIndex == uint32(routeDescription.InterfaceIndex) { + if routeDescription.Destination == "0.0.0.0" && routeDescription.Mask == "0.0.0.0" { + configuration.Gateway = routeDescription.NextHop + break + } + } + } + // Appending configuration to NIC configurations + nic.Configurations = append(nic.Configurations, configuration) + } + } + // Appenging NIC to NICs + nics = append(nics, nic) + } + + return nics +} + +func (ctx *context) netDeviceName(description win32NetworkAdapter) string { + var name string + if strings.TrimSpace(description.NetConnectionID) != "" { + name = description.NetConnectionID + " - " + description.Description + } else { + name = description.Description + } + return name +} + +func (ctx *context) netConfigIP(IPs []string) (string, string) { + var IPv4 string + var IPv6 string + if len(IPs) > 0 { + IPv4 = IPs[0] + } + if len(IPs) > 1 { + IPv6 = IPs[1] + } + return IPv4, IPv6 +}