From 2bb661dc7c70420c3e5c97c5fff70f954a4bb5e6 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 22 May 2019 20:18:38 +0200 Subject: winipcfg: import We'll maintain this as part of the same repo here. Later maybe we'll push it into x/sys/windows. Signed-off-by: Simon Rozman Signed-off-by: Aleksandar Pesic --- tunnel/winipcfg/interface_change_handler.go | 73 ++ tunnel/winipcfg/luid.go | 355 +++++++ tunnel/winipcfg/mksyscall.go | 8 + tunnel/winipcfg/netsh.go | 48 + tunnel/winipcfg/route_change_handler.go | 80 ++ tunnel/winipcfg/types.go | 952 +++++++++++++++++++ tunnel/winipcfg/types_386.go | 230 +++++ tunnel/winipcfg/types_amd64.go | 218 +++++ tunnel/winipcfg/types_test.go | 1057 +++++++++++++++++++++ tunnel/winipcfg/types_test_386.go | 57 ++ tunnel/winipcfg/types_test_amd64.go | 57 ++ tunnel/winipcfg/unicast_address_change_handler.go | 73 ++ tunnel/winipcfg/utils.go | 26 + tunnel/winipcfg/winipcfg.go | 169 ++++ tunnel/winipcfg/winipcfg_test.go | 705 ++++++++++++++ tunnel/winipcfg/zwinipcfg_windows.go | 318 +++++++ 16 files changed, 4426 insertions(+) create mode 100644 tunnel/winipcfg/interface_change_handler.go create mode 100644 tunnel/winipcfg/luid.go create mode 100644 tunnel/winipcfg/mksyscall.go create mode 100644 tunnel/winipcfg/netsh.go create mode 100644 tunnel/winipcfg/route_change_handler.go create mode 100644 tunnel/winipcfg/types.go create mode 100644 tunnel/winipcfg/types_386.go create mode 100644 tunnel/winipcfg/types_amd64.go create mode 100644 tunnel/winipcfg/types_test.go create mode 100644 tunnel/winipcfg/types_test_386.go create mode 100644 tunnel/winipcfg/types_test_amd64.go create mode 100644 tunnel/winipcfg/unicast_address_change_handler.go create mode 100644 tunnel/winipcfg/utils.go create mode 100644 tunnel/winipcfg/winipcfg.go create mode 100644 tunnel/winipcfg/winipcfg_test.go create mode 100644 tunnel/winipcfg/zwinipcfg_windows.go (limited to 'tunnel/winipcfg') diff --git a/tunnel/winipcfg/interface_change_handler.go b/tunnel/winipcfg/interface_change_handler.go new file mode 100644 index 00000000..6bb8cf2b --- /dev/null +++ b/tunnel/winipcfg/interface_change_handler.go @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "sync" + + "golang.org/x/sys/windows" +) + +// InterfaceChangeCallback structure allows interface change callback handling. +type InterfaceChangeCallback struct { + cb func(notificationType MibNotificationType, iface *MibIPInterfaceRow) +} + +var ( + interfaceChangeMutex = sync.Mutex{} + interfaceChangeCallbacks = make(map[*InterfaceChangeCallback]bool) + interfaceChangeHandle = windows.Handle(0) +) + +// RegisterInterfaceChangeCallback registers a new InterfaceChangeCallback. If this particular callback is already +// registered, the function will silently return. Returned InterfaceChangeCallback.Unregister method should be used +// to unregister. +func RegisterInterfaceChangeCallback(callback func(notificationType MibNotificationType, iface *MibIPInterfaceRow)) (*InterfaceChangeCallback, error) { + cb := &InterfaceChangeCallback{callback} + + interfaceChangeMutex.Lock() + defer interfaceChangeMutex.Unlock() + + interfaceChangeCallbacks[cb] = true + + if interfaceChangeHandle == 0 { + err := notifyIPInterfaceChange(windows.AF_UNSPEC, windows.NewCallback(interfaceChanged), 0, false, &interfaceChangeHandle) + if err != nil { + delete(interfaceChangeCallbacks, cb) + interfaceChangeHandle = 0 + return nil, err + } + } + + return cb, nil +} + +// Unregister unregisters the callback. +func (callback *InterfaceChangeCallback) Unregister() error { + interfaceChangeMutex.Lock() + defer interfaceChangeMutex.Unlock() + + delete(interfaceChangeCallbacks, callback) + + if len(interfaceChangeCallbacks) < 1 && interfaceChangeHandle != 0 { + err := cancelMibChangeNotify2(interfaceChangeHandle) + if err != nil { + return err + } + interfaceChangeHandle = 0 + } + + return nil +} + +func interfaceChanged(callerContext uintptr, row *MibIPInterfaceRow, notificationType MibNotificationType) uintptr { + interfaceChangeMutex.Lock() + for cb := range interfaceChangeCallbacks { + cb.cb(notificationType, row) + } + interfaceChangeMutex.Unlock() + return 0 +} diff --git a/tunnel/winipcfg/luid.go b/tunnel/winipcfg/luid.go new file mode 100644 index 00000000..246c7585 --- /dev/null +++ b/tunnel/winipcfg/luid.go @@ -0,0 +1,355 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "fmt" + "net" + + "golang.org/x/sys/windows" +) + +// LUID represents a network interface. +type LUID uint64 + +// IPInterface method retrieves IP information for the specified interface on the local computer. +func (luid LUID) IPInterface(family AddressFamily) (*MibIPInterfaceRow, error) { + row := &MibIPInterfaceRow{} + row.Init() + row.InterfaceLUID = luid + row.Family = family + err := row.get() + if err != nil { + return nil, err + } + return row, nil +} + +// Interface method retrieves information for the specified adapter on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getifentry2 +func (luid LUID) Interface() (*MibIfRow2, error) { + row := &MibIfRow2{} + row.InterfaceLUID = luid + err := row.get() + if err != nil { + return nil, err + } + return row, nil +} + +// GUID method converts a locally unique identifier (LUID) for a network interface to a globally unique identifier (GUID) for the interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-convertinterfaceluidtoguid +func (luid LUID) GUID() (*windows.GUID, error) { + guid := &windows.GUID{} + err := convertInterfaceLUIDToGUID(&luid, guid) + if err != nil { + return nil, err + } + return guid, nil +} + +// LUIDFromGUID function converts a globally unique identifier (GUID) for a network interface to the locally unique identifier (LUID) for the interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-convertinterfaceguidtoluid +func LUIDFromGUID(guid *windows.GUID) (LUID, error) { + var luid LUID + err := convertInterfaceGUIDToLUID(guid, &luid) + if err != nil { + return 0, err + } + return luid, nil +} + +// IPAddress method returns MibUnicastIPAddressRow struct that matches to provided 'ip' argument. Corresponds to GetUnicastIpAddressEntry +// (https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getunicastipaddressentry) +func (luid LUID) IPAddress(ip net.IP) (*MibUnicastIPAddressRow, error) { + row := &MibUnicastIPAddressRow{InterfaceLUID: luid} + + err := row.Address.SetIP(ip, 0) + if err != nil { + return nil, err + } + + err = row.get() + if err != nil { + return nil, err + } + + return row, nil +} + +// AddIPAddress method adds new unicast IP address to the interface. Corresponds to CreateUnicastIpAddressEntry function +// (https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createunicastipaddressentry). +func (luid LUID) AddIPAddress(address net.IPNet) error { + row := &MibUnicastIPAddressRow{} + initializeUnicastIPAddressEntry(row) + row.InterfaceLUID = luid + err := row.Address.SetIP(address.IP, 0) + if err != nil { + return err + } + ones, _ := address.Mask.Size() + row.OnLinkPrefixLength = uint8(ones) + return row.Create() +} + +// AddIPAddresses method adds multiple new unicast IP addresses to the interface. Corresponds to CreateUnicastIpAddressEntry function +// (https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createunicastipaddressentry). +func (luid LUID) AddIPAddresses(addresses []net.IPNet) error { + for i := range addresses { + err := luid.AddIPAddress(addresses[i]) + if err != nil { + return err + } + } + return nil +} + +// SetIPAddresses method sets new unicast IP addresses to the interface. +func (luid LUID) SetIPAddresses(addresses []net.IPNet) error { + err := luid.FlushIPAddresses(windows.AF_UNSPEC) + if err != nil { + return err + } + return luid.AddIPAddresses(addresses) +} + +// DeleteIPAddress method deletes interface's unicast IP address. Corresponds to DeleteUnicastIpAddressEntry function +// (https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-deleteunicastipaddressentry). +func (luid LUID) DeleteIPAddress(ip net.IP) error { + row, err := luid.IPAddress(ip) + if err != nil { + return err + } + return row.Delete() +} + +// FlushIPAddresses method deletes all interface's unicast IP addresses. +func (luid LUID) FlushIPAddresses(family AddressFamily) error { + var tab *mibUnicastIPAddressTable + err := getUnicastIPAddressTable(family, &tab) + if err != nil { + return err + } + t := tab.get() + for i := range t { + if t[i].InterfaceLUID == luid { + t[i].Delete() + } + } + tab.free() + return nil +} + +// Route method returns route determined with the input arguments. Corresponds to GetIpForwardEntry2 function +// (https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipforwardentry2). +// NOTE: If the corresponding route isn't found, the method will return error. +func (luid LUID) Route(destination net.IPNet, nextHop net.IP) (*MibIPforwardRow2, error) { + row := &MibIPforwardRow2{} + row.Init() + row.InterfaceLUID = luid + err := row.DestinationPrefix.SetIPNet(destination) + if err != nil { + return nil, err + } + err = row.NextHop.SetIP(nextHop, 0) + if err != nil { + return nil, err + } + + err = row.get() + if err != nil { + return nil, err + } + return row, nil +} + +// AddRoute method adds a route to the interface. Corresponds to CreateIpForwardEntry2 function, with added splitDefault feature. +// (https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createipforwardentry2) +func (luid LUID) AddRoute(destination net.IPNet, nextHop net.IP, metric uint32) error { + row := &MibIPforwardRow2{} + row.Init() + row.InterfaceLUID = luid + err := row.DestinationPrefix.SetIPNet(destination) + if err != nil { + return err + } + err = row.NextHop.SetIP(nextHop, 0) + if err != nil { + return err + } + row.Metric = metric + return row.Create() +} + +// AddRoutes method adds multiple routes to the interface. +func (luid LUID) AddRoutes(routesData []*RouteData) error { + for _, rd := range routesData { + err := luid.AddRoute(rd.Destination, rd.NextHop, rd.Metric) + if err != nil { + return err + } + } + return nil +} + +// SetRoutes method sets (flush than add) multiple routes to the interface. +func (luid LUID) SetRoutes(routesData []*RouteData) error { + err := luid.FlushRoutes(windows.AF_UNSPEC) + if err != nil { + return err + } + return luid.AddRoutes(routesData) +} + +// DeleteRoute method deletes a route that matches the criteria. Corresponds to DeleteIpForwardEntry2 function +// (https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-deleteipforwardentry2). +func (luid LUID) DeleteRoute(destination net.IPNet, nextHop net.IP) error { + row := &MibIPforwardRow2{} + row.Init() + row.InterfaceLUID = luid + err := row.DestinationPrefix.SetIPNet(destination) + if err != nil { + return err + } + err = row.NextHop.SetIP(nextHop, 0) + if err != nil { + return err + } + err = row.get() + if err != nil { + return err + } + return row.Delete() +} + +// FlushRoutes method deletes all interface's routes. +// It continues on failures, and returns the last error afterwards. +func (luid LUID) FlushRoutes(family AddressFamily) error { + var tab *mibIPforwardTable2 + err := getIPForwardTable2(family, &tab) + if err != nil { + return err + } + t := tab.get() + for i := range t { + if t[i].InterfaceLUID == luid { + err2 := t[i].Delete() + if err2 != nil { + err = err2 + } + } + } + tab.free() + return err +} + +// DNS method returns all DNS server addresses associated with the adapter. +func (luid LUID) DNS() ([]net.IP, error) { + addresses, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault) + if err != nil { + return nil, err + } + r := make([]net.IP, 0, len(addresses)) + for _, addr := range addresses { + if addr.LUID == luid { + for dns := addr.FirstDNSServerAddress; dns != nil; dns = dns.Next { + if ip := SocketAddressToIP(&dns.Address); len(ip) != 0 { + r = append(r, ip) + } else { + return nil, windows.ERROR_INVALID_PARAMETER + } + } + } + } + return r, nil +} + +const ( + netshCmdTemplateFlush4 = "interface ipv4 set dnsservers name=%d source=static address=none validate=no register=both" + netshCmdTemplateFlush6 = "interface ipv6 set dnsservers name=%d source=static address=none validate=no register=both" + netshCmdTemplateAdd4 = "interface ipv4 add dnsservers name=%d address=%s validate=no" + netshCmdTemplateAdd6 = "interface ipv6 add dnsservers name=%d address=%s validate=no" +) + +// FlushDNS method clears all DNS servers associated with the adapter. +func (luid LUID) FlushDNS() error { + cmds := make([]string, 0, 2) + ipif4, err := luid.IPInterface(windows.AF_INET) + if err == nil { + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateFlush4, ipif4.InterfaceIndex)) + } + ipif6, err := luid.IPInterface(windows.AF_INET6) + if err == nil { + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateFlush6, ipif6.InterfaceIndex)) + } + + if len(cmds) == 0 { + return nil + } + return runNetsh(cmds) +} + +// AddDNS method associates additional DNS servers with the adapter. +func (luid LUID) AddDNS(dnses []net.IP) error { + var ipif4, ipif6 *MibIPInterfaceRow + var err error + cmds := make([]string, 0, len(dnses)) + for i := 0; i < len(dnses); i++ { + if v4 := dnses[i].To4(); v4 != nil { + if ipif4 == nil { + ipif4, err = luid.IPInterface(windows.AF_INET) + if err != nil { + return err + } + } + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd4, ipif4.InterfaceIndex, v4.String())) + } else if v6 := dnses[i].To16(); v6 != nil { + if ipif6 == nil { + ipif6, err = luid.IPInterface(windows.AF_INET6) + if err != nil { + return err + } + } + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd6, ipif6.InterfaceIndex, v6.String())) + } + } + + if len(cmds) == 0 { + return nil + } + return runNetsh(cmds) +} + +// SetDNS method clears previous and associates new DNS servers with the adapter. +func (luid LUID) SetDNS(dnses []net.IP) error { + cmds := make([]string, 0, 2+len(dnses)) + ipif4, err := luid.IPInterface(windows.AF_INET) + if err == nil { + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateFlush4, ipif4.InterfaceIndex)) + } + ipif6, err := luid.IPInterface(windows.AF_INET6) + if err == nil { + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateFlush6, ipif6.InterfaceIndex)) + } + for i := 0; i < len(dnses); i++ { + if v4 := dnses[i].To4(); v4 != nil { + if ipif4 == nil { + return windows.ERROR_NOT_SUPPORTED + } + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd4, ipif4.InterfaceIndex, v4.String())) + } else if v6 := dnses[i].To16(); v6 != nil { + if ipif6 == nil { + return windows.ERROR_NOT_SUPPORTED + } + cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd6, ipif6.InterfaceIndex, v6.String())) + } + } + + if len(cmds) == 0 { + return nil + } + return runNetsh(cmds) +} diff --git a/tunnel/winipcfg/mksyscall.go b/tunnel/winipcfg/mksyscall.go new file mode 100644 index 00000000..c0afbc41 --- /dev/null +++ b/tunnel/winipcfg/mksyscall.go @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zwinipcfg_windows.go winipcfg.go diff --git a/tunnel/winipcfg/netsh.go b/tunnel/winipcfg/netsh.go new file mode 100644 index 00000000..4cff5de8 --- /dev/null +++ b/tunnel/winipcfg/netsh.go @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "bytes" + "fmt" + "io" + "os/exec" + "strings" + + "golang.org/x/sys/windows" +) + +// I wish we didn't have to do this. netiohlp.dll (what's used by netsh.exe) has some nice tricks with writing directly +// to the registry and the nsi kernel object, but it's not clear copying those makes for a stable interface. WMI doesn't +// work with v6. CMI isn't in Windows 7. +func runNetsh(cmds []string) error { + system32, err := windows.GetSystemDirectory() + if err != nil { + return err + } + cmd := exec.Command(system32 + "\\netsh.exe") // I wish we could append (, "-f", "CONIN$") but Go sets up the process context wrong. + stdin, err := cmd.StdinPipe() + if err != nil { + return fmt.Errorf("runNetsh stdin pipe - %v", err) + } + go func() { + defer stdin.Close() + io.WriteString(stdin, strings.Join(append(cmds, "exit\r\n"), "\r\n")) + }() + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("runNetsh run - %v", err) + } + // Horrible kludges, sorry. + cleaned := bytes.ReplaceAll(output, []byte("netsh>"), []byte{}) + cleaned = bytes.ReplaceAll(cleaned, []byte("There are no Domain Name Servers (DNS) configured on this computer."), []byte{}) + cleaned = bytes.TrimSpace(cleaned) + if len(cleaned) != 0 { + return fmt.Errorf("runNetsh returned error strings.\ninput:\n%s\noutput\n:%s", + strings.Join(cmds, "\n"), bytes.ReplaceAll(output, []byte{'\r', '\n'}, []byte{'\n'})) + } + return nil +} diff --git a/tunnel/winipcfg/route_change_handler.go b/tunnel/winipcfg/route_change_handler.go new file mode 100644 index 00000000..e43fa3c0 --- /dev/null +++ b/tunnel/winipcfg/route_change_handler.go @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "sync" + + "golang.org/x/sys/windows" +) + +// RouteChangeCallback structure allows route change callback handling. +type RouteChangeCallback struct { + cb func(notificationType MibNotificationType, route *MibIPforwardRow2) +} + +var ( + routeChangeAddRemoveMutex = sync.Mutex{} + routeChangeMutex = sync.Mutex{} + routeChangeCallbacks = make(map[*RouteChangeCallback]bool) + routeChangeHandle = windows.Handle(0) +) + +// RegisterRouteChangeCallback registers a new RouteChangeCallback. If this particular callback is already +// registered, the function will silently return. Returned RouteChangeCallback.Unregister method should be used +// to unregister. +func RegisterRouteChangeCallback(callback func(notificationType MibNotificationType, route *MibIPforwardRow2)) (*RouteChangeCallback, error) { + s := &RouteChangeCallback{callback} + + routeChangeAddRemoveMutex.Lock() + defer routeChangeAddRemoveMutex.Unlock() + + routeChangeMutex.Lock() + defer routeChangeMutex.Unlock() + + routeChangeCallbacks[s] = true + + if routeChangeHandle == 0 { + err := notifyRouteChange2(windows.AF_UNSPEC, windows.NewCallback(routeChanged), 0, false, &routeChangeHandle) + if err != nil { + delete(routeChangeCallbacks, s) + routeChangeHandle = 0 + return nil, err + } + } + + return s, nil +} + +// Unregister unregisters the callback. +func (callback *RouteChangeCallback) Unregister() error { + routeChangeAddRemoveMutex.Lock() + defer routeChangeAddRemoveMutex.Unlock() + + routeChangeMutex.Lock() + delete(routeChangeCallbacks, callback) + removeIt := len(routeChangeCallbacks) == 0 && routeChangeHandle != 0 + routeChangeMutex.Unlock() + + if removeIt { + err := cancelMibChangeNotify2(routeChangeHandle) + if err != nil { + return err + } + routeChangeHandle = 0 + } + + return nil +} + +func routeChanged(callerContext uintptr, row *MibIPforwardRow2, notificationType MibNotificationType) uintptr { + routeChangeMutex.Lock() + for cb := range routeChangeCallbacks { + cb.cb(notificationType, row) + } + routeChangeMutex.Unlock() + return 0 +} diff --git a/tunnel/winipcfg/types.go b/tunnel/winipcfg/types.go new file mode 100644 index 00000000..684a6c77 --- /dev/null +++ b/tunnel/winipcfg/types.go @@ -0,0 +1,952 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "bytes" + "net" + "unsafe" + + "golang.org/x/sys/windows" +) + +const ( + anySize = 1 + maxDNSSuffixStringLength = 256 + maxDHCPv6DUIDLength = 130 + ifMaxStringSize = 256 + ifMaxPhysAddressLength = 32 +) + +// AddressFamily enumeration specifies protocol family and is one of the windows.AF_* constants. +type AddressFamily uint16 + +// IPAAFlags enumeration describes adapter addresses flags +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_addresses_lh +type IPAAFlags uint32 + +const ( + IPAAFlagDdnsEnabled IPAAFlags = 1 << iota + IPAAFlagRegisterAdapterSuffix + IPAAFlagDhcpv4Enabled + IPAAFlagReceiveOnly + IPAAFlagNoMulticast + IPAAFlagIpv6OtherStatefulConfig + IPAAFlagNetbiosOverTcpipEnabled + IPAAFlagIpv4Enabled + IPAAFlagIpv6Enabled + IPAAFlagIpv6ManagedAddressConfigurationSupported +) + +// IfOperStatus enumeration specifies the operational status of an interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ne-ifdef-if_oper_status +type IfOperStatus uint32 + +const ( + IfOperStatusUp IfOperStatus = iota + 1 + IfOperStatusDown + IfOperStatusTesting + IfOperStatusUnknown + IfOperStatusDormant + IfOperStatusNotPresent + IfOperStatusLowerLayerDown +) + +// IfType enumeration specifies interface type. +type IfType uint32 + +const ( + IfTypeOther IfType = 1 // None of the below + IfTypeRegular1822 = 2 + IfTypeHdh1822 = 3 + IfTypeDdnX25 = 4 + IfTypeRfc877X25 = 5 + IfTypeEthernetCSMACD = 6 + IfTypeISO88023CSMACD = 7 + IfTypeISO88024Tokenbus = 8 + IfTypeISO88025Tokenring = 9 + IfTypeISO88026Man = 10 + IfTypeStarlan = 11 + IfTypeProteon10Mbit = 12 + IfTypeProteon80Mbit = 13 + IfTypeHyperchannel = 14 + IfTypeFddi = 15 + IfTypeLapB = 16 + IfTypeSdlc = 17 + IfTypeDs1 = 18 // DS1-MIB + IfTypeE1 = 19 // Obsolete; see DS1-MIB + IfTypeBasicISDN = 20 + IfTypePrimaryISDN = 21 + IfTypePropPoint2PointSerial = 22 // proprietary serial + IfTypePPP = 23 + IfTypeSoftwareLoopback = 24 + IfTypeEon = 25 // CLNP over IP + IfTypeEthernet3Mbit = 26 + IfTypeNsip = 27 // XNS over IP + IfTypeSlip = 28 // Generic Slip + IfTypeUltra = 29 // ULTRA Technologies + IfTypeDs3 = 30 // DS3-MIB + IfTypeSip = 31 // SMDS, coffee + IfTypeFramerelay = 32 // DTE only + IfTypeRs232 = 33 + IfTypePara = 34 // Parallel port + IfTypeArcnet = 35 + IfTypeArcnetPlus = 36 + IfTypeAtm = 37 // ATM cells + IfTypeMioX25 = 38 + IfTypeSonet = 39 // SONET or SDH + IfTypeX25Ple = 40 + IfTypeIso88022LLC = 41 + IfTypeLocaltalk = 42 + IfTypeSmdsDxi = 43 + IfTypeFramerelayService = 44 // FRNETSERV-MIB + IfTypeV35 = 45 + IfTypeHssi = 46 + IfTypeHippi = 47 + IfTypeModem = 48 // Generic Modem + IfTypeAal5 = 49 // AAL5 over ATM + IfTypeSonetPath = 50 + IfTypeSonetVt = 51 + IfTypeSmdsIcip = 52 // SMDS InterCarrier Interface + IfTypePropVirtual = 53 // Proprietary virtual/internal + IfTypePropMultiplexor = 54 // Proprietary multiplexing + IfTypeIEEE80212 = 55 // 100BaseVG + IfTypeFibrechannel = 56 + IfTypeHippiinterface = 57 + IfTypeFramerelayInterconnect = 58 // Obsolete, use 32 or 44 + IfTypeAflane8023 = 59 // ATM Emulated LAN for 802.3 + IfTypeAflane8025 = 60 // ATM Emulated LAN for 802.5 + IfTypeCctemul = 61 // ATM Emulated circuit + IfTypeFastether = 62 // Fast Ethernet (100BaseT) + IfTypeISDN = 63 // ISDN and X.25 + IfTypeV11 = 64 // CCITT V.11/X.21 + IfTypeV36 = 65 // CCITT V.36 + IfTypeG703_64k = 66 // CCITT G703 at 64Kbps + IfTypeG703_2mb = 67 // Obsolete; see DS1-MIB + IfTypeQllc = 68 // SNA QLLC + IfTypeFastetherFX = 69 // Fast Ethernet (100BaseFX) + IfTypeChannel = 70 + IfTypeIEEE80211 = 71 // Radio spread spectrum + IfTypeIBM370parchan = 72 // IBM System 360/370 OEMI Channel + IfTypeEscon = 73 // IBM Enterprise Systems Connection + IfTypeDlsw = 74 // Data Link Switching + IfTypeISDNS = 75 // ISDN S/T interface + IfTypeISDNU = 76 // ISDN U interface + IfTypeLapD = 77 // Link Access Protocol D + IfTypeIpswitch = 78 // IP Switching Objects + IfTypeRsrb = 79 // Remote Source Route Bridging + IfTypeAtmLogical = 80 // ATM Logical Port + IfTypeDs0 = 81 // Digital Signal Level 0 + IfTypeDs0Bundle = 82 // Group of ds0s on the same ds1 + IfTypeBsc = 83 // Bisynchronous Protocol + IfTypeAsync = 84 // Asynchronous Protocol + IfTypeCnr = 85 // Combat Net Radio + IfTypeIso88025rDtr = 86 // ISO 802.5r DTR + IfTypeEplrs = 87 // Ext Pos Loc Report Sys + IfTypeArap = 88 // Appletalk Remote Access Protocol + IfTypePropCnls = 89 // Proprietary Connectionless Proto + IfTypeHostpad = 90 // CCITT-ITU X.29 PAD Protocol + IfTypeTermpad = 91 // CCITT-ITU X.3 PAD Facility + IfTypeFramerelayMpi = 92 // Multiproto Interconnect over FR + IfTypeX213 = 93 // CCITT-ITU X213 + IfTypeAdsl = 94 // Asymmetric Digital Subscrbr Loop + IfTypeRadsl = 95 // Rate-Adapt Digital Subscrbr Loop + IfTypeSdsl = 96 // Symmetric Digital Subscriber Loop + IfTypeVdsl = 97 // Very H-Speed Digital Subscrb Loop + IfTypeIso88025Crfprint = 98 // ISO 802.5 CRFP + IfTypeMyrinet = 99 // Myricom Myrinet + IfTypeVoiceEm = 100 // Voice recEive and transMit + IfTypeVoiceFxo = 101 // Voice Foreign Exchange Office + IfTypeVoiceFxs = 102 // Voice Foreign Exchange Station + IfTypeVoiceEncap = 103 // Voice encapsulation + IfTypeVoiceOverip = 104 // Voice over IP encapsulation + IfTypeAtmDxi = 105 // ATM DXI + IfTypeAtmFuni = 106 // ATM FUNI + IfTypeAtmIma = 107 // ATM IMA + IfTypePPPmultilinkbundle = 108 // PPP Multilink Bundle + IfTypeIpoverCdlc = 109 // IBM ipOverCdlc + IfTypeIpoverClaw = 110 // IBM Common Link Access to Workstn + IfTypeStacktostack = 111 // IBM stackToStack + IfTypeVirtualipaddress = 112 // IBM VIPA + IfTypeMpc = 113 // IBM multi-proto channel support + IfTypeIpoverAtm = 114 // IBM ipOverAtm + IfTypeIso88025Fiber = 115 // ISO 802.5j Fiber Token Ring + IfTypeTdlc = 116 // IBM twinaxial data link control + IfTypeGigabitethernet = 117 + IfTypeHdlc = 118 + IfTypeLapF = 119 + IfTypeV37 = 120 + IfTypeX25Mlp = 121 // Multi-Link Protocol + IfTypeX25Huntgroup = 122 // X.25 Hunt Group + IfTypeTransphdlc = 123 + IfTypeInterleave = 124 // Interleave channel + IfTypeFast = 125 // Fast channel + IfTypeIP = 126 // IP (for APPN HPR in IP networks) + IfTypeDocscableMaclayer = 127 // CATV Mac Layer + IfTypeDocscableDownstream = 128 // CATV Downstream interface + IfTypeDocscableUpstream = 129 // CATV Upstream interface + IfTypeA12mppswitch = 130 // Avalon Parallel Processor + IfTypeTunnel = 131 // Encapsulation interface + IfTypeCoffee = 132 // Coffee pot + IfTypeCes = 133 // Circuit Emulation Service + IfTypeAtmSubinterface = 134 // ATM Sub Interface + IfTypeL2Vlan = 135 // Layer 2 Virtual LAN using 802.1Q + IfTypeL3Ipvlan = 136 // Layer 3 Virtual LAN using IP + IfTypeL3Ipxvlan = 137 // Layer 3 Virtual LAN using IPX + IfTypeDigitalpowerline = 138 // IP over Power Lines + IfTypeMediamailoverip = 139 // Multimedia Mail over IP + IfTypeDtm = 140 // Dynamic syncronous Transfer Mode + IfTypeDcn = 141 // Data Communications Network + IfTypeIpforward = 142 // IP Forwarding Interface + IfTypeMsdsl = 143 // Multi-rate Symmetric DSL + IfTypeIEEE1394 = 144 // IEEE1394 High Perf Serial Bus + IfTypeIfGsn = 145 + IfTypeDvbrccMaclayer = 146 + IfTypeDvbrccDownstream = 147 + IfTypeDvbrccUpstream = 148 + IfTypeAtmVirtual = 149 + IfTypeMplsTunnel = 150 + IfTypeSrp = 151 + IfTypeVoiceoveratm = 152 + IfTypeVoiceoverframerelay = 153 + IfTypeIdsl = 154 + IfTypeCompositelink = 155 + IfTypeSs7Siglink = 156 + IfTypePropWirelessP2P = 157 + IfTypeFrForward = 158 + IfTypeRfc1483 = 159 + IfTypeUsb = 160 + IfTypeIEEE8023adLag = 161 + IfTypeBgpPolicyAccounting = 162 + IfTypeFrf16MfrBundle = 163 + IfTypeH323Gatekeeper = 164 + IfTypeH323Proxy = 165 + IfTypeMpls = 166 + IfTypeMfSiglink = 167 + IfTypeHdsl2 = 168 + IfTypeShdsl = 169 + IfTypeDs1Fdl = 170 + IfTypePos = 171 + IfTypeDvbAsiIn = 172 + IfTypeDvbAsiOut = 173 + IfTypePlc = 174 + IfTypeNfas = 175 + IfTypeTr008 = 176 + IfTypeGr303Rdt = 177 + IfTypeGr303Idt = 178 + IfTypeIsup = 179 + IfTypePropDocsWirelessMaclayer = 180 + IfTypePropDocsWirelessDownstream = 181 + IfTypePropDocsWirelessUpstream = 182 + IfTypeHiperlan2 = 183 + IfTypePropBwaP2MP = 184 + IfTypeSonetOverheadChannel = 185 + IfTypeDigitalWrapperOverheadChannel = 186 + IfTypeAal2 = 187 + IfTypeRadioMac = 188 + IfTypeAtmRadio = 189 + IfTypeImt = 190 + IfTypeMvl = 191 + IfTypeReachDsl = 192 + IfTypeFrDlciEndpt = 193 + IfTypeAtmVciEndpt = 194 + IfTypeOpticalChannel = 195 + IfTypeOpticalTransport = 196 + IfTypeIEEE80216Wman = 237 + IfTypeWwanpp = 243 // WWAN devices based on GSM technology + IfTypeWwanpp2 = 244 // WWAN devices based on CDMA technology + IfTypeIEEE802154 = 259 // IEEE 802.15.4 WPAN interface + IfTypeXboxWireless = 281 +) + +// MibIfEntryLevel enumeration specifies level of interface information to retrieve in GetIfTable2Ex function call. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getifentry2ex +type MibIfEntryLevel uint32 + +const ( + MibIfEntryNormal MibIfEntryLevel = 0 + MibIfEntryNormalWithoutStatistics = 2 +) + +// NdisMedium enumeration type identifies the medium types that NDIS drivers support. +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddndis/ne-ntddndis-_ndis_medium +type NdisMedium uint32 + +const ( + NdisMedium802_3 NdisMedium = iota + NdisMedium802_5 + NdisMediumFddi + NdisMediumWan + NdisMediumLocalTalk + NdisMediumDix // defined for convenience, not a real medium + NdisMediumArcnetRaw + NdisMediumArcnet878_2 + NdisMediumAtm + NdisMediumWirelessWan + NdisMediumIrda + NdisMediumBpc + NdisMediumCoWan + NdisMedium1394 + NdisMediumInfiniBand + NdisMediumTunnel + NdisMediumNative802_11 + NdisMediumLoopback + NdisMediumWiMAX + NdisMediumIP + NdisMediumMax +) + +// NdisPhysicalMedium describes NDIS physical medium type. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_if_row2 +type NdisPhysicalMedium uint32 + +const ( + NdisPhysicalMediumUnspecified NdisPhysicalMedium = iota + NdisPhysicalMediumWirelessLan + NdisPhysicalMediumCableModem + NdisPhysicalMediumPhoneLine + NdisPhysicalMediumPowerLine + NdisPhysicalMediumDSL // includes ADSL and UADSL (G.Lite) + NdisPhysicalMediumFibreChannel + NdisPhysicalMedium1394 + NdisPhysicalMediumWirelessWan + NdisPhysicalMediumNative802_11 + NdisPhysicalMediumBluetooth + NdisPhysicalMediumInfiniband + NdisPhysicalMediumWiMax + NdisPhysicalMediumUWB + NdisPhysicalMedium802_3 + NdisPhysicalMedium802_5 + NdisPhysicalMediumIrda + NdisPhysicalMediumWiredWAN + NdisPhysicalMediumWiredCoWan + NdisPhysicalMediumOther + NdisPhysicalMediumNative802_15_4 + NdisPhysicalMediumMax +) + +// NetIfAccessType enumeration type specifies the NDIS network interface access type. +// https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ne-ifdef-_net_if_access_type +type NetIfAccessType uint32 + +const ( + NetIfAccessLoopback NetIfAccessType = iota + 1 + NetIfAccessBroadcast + NetIfAccessPointToPoint + NetIfAccessPointToMultiPoint + NetIfAccessMax +) + +// NetIfAdminStatus enumeration type specifies the NDIS network interface administrative status, as described in RFC 2863. +// https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ne-ifdef-net_if_admin_status +type NetIfAdminStatus uint32 + +const ( + NetIfAdminStatusUp NetIfAdminStatus = iota + 1 + NetIfAdminStatusDown + NetIfAdminStatusTesting +) + +// NetIfConnectionType enumeration type specifies the NDIS network interface connection type. +// https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ne-ifdef-_net_if_connection_type +type NetIfConnectionType uint32 + +const ( + NetIfConnectionDedicated NetIfConnectionType = iota + 1 + NetIfConnectionPassive + NetIfConnectionDemand + NetIfConnectionMaximum +) + +// NetIfDirectionType enumeration type specifies the NDIS network interface direction type. +// https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ne-ifdef-net_if_direction_type +type NetIfDirectionType uint32 + +const ( + NetIfDirectionSendReceive NetIfDirectionType = iota + NetIfDirectionSendOnly + NetIfDirectionReceiveOnly + NetIfDirectionMaximum +) + +// NetIfMediaConnectState enumeration type specifies the NDIS network interface connection state. +// https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ne-ifdef-_net_if_media_connect_state +type NetIfMediaConnectState uint32 + +const ( + MediaConnectStateUnknown NetIfMediaConnectState = iota + MediaConnectStateConnected + MediaConnectStateDisconnected +) + +// DadState enumeration specifies information about the duplicate address detection (DAD) state for an IPv4 or IPv6 address. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ne-nldef-nl_dad_state +type DadState uint32 + +const ( + DadStateInvalid DadState = iota + DadStateTentative + DadStateDuplicate + DadStateDeprecated + DadStatePreferred +) + +// PrefixOrigin enumeration specifies the origin of an IPv4 or IPv6 address prefix, and is used with the IP_ADAPTER_UNICAST_ADDRESS structure. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ne-nldef-nl_prefix_origin +type PrefixOrigin uint32 + +const ( + PrefixOriginOther PrefixOrigin = iota + PrefixOriginManual + PrefixOriginWellKnown + PrefixOriginDHCP + PrefixOriginRouterAdvertisement + PrefixOriginUnchanged = 1 << 4 +) + +// LinkLocalAddressBehavior enumeration type defines the link local address behavior. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ne-nldef-_nl_link_local_address_behavior +type LinkLocalAddressBehavior int32 + +const ( + LinkLocalAddressAlwaysOff LinkLocalAddressBehavior = iota // Never use link locals. + LinkLocalAddressDelayed // Use link locals only if no other addresses. (default for IPv4). Legacy mapping: IPAutoconfigurationEnabled. + LinkLocalAddressAlwaysOn // Always use link locals (default for IPv6). + LinkLocalAddressUnchanged = -1 +) + +// OffloadRod enumeration specifies a set of flags that indicate the offload capabilities for an IP interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ns-nldef-_nl_interface_offload_rod +type OffloadRod uint8 + +const ( + ChecksumSupported OffloadRod = 1 << iota + OptionsSupported + DatagramChecksumSupported + StreamChecksumSupported + StreamOptionsSupported + FastPathCompatible + LargeSendOffloadSupported + GiantSendOffloadSupported +) + +// RouteOrigin enumeration type defines the origin of the IP route. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ne-nldef-nl_route_origin +type RouteOrigin uint32 + +const ( + RouteOriginManual RouteOrigin = iota + RouteOriginWellKnown + RouteOriginDHCP + RouteOriginRouterAdvertisement + RouteOrigin6to4 +) + +// RouteProtocol enumeration type defines the routing mechanism that an IP route was added with, as described in RFC 4292. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ne-nldef-nl_route_protocol +type RouteProtocol uint32 + +const ( + RouteProtocolOther RouteProtocol = iota + 1 + RouteProtocolLocal + RouteProtocolNetMgmt + RouteProtocolIcmp + RouteProtocolEgp + RouteProtocolGgp + RouteProtocolHello + RouteProtocolRip + RouteProtocolIsIs + RouteProtocolEsIs + RouteProtocolCisco + RouteProtocolBbn + RouteProtocolOspf + RouteProtocolBgp + RouteProtocolIdpr + RouteProtocolEigrp + RouteProtocolDvmrp + RouteProtocolRpl + RouteProtocolDHCP + RouteProtocolNTAutostatic = 10002 + RouteProtocolNTStatic = 10006 + RouteProtocolNTStaticNonDOD = 10007 +) + +// RouterDiscoveryBehavior enumeration type defines the router discovery behavior, as described in RFC 2461. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ne-nldef-_nl_router_discovery_behavior +type RouterDiscoveryBehavior int32 + +const ( + RouterDiscoveryDisabled RouterDiscoveryBehavior = iota + RouterDiscoveryEnabled + RouterDiscoveryDHCP + RouterDiscoveryUnchanged = -1 +) + +// SuffixOrigin enumeration specifies the origin of an IPv4 or IPv6 address suffix, and is used with the IP_ADAPTER_UNICAST_ADDRESS structure. +// https://docs.microsoft.com/en-us/windows/desktop/api/nldef/ne-nldef-nl_suffix_origin +type SuffixOrigin uint32 + +const ( + SuffixOriginOther SuffixOrigin = iota + SuffixOriginManual + SuffixOriginWellKnown + SuffixOriginDHCP + SuffixOriginLinkLayerAddress + SuffixOriginRandom + SuffixOriginUnchanged = 1 << 4 +) + +// MibNotificationType enumeration defines the notification type passed to a callback function when a notification occurs. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ne-netioapi-_mib_notification_type +type MibNotificationType uint32 + +const ( + MibParameterNotification MibNotificationType = iota // Parameter change + MibAddInstance // Addition + MibDeleteInstance // Deletion + MibInitialNotification // Initial notification +) + +// TunnelType enumeration type defines the encapsulation method used by a tunnel, as described by the Internet Assigned Names Authority (IANA). +// https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ne-ifdef-tunnel_type +type TunnelType uint32 + +const ( + TunnelTypeNone TunnelType = 0 + TunnelTypeOther = 1 + TunnelTypeDirect = 2 + TunnelType6to4 = 11 + TunnelTypeIsatap = 13 + TunnelTypeTeredo = 14 + TunnelTypeIPHTTPS = 15 +) + +// InterfaceAndOperStatusFlags enumeration type defines interface and operation flags +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_if_row2 +type InterfaceAndOperStatusFlags uint8 + +const ( + IAOSFHardwareInterface InterfaceAndOperStatusFlags = 1 << iota + IAOSFFilterInterface + IAOSFConnectorPresent + IAOSFNotAuthenticated + IAOSFNotMediaConnected + IAOSFPaused + IAOSFLowPower + IAOSFEndPointInterface +) + +// GAAFlags enumeration defines flags used in GetAdaptersAddresses calls +// https://docs.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getadaptersaddresses +type GAAFlags uint32 + +const ( + GAAFlagSkipUnicast GAAFlags = 1 << iota + GAAFlagSkipAnycast + GAAFlagSkipMulticast + GAAFlagSkipDNSServer + GAAFlagIncludePrefix + GAAFlagSkipFriendlyName + GAAFlagIncludeWinsInfo + GAAFlagIncludeGateways + GAAFlagIncludeAllInterfaces + GAAFlagIncludeAllCompartments + GAAFlagIncludeTunnelBindingOrder + GAAFlagSkipDNSInfo + + GAAFlagDefault GAAFlags = 0 + GAAFlagSkipAll = GAAFlagSkipUnicast | GAAFlagSkipAnycast | GAAFlagSkipMulticast | GAAFlagSkipDNSServer | GAAFlagSkipFriendlyName | GAAFlagSkipDNSInfo + GAAFlagIncludeAll = GAAFlagIncludePrefix | GAAFlagIncludeWinsInfo | GAAFlagIncludeGateways | GAAFlagIncludeAllInterfaces | GAAFlagIncludeAllCompartments | GAAFlagIncludeTunnelBindingOrder +) + +// ScopeLevel enumeration is used with the IP_ADAPTER_ADDRESSES structure to identify scope levels for IPv6 addresses. +// https://docs.microsoft.com/en-us/windows/desktop/api/ws2def/ne-ws2def-scope_level +type ScopeLevel uint32 + +const ( + ScopeLevelInterface ScopeLevel = 1 + ScopeLevelLink = 2 + ScopeLevelSubnet = 3 + ScopeLevelAdmin = 4 + ScopeLevelSite = 5 + ScopeLevelOrganization = 8 + ScopeLevelGlobal = 14 + ScopeLevelCount = 16 +) + +// Theoretical array index limitations +const ( + maxIndexCount8 = (1 << 31) - 1 + maxIndexCount16 = (1 << 30) - 1 +) + +// RouteData structure describes a route to add +type RouteData struct { + Destination net.IPNet + NextHop net.IP + Metric uint32 +} + +// IPAdapterDNSSuffix structure stores a DNS suffix in a linked list of DNS suffixes for a particular adapter. +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_dns_suffix +type IPAdapterDNSSuffix struct { + Next *IPAdapterDNSSuffix + str [maxDNSSuffixStringLength]uint16 +} + +// String method returns the DNS suffix for this DNS suffix entry. +func (obj *IPAdapterDNSSuffix) String() string { + return windows.UTF16ToString(obj.str[:]) +} + +// AdapterName method returns the name of the adapter with which these addresses are associated. +// Unlike an adapter's friendly name, the adapter name returned by AdapterName is permanent and cannot be modified by the user. +func (addr *IPAdapterAddresses) AdapterName() string { + if addr.adapterName == nil { + return "" + } + slice := (*(*[maxIndexCount8]uint8)(unsafe.Pointer(addr.adapterName)))[:] + null := bytes.IndexByte(slice, 0) + if null != -1 { + slice = slice[:null] + } + return string(slice) +} + +// DNSSuffix method returns adapter DNS suffix associated with this adapter. +func (addr *IPAdapterAddresses) DNSSuffix() string { + if addr.dnsSuffix == nil { + return "" + } + return windows.UTF16ToString((*(*[maxIndexCount16]uint16)(unsafe.Pointer(addr.dnsSuffix)))[:]) +} + +// Description method returns description for the adapter. +func (addr *IPAdapterAddresses) Description() string { + if addr.description == nil { + return "" + } + return windows.UTF16ToString((*(*[maxIndexCount16]uint16)(unsafe.Pointer(addr.description)))[:]) +} + +// FriendlyName method returns a user-friendly name for the adapter. For example: "Local Area Connection 1." +// This name appears in contexts such as the ipconfig command line program and the Connection folder. +func (addr *IPAdapterAddresses) FriendlyName() string { + if addr.friendlyName == nil { + return "" + } + return windows.UTF16ToString((*(*[maxIndexCount16]uint16)(unsafe.Pointer(addr.friendlyName)))[:]) +} + +// PhysicalAddress method returns the Media Access Control (MAC) address for the adapter. +// For example, on an Ethernet network this member would specify the Ethernet hardware address. +func (addr *IPAdapterAddresses) PhysicalAddress() []byte { + return addr.physicalAddress[:addr.physicalAddressLength] +} + +// DHCPv6ClientDUID method returns the DHCP unique identifier (DUID) for the DHCPv6 client. +// This information is only applicable to an IPv6 adapter address configured using DHCPv6. +func (addr *IPAdapterAddresses) DHCPv6ClientDUID() []byte { + return addr.dhcpv6ClientDUID[:addr.dhcpv6ClientDUIDLength] +} + +// Init method initializes the members of an MIB_IPINTERFACE_ROW entry with default values. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-initializeipinterfaceentry +func (row *MibIPInterfaceRow) Init() { + initializeIPInterfaceEntry(row) +} + +// get method retrieves IP information for the specified interface on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipinterfaceentry +func (row *MibIPInterfaceRow) get() error { + if err := getIPInterfaceEntry(row); err != nil { + return err + } + + // Patch that fixes SitePrefixLength issue + // https://stackoverflow.com/questions/54857292/setipinterfaceentry-returns-error-invalid-parameter?noredirect=1 + switch row.Family { + case windows.AF_INET: + if row.SitePrefixLength > 32 { + row.SitePrefixLength = 0 + } + case windows.AF_INET6: + if row.SitePrefixLength > 128 { + row.SitePrefixLength = 128 + } + } + + return nil +} + +// Set method sets the properties of an IP interface on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-setipinterfaceentry +func (row *MibIPInterfaceRow) Set() error { + return setIPInterfaceEntry(row) +} + +// get method returns all table rows as a Go slice. +func (tab *mibIPInterfaceTable) get() []MibIPInterfaceRow { + const maxCount = maxIndexCount8 / unsafe.Sizeof(MibIPInterfaceRow{}) + return (*[maxCount]MibIPInterfaceRow)(unsafe.Pointer(&tab.table[0]))[:tab.numEntries] +} + +// free method frees the buffer allocated by the functions that return tables of network interfaces, addresses, and routes. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-freemibtable +func (tab *mibIPInterfaceTable) free() { + freeMibTable(unsafe.Pointer(tab)) +} + +// Alias method returns a string that contains the alias name of the network interface. +func (row *MibIfRow2) Alias() string { + return windows.UTF16ToString(row.alias[:]) +} + +// Description method returns a string that contains a description of the network interface. +func (row *MibIfRow2) Description() string { + return windows.UTF16ToString(row.description[:]) +} + +// PhysicalAddress method returns the physical hardware address of the adapter for this network interface. +func (row *MibIfRow2) PhysicalAddress() []byte { + return row.physicalAddress[:row.physicalAddressLength] +} + +// PermanentPhysicalAddress method returns the permanent physical hardware address of the adapter for this network interface. +func (row *MibIfRow2) PermanentPhysicalAddress() []byte { + return row.permanentPhysicalAddress[:row.physicalAddressLength] +} + +// get method retrieves information for the specified interface on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getifentry2 +func (row *MibIfRow2) get() (ret error) { + return getIfEntry2(row) +} + +// get method returns all table rows as a Go slice. +func (tab *mibIfTable2) get() []MibIfRow2 { + const maxCount = maxIndexCount8 / unsafe.Sizeof(MibIfRow2{}) + return (*[maxCount]MibIfRow2)(unsafe.Pointer(&tab.table[0]))[:tab.numEntries] +} + +// free method frees the buffer allocated by the functions that return tables of network interfaces, addresses, and routes. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-freemibtable +func (tab *mibIfTable2) free() { + freeMibTable(unsafe.Pointer(tab)) +} + +// RawSockaddrInet union contains an IPv4, an IPv6 address, or an address family. +// https://docs.microsoft.com/en-us/windows/desktop/api/ws2ipdef/ns-ws2ipdef-_sockaddr_inet +type RawSockaddrInet struct { + Family AddressFamily + data [26]byte +} + +// SetIP method sets family, address, and port to the given IPv4 or IPv6 address and port. +// All other members of the structure are set to zero. +func (addr *RawSockaddrInet) SetIP(ip net.IP, port uint16) error { + if v4 := ip.To4(); v4 != nil { + addr4 := (*windows.RawSockaddrInet4)(unsafe.Pointer(addr)) + addr4.Family = windows.AF_INET + copy(addr4.Addr[:], v4) + addr4.Port = port + for i := 0; i < 8; i++ { + addr4.Zero[i] = 0 + } + return nil + } + + if v6 := ip.To16(); v6 != nil { + addr6 := (*windows.RawSockaddrInet6)(unsafe.Pointer(addr)) + addr6.Family = windows.AF_INET6 + addr6.Port = port + addr6.Flowinfo = 0 + copy(addr6.Addr[:], v6) + addr6.Scope_id = 0 + return nil + } + + return windows.ERROR_INVALID_PARAMETER +} + +// IP method returns IPv4 or IPv6 address. +// If the address is neither IPv4 not IPv6 nil is returned. +func (addr *RawSockaddrInet) IP() net.IP { + switch addr.Family { + case windows.AF_INET: + return (*windows.RawSockaddrInet4)(unsafe.Pointer(addr)).Addr[:] + + case windows.AF_INET6: + return (*windows.RawSockaddrInet6)(unsafe.Pointer(addr)).Addr[:] + } + + return nil +} + +// Init method initializes a MibUnicastIPAddressRow structure with default values for a unicast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-initializeunicastipaddressentry +func (row *MibUnicastIPAddressRow) Init() { + initializeUnicastIPAddressEntry(row) +} + +// get method retrieves information for an existing unicast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getunicastipaddressentry +func (row *MibUnicastIPAddressRow) get() error { + return getUnicastIPAddressEntry(row) +} + +// Set method sets the properties of an existing unicast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-setunicastipaddressentry +func (row *MibUnicastIPAddressRow) Set() error { + return setUnicastIPAddressEntry(row) +} + +// Create method adds a new unicast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createunicastipaddressentry +func (row *MibUnicastIPAddressRow) Create() error { + return createUnicastIPAddressEntry(row) +} + +// Delete method deletes an existing unicast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-deleteunicastipaddressentry +func (row *MibUnicastIPAddressRow) Delete() error { + return deleteUnicastIPAddressEntry(row) +} + +// get method returns all table rows as a Go slice. +func (tab *mibUnicastIPAddressTable) get() []MibUnicastIPAddressRow { + const maxCount = maxIndexCount8 / unsafe.Sizeof(MibUnicastIPAddressRow{}) + return (*[maxCount]MibUnicastIPAddressRow)(unsafe.Pointer(&tab.table[0]))[:tab.numEntries] +} + +// free method frees the buffer allocated by the functions that return tables of network interfaces, addresses, and routes. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-freemibtable +func (tab *mibUnicastIPAddressTable) free() { + freeMibTable(unsafe.Pointer(tab)) +} + +// get method retrieves information for an existing anycast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getanycastipaddressentry +func (row *MibAnycastIPAddressRow) get() error { + return getAnycastIPAddressEntry(row) +} + +// Create method adds a new anycast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createanycastipaddressentry +func (row *MibAnycastIPAddressRow) Create() error { + return createAnycastIPAddressEntry(row) +} + +// Delete method deletes an existing anycast IP address entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-deleteanycastipaddressentry +func (row *MibAnycastIPAddressRow) Delete() error { + return deleteAnycastIPAddressEntry(row) +} + +// get method returns all table rows as a Go slice. +func (tab *mibAnycastIPAddressTable) get() []MibAnycastIPAddressRow { + const maxCount = maxIndexCount8 / unsafe.Sizeof(MibAnycastIPAddressRow{}) + return (*[maxCount]MibAnycastIPAddressRow)(unsafe.Pointer(&tab.table[0]))[:tab.numEntries] +} + +// free method frees the buffer allocated by the functions that return tables of network interfaces, addresses, and routes. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-freemibtable +func (tab *mibAnycastIPAddressTable) free() { + freeMibTable(unsafe.Pointer(tab)) +} + +// IPAddressPrefix structure stores an IP address prefix. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_ip_address_prefix +type IPAddressPrefix struct { + Prefix RawSockaddrInet + PrefixLength uint8 + _ [2]byte +} + +// SetIPNet method sets IP address prefix using net.IPNet. +func (prefix *IPAddressPrefix) SetIPNet(net net.IPNet) error { + err := prefix.Prefix.SetIP(net.IP, 0) + if err != nil { + return err + } + ones, _ := net.Mask.Size() + prefix.PrefixLength = uint8(ones) + return nil +} + +// IPNet method returns IP address prefix as net.IPNet. +// If the address is neither IPv4 not IPv6 an empty net.IPNet is returned. The resulting net.IPNet should be checked appropriately. +func (prefix *IPAddressPrefix) IPNet() net.IPNet { + switch prefix.Prefix.Family { + case windows.AF_INET: + return net.IPNet{IP: (*windows.RawSockaddrInet4)(unsafe.Pointer(&prefix.Prefix)).Addr[:], Mask: net.CIDRMask(int(prefix.PrefixLength), 8*net.IPv4len)} + case windows.AF_INET6: + return net.IPNet{IP: (*windows.RawSockaddrInet6)(unsafe.Pointer(&prefix.Prefix)).Addr[:], Mask: net.CIDRMask(int(prefix.PrefixLength), 8*net.IPv6len)} + } + return net.IPNet{} +} + +// MibIPforwardRow2 structure stores information about an IP route entry. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_ipforward_row2 +type MibIPforwardRow2 struct { + InterfaceLUID LUID + InterfaceIndex uint32 + DestinationPrefix IPAddressPrefix + NextHop RawSockaddrInet + SitePrefixLength uint8 + ValidLifetime uint32 + PreferredLifetime uint32 + Metric uint32 + Protocol RouteProtocol + Loopback bool + AutoconfigureAddress bool + Publish bool + Immortal bool + Age uint32 + Origin RouteOrigin +} + +// Init method initializes a MIB_IPFORWARD_ROW2 structure with default values for an IP route entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-initializeipforwardentry +func (row *MibIPforwardRow2) Init() { + initializeIPForwardEntry(row) +} + +// get method retrieves information for an IP route entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipforwardentry2 +func (row *MibIPforwardRow2) get() error { + return getIPForwardEntry2(row) +} + +// Set method sets the properties of an IP route entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-setipforwardentry2 +func (row *MibIPforwardRow2) Set() error { + return setIPForwardEntry2(row) +} + +// Create method creates a new IP route entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createipforwardentry2 +func (row *MibIPforwardRow2) Create() error { + return createIPForwardEntry2(row) +} + +// Delete method deletes an IP route entry on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-deleteipforwardentry2 +func (row *MibIPforwardRow2) Delete() error { + return deleteIPForwardEntry2(row) +} + +// get method returns all table rows as a Go slice. +func (tab *mibIPforwardTable2) get() []MibIPforwardRow2 { + const maxCount = maxIndexCount8 / unsafe.Sizeof(MibIPforwardRow2{}) + return (*[maxCount]MibIPforwardRow2)(unsafe.Pointer(&tab.table[0]))[:tab.numEntries] +} + +// free method frees the buffer allocated by the functions that return tables of network interfaces, addresses, and routes. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-freemibtable +func (tab *mibIPforwardTable2) free() { + freeMibTable(unsafe.Pointer(tab)) +} diff --git a/tunnel/winipcfg/types_386.go b/tunnel/winipcfg/types_386.go new file mode 100644 index 00000000..3a4b5733 --- /dev/null +++ b/tunnel/winipcfg/types_386.go @@ -0,0 +1,230 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "golang.org/x/sys/windows" +) + +// IPAdapterWINSServerAddress structure stores a single Windows Internet Name Service (WINS) server address in a linked list of WINS server addresses for a particular adapter. +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_wins_server_address_lh +type IPAdapterWINSServerAddress struct { + Length uint32 + _ uint32 + Next *IPAdapterWINSServerAddress + Address windows.SocketAddress + _ [4]byte +} + +// IPAdapterGatewayAddress structure stores a single gateway address in a linked list of gateway addresses for a particular adapter. +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_gateway_address_lh +type IPAdapterGatewayAddress struct { + Length uint32 + _ uint32 + Next *IPAdapterGatewayAddress + Address windows.SocketAddress + _ [4]byte +} + +// IPAdapterAddresses structure is the header node for a linked list of addresses for a particular adapter. This structure can simultaneously be used as part of a linked list of IP_ADAPTER_ADDRESSES structures. +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_addresses_lh +// This is a modified and extended version of windows.IpAdapterAddresses. +type IPAdapterAddresses struct { + Length uint32 + IfIndex uint32 + Next *IPAdapterAddresses + adapterName *byte + FirstUnicastAddress *windows.IpAdapterUnicastAddress + FirstAnycastAddress *windows.IpAdapterAnycastAddress + FirstMulticastAddress *windows.IpAdapterMulticastAddress + FirstDNSServerAddress *windows.IpAdapterDnsServerAdapter + dnsSuffix *uint16 + description *uint16 + friendlyName *uint16 + physicalAddress [windows.MAX_ADAPTER_ADDRESS_LENGTH]byte + physicalAddressLength uint32 + Flags IPAAFlags + MTU uint32 + IfType IfType + OperStatus IfOperStatus + IPv6IfIndex uint32 + ZoneIndices [16]uint32 + FirstPrefix *windows.IpAdapterPrefix + TransmitLinkSpeed uint64 + ReceiveLinkSpeed uint64 + FirstWINSServerAddress *IPAdapterWINSServerAddress + FirstGatewayAddress *IPAdapterGatewayAddress + Ipv4Metric uint32 + Ipv6Metric uint32 + LUID LUID + DHCPv4Server windows.SocketAddress + CompartmentID uint32 + NetworkGUID windows.GUID + ConnectionType NetIfConnectionType + TunnelType TunnelType + DHCPv6Server windows.SocketAddress + dhcpv6ClientDUID [maxDHCPv6DUIDLength]byte + dhcpv6ClientDUIDLength uint32 + DHCPv6IAID uint32 + FirstDNSSuffix *IPAdapterDNSSuffix + _ [4]byte +} + +// MibIPInterfaceRow structure stores interface management information for a particular IP address family on a network interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_ipinterface_row +type MibIPInterfaceRow struct { + Family AddressFamily + _ [4]byte + InterfaceLUID LUID + InterfaceIndex uint32 + MaxReassemblySize uint32 + InterfaceIdentifier uint64 + MinRouterAdvertisementInterval uint32 + MaxRouterAdvertisementInterval uint32 + AdvertisingEnabled bool + ForwardingEnabled bool + WeakHostSend bool + WeakHostReceive bool + UseAutomaticMetric bool + UseNeighborUnreachabilityDetection bool + ManagedAddressConfigurationSupported bool + OtherStatefulConfigurationSupported bool + AdvertiseDefaultRoute bool + RouterDiscoveryBehavior RouterDiscoveryBehavior + DadTransmits uint32 + BaseReachableTime uint32 + RetransmitTime uint32 + PathMTUDiscoveryTimeout uint32 + LinkLocalAddressBehavior LinkLocalAddressBehavior + LinkLocalAddressTimeout uint32 + ZoneIndices [ScopeLevelCount]uint32 + SitePrefixLength uint32 + Metric uint32 + NLMTU uint32 + Connected bool + SupportsWakeUpPatterns bool + SupportsNeighborDiscovery bool + SupportsRouterDiscovery bool + ReachableTime uint32 + TransmitOffload OffloadRod + ReceiveOffload OffloadRod + DisableDefaultRoutes bool +} + +// mibIPInterfaceTable structure contains a table of IP interface entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_ipinterface_table +type mibIPInterfaceTable struct { + numEntries uint32 + _ [4]byte + table [anySize]MibIPInterfaceRow +} + +// MibIfRow2 structure stores information about a particular interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_if_row2 +type MibIfRow2 struct { + InterfaceLUID LUID + InterfaceIndex uint32 + InterfaceGUID windows.GUID + alias [ifMaxStringSize + 1]uint16 + description [ifMaxStringSize + 1]uint16 + physicalAddressLength uint32 + physicalAddress [ifMaxPhysAddressLength]byte + permanentPhysicalAddress [ifMaxPhysAddressLength]byte + MTU uint32 + Type IfType + TunnelType TunnelType + MediaType NdisMedium + PhysicalMediumType NdisPhysicalMedium + AccessType NetIfAccessType + DirectionType NetIfDirectionType + InterfaceAndOperStatusFlags InterfaceAndOperStatusFlags + OperStatus IfOperStatus + AdminStatus NetIfAdminStatus + MediaConnectState NetIfMediaConnectState + NetworkGUID windows.GUID + ConnectionType NetIfConnectionType + _ [4]byte + TransmitLinkSpeed uint64 + ReceiveLinkSpeed uint64 + InOctets uint64 + InUcastPkts uint64 + InNUcastPkts uint64 + InDiscards uint64 + InErrors uint64 + InUnknownProtos uint64 + InUcastOctets uint64 + InMulticastOctets uint64 + InBroadcastOctets uint64 + OutOctets uint64 + OutUcastPkts uint64 + OutNUcastPkts uint64 + OutDiscards uint64 + OutErrors uint64 + OutUcastOctets uint64 + OutMulticastOctets uint64 + OutBroadcastOctets uint64 + OutQLen uint64 +} + +// mibIfTable2 structure contains a table of logical and physical interface entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_if_table2 +type mibIfTable2 struct { + numEntries uint32 + _ [4]byte + table [anySize]MibIfRow2 +} + +// MibUnicastIPAddressRow structure stores information about a unicast IP address. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_unicastipaddress_row +type MibUnicastIPAddressRow struct { + Address RawSockaddrInet + _ [4]byte + InterfaceLUID LUID + InterfaceIndex uint32 + PrefixOrigin PrefixOrigin + SuffixOrigin SuffixOrigin + ValidLifetime uint32 + PreferredLifetime uint32 + OnLinkPrefixLength uint8 + SkipAsSource bool + DadState DadState + ScopeID uint32 + CreationTimeStamp int64 +} + +// mibUnicastIPAddressTable structure contains a table of unicast IP address entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_unicastipaddress_table +type mibUnicastIPAddressTable struct { + numEntries uint32 + _ [4]byte + table [anySize]MibUnicastIPAddressRow +} + +// MibAnycastIPAddressRow structure stores information about an anycast IP address. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_anycastipaddress_row +type MibAnycastIPAddressRow struct { + Address RawSockaddrInet + _ [4]byte + InterfaceLUID LUID + InterfaceIndex uint32 + ScopeID uint32 +} + +// mibAnycastIPAddressTable structure contains a table of anycast IP address entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-mib_anycastipaddress_table +type mibAnycastIPAddressTable struct { + numEntries uint32 + _ [4]byte + table [anySize]MibAnycastIPAddressRow +} + +// mibIPforwardTable2 structure contains a table of IP route entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_ipforward_table2 +type mibIPforwardTable2 struct { + numEntries uint32 + _ [4]byte + table [anySize]MibIPforwardRow2 +} diff --git a/tunnel/winipcfg/types_amd64.go b/tunnel/winipcfg/types_amd64.go new file mode 100644 index 00000000..11242891 --- /dev/null +++ b/tunnel/winipcfg/types_amd64.go @@ -0,0 +1,218 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "golang.org/x/sys/windows" +) + +// IPAdapterWINSServerAddress structure stores a single Windows Internet Name Service (WINS) server address in a linked list of WINS server addresses for a particular adapter. +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_wins_server_address_lh +type IPAdapterWINSServerAddress struct { + Length uint32 + _ uint32 + Next *IPAdapterWINSServerAddress + Address windows.SocketAddress +} + +// IPAdapterGatewayAddress structure stores a single gateway address in a linked list of gateway addresses for a particular adapter. +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_gateway_address_lh +type IPAdapterGatewayAddress struct { + Length uint32 + _ uint32 + Next *IPAdapterGatewayAddress + Address windows.SocketAddress +} + +// IPAdapterAddresses structure is the header node for a linked list of addresses for a particular adapter. This structure can simultaneously be used as part of a linked list of IP_ADAPTER_ADDRESSES structures. +// https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_adapter_addresses_lh +// This is a modified and extended version of windows.IpAdapterAddresses. +type IPAdapterAddresses struct { + Length uint32 + IfIndex uint32 + Next *IPAdapterAddresses + adapterName *byte + FirstUnicastAddress *windows.IpAdapterUnicastAddress + FirstAnycastAddress *windows.IpAdapterAnycastAddress + FirstMulticastAddress *windows.IpAdapterMulticastAddress + FirstDNSServerAddress *windows.IpAdapterDnsServerAdapter + dnsSuffix *uint16 + description *uint16 + friendlyName *uint16 + physicalAddress [windows.MAX_ADAPTER_ADDRESS_LENGTH]byte + physicalAddressLength uint32 + Flags IPAAFlags + MTU uint32 + IfType IfType + OperStatus IfOperStatus + IPv6IfIndex uint32 + ZoneIndices [16]uint32 + FirstPrefix *windows.IpAdapterPrefix + TransmitLinkSpeed uint64 + ReceiveLinkSpeed uint64 + FirstWINSServerAddress *IPAdapterWINSServerAddress + FirstGatewayAddress *IPAdapterGatewayAddress + Ipv4Metric uint32 + Ipv6Metric uint32 + LUID LUID + DHCPv4Server windows.SocketAddress + CompartmentID uint32 + NetworkGUID windows.GUID + ConnectionType NetIfConnectionType + TunnelType TunnelType + DHCPv6Server windows.SocketAddress + dhcpv6ClientDUID [maxDHCPv6DUIDLength]byte + dhcpv6ClientDUIDLength uint32 + DHCPv6IAID uint32 + FirstDNSSuffix *IPAdapterDNSSuffix +} + +// MibIPInterfaceRow structure stores interface management information for a particular IP address family on a network interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_ipinterface_row +type MibIPInterfaceRow struct { + Family AddressFamily + InterfaceLUID LUID + InterfaceIndex uint32 + MaxReassemblySize uint32 + InterfaceIdentifier uint64 + MinRouterAdvertisementInterval uint32 + MaxRouterAdvertisementInterval uint32 + AdvertisingEnabled bool + ForwardingEnabled bool + WeakHostSend bool + WeakHostReceive bool + UseAutomaticMetric bool + UseNeighborUnreachabilityDetection bool + ManagedAddressConfigurationSupported bool + OtherStatefulConfigurationSupported bool + AdvertiseDefaultRoute bool + RouterDiscoveryBehavior RouterDiscoveryBehavior + DadTransmits uint32 + BaseReachableTime uint32 + RetransmitTime uint32 + PathMTUDiscoveryTimeout uint32 + LinkLocalAddressBehavior LinkLocalAddressBehavior + LinkLocalAddressTimeout uint32 + ZoneIndices [ScopeLevelCount]uint32 + SitePrefixLength uint32 + Metric uint32 + NLMTU uint32 + Connected bool + SupportsWakeUpPatterns bool + SupportsNeighborDiscovery bool + SupportsRouterDiscovery bool + ReachableTime uint32 + TransmitOffload OffloadRod + ReceiveOffload OffloadRod + DisableDefaultRoutes bool +} + +// mibIPInterfaceTable structure contains a table of IP interface entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_ipinterface_table +type mibIPInterfaceTable struct { + numEntries uint32 + table [anySize]MibIPInterfaceRow +} + +// MibIfRow2 structure stores information about a particular interface. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_if_row2 +type MibIfRow2 struct { + InterfaceLUID LUID + InterfaceIndex uint32 + InterfaceGUID windows.GUID + alias [ifMaxStringSize + 1]uint16 + description [ifMaxStringSize + 1]uint16 + physicalAddressLength uint32 + physicalAddress [ifMaxPhysAddressLength]byte + permanentPhysicalAddress [ifMaxPhysAddressLength]byte + MTU uint32 + Type IfType + TunnelType TunnelType + MediaType NdisMedium + PhysicalMediumType NdisPhysicalMedium + AccessType NetIfAccessType + DirectionType NetIfDirectionType + InterfaceAndOperStatusFlags InterfaceAndOperStatusFlags + OperStatus IfOperStatus + AdminStatus NetIfAdminStatus + MediaConnectState NetIfMediaConnectState + NetworkGUID windows.GUID + ConnectionType NetIfConnectionType + TransmitLinkSpeed uint64 + ReceiveLinkSpeed uint64 + InOctets uint64 + InUcastPkts uint64 + InNUcastPkts uint64 + InDiscards uint64 + InErrors uint64 + InUnknownProtos uint64 + InUcastOctets uint64 + InMulticastOctets uint64 + InBroadcastOctets uint64 + OutOctets uint64 + OutUcastPkts uint64 + OutNUcastPkts uint64 + OutDiscards uint64 + OutErrors uint64 + OutUcastOctets uint64 + OutMulticastOctets uint64 + OutBroadcastOctets uint64 + OutQLen uint64 +} + +// mibIfTable2 structure contains a table of logical and physical interface entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_if_table2 +type mibIfTable2 struct { + numEntries uint32 + table [anySize]MibIfRow2 +} + +// MibUnicastIPAddressRow structure stores information about a unicast IP address. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_unicastipaddress_row +type MibUnicastIPAddressRow struct { + Address RawSockaddrInet + InterfaceLUID LUID + InterfaceIndex uint32 + PrefixOrigin PrefixOrigin + SuffixOrigin SuffixOrigin + ValidLifetime uint32 + PreferredLifetime uint32 + OnLinkPrefixLength uint8 + SkipAsSource bool + DadState DadState + ScopeID uint32 + CreationTimeStamp int64 +} + +// mibUnicastIPAddressTable structure contains a table of unicast IP address entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_unicastipaddress_table +type mibUnicastIPAddressTable struct { + numEntries uint32 + table [anySize]MibUnicastIPAddressRow +} + +// MibAnycastIPAddressRow structure stores information about an anycast IP address. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_anycastipaddress_row +type MibAnycastIPAddressRow struct { + Address RawSockaddrInet + InterfaceLUID LUID + InterfaceIndex uint32 + ScopeID uint32 +} + +// mibAnycastIPAddressTable structure contains a table of anycast IP address entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-mib_anycastipaddress_table +type mibAnycastIPAddressTable struct { + numEntries uint32 + table [anySize]MibAnycastIPAddressRow +} + +// mibIPforwardTable2 structure contains a table of IP route entries. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/ns-netioapi-_mib_ipforward_table2 +type mibIPforwardTable2 struct { + numEntries uint32 + table [anySize]MibIPforwardRow2 +} diff --git a/tunnel/winipcfg/types_test.go b/tunnel/winipcfg/types_test.go new file mode 100644 index 00000000..c7494e8c --- /dev/null +++ b/tunnel/winipcfg/types_test.go @@ -0,0 +1,1057 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "testing" + "unsafe" +) + +const ( + mibIPInterfaceRowSize = 168 + mibIPInterfaceRowInterfaceLUIDOffset = 8 + mibIPInterfaceRowInterfaceIndexOffset = 16 + mibIPInterfaceRowMaxReassemblySizeOffset = 20 + mibIPInterfaceRowInterfaceIdentifierOffset = 24 + mibIPInterfaceRowMinRouterAdvertisementIntervalOffset = 32 + mibIPInterfaceRowMaxRouterAdvertisementIntervalOffset = 36 + mibIPInterfaceRowAdvertisingEnabledOffset = 40 + mibIPInterfaceRowForwardingEnabledOffset = 41 + mibIPInterfaceRowWeakHostSendOffset = 42 + mibIPInterfaceRowWeakHostReceiveOffset = 43 + mibIPInterfaceRowUseAutomaticMetricOffset = 44 + mibIPInterfaceRowUseNeighborUnreachabilityDetectionOffset = 45 + mibIPInterfaceRowManagedAddressConfigurationSupportedOffset = 46 + mibIPInterfaceRowOtherStatefulConfigurationSupportedOffset = 47 + mibIPInterfaceRowAdvertiseDefaultRouteOffset = 48 + mibIPInterfaceRowRouterDiscoveryBehaviorOffset = 52 + mibIPInterfaceRowDadTransmitsOffset = 56 + mibIPInterfaceRowBaseReachableTimeOffset = 60 + mibIPInterfaceRowRetransmitTimeOffset = 64 + mibIPInterfaceRowPathMTUDiscoveryTimeoutOffset = 68 + mibIPInterfaceRowLinkLocalAddressBehaviorOffset = 72 + mibIPInterfaceRowLinkLocalAddressTimeoutOffset = 76 + mibIPInterfaceRowZoneIndicesOffset = 80 + mibIPInterfaceRowSitePrefixLengthOffset = 144 + mibIPInterfaceRowMetricOffset = 148 + mibIPInterfaceRowNLMTUOffset = 152 + mibIPInterfaceRowConnectedOffset = 156 + mibIPInterfaceRowSupportsWakeUpPatternsOffset = 157 + mibIPInterfaceRowSupportsNeighborDiscoveryOffset = 158 + mibIPInterfaceRowSupportsRouterDiscoveryOffset = 159 + mibIPInterfaceRowReachableTimeOffset = 160 + mibIPInterfaceRowTransmitOffloadOffset = 164 + mibIPInterfaceRowReceiveOffloadOffset = 165 + mibIPInterfaceRowDisableDefaultRoutesOffset = 166 + + mibIPInterfaceTableSize = 176 + mibIPInterfaceTableTableOffset = 8 + + mibIfRow2Size = 1352 + mibIfRow2InterfaceIndexOffset = 8 + mibIfRow2InterfaceGUIDOffset = 12 + mibIfRow2AliasOffset = 28 + mibIfRow2DescriptionOffset = 542 + mibIfRow2PhysicalAddressLengthOffset = 1056 + mibIfRow2PhysicalAddressOffset = 1060 + mibIfRow2PermanentPhysicalAddressOffset = 1092 + mibIfRow2MTUOffset = 1124 + mibIfRow2TypeOffset = 1128 + mibIfRow2TunnelTypeOffset = 1132 + mibIfRow2MediaTypeOffset = 1136 + mibIfRow2PhysicalMediumTypeOffset = 1140 + mibIfRow2AccessTypeOffset = 1144 + mibIfRow2DirectionTypeOffset = 1148 + mibIfRow2InterfaceAndOperStatusFlagsOffset = 1152 + mibIfRow2OperStatusOffset = 1156 + mibIfRow2AdminStatusOffset = 1160 + mibIfRow2MediaConnectStateOffset = 1164 + mibIfRow2NetworkGUIDOffset = 1168 + mibIfRow2ConnectionTypeOffset = 1184 + mibIfRow2TransmitLinkSpeedOffset = 1192 + mibIfRow2ReceiveLinkSpeedOffset = 1200 + mibIfRow2InOctetsOffset = 1208 + mibIfRow2InUcastPktsOffset = 1216 + mibIfRow2InNUcastPktsOffset = 1224 + mibIfRow2InDiscardsOffset = 1232 + mibIfRow2InErrorsOffset = 1240 + mibIfRow2InUnknownProtosOffset = 1248 + mibIfRow2InUcastOctetsOffset = 1256 + mibIfRow2InMulticastOctetsOffset = 1264 + mibIfRow2InBroadcastOctetsOffset = 1272 + mibIfRow2OutOctetsOffset = 1280 + mibIfRow2OutUcastPktsOffset = 1288 + mibIfRow2OutNUcastPktsOffset = 1296 + mibIfRow2OutDiscardsOffset = 1304 + mibIfRow2OutErrorsOffset = 1312 + mibIfRow2OutUcastOctetsOffset = 1320 + mibIfRow2OutMulticastOctetsOffset = 1328 + mibIfRow2OutBroadcastOctetsOffset = 1336 + mibIfRow2OutQLenOffset = 1344 + + mibIfTable2Size = 1360 + mibIfTable2TableOffset = 8 + + rawSockaddrInetSize = 28 + rawSockaddrInetDataOffset = 2 + + mibUnicastIPAddressRowSize = 80 + mibUnicastIPAddressRowInterfaceLUIDOffset = 32 + mibUnicastIPAddressRowInterfaceIndexOffset = 40 + mibUnicastIPAddressRowPrefixOriginOffset = 44 + mibUnicastIPAddressRowSuffixOriginOffset = 48 + mibUnicastIPAddressRowValidLifetimeOffset = 52 + mibUnicastIPAddressRowPreferredLifetimeOffset = 56 + mibUnicastIPAddressRowOnLinkPrefixLengthOffset = 60 + mibUnicastIPAddressRowSkipAsSourceOffset = 61 + mibUnicastIPAddressRowDadStateOffset = 64 + mibUnicastIPAddressRowScopeIDOffset = 68 + mibUnicastIPAddressRowCreationTimeStampOffset = 72 + + mibUnicastIPAddressTableSize = 88 + mibUnicastIPAddressTableTableOffset = 8 + + mibAnycastIPAddressRowSize = 48 + mibAnycastIPAddressRowInterfaceLUIDOffset = 32 + mibAnycastIPAddressRowInterfaceIndexOffset = 40 + mibAnycastIPAddressRowScopeIDOffset = 44 + + mibAnycastIPAddressTableSize = 56 + mibAnycastIPAddressTableTableOffset = 8 + + ipAddressPrefixSize = 32 + ipAddressPrefixPrefixLengthOffset = 28 + + mibIPforwardRow2Size = 104 + mibIPforwardRow2InterfaceIndexOffset = 8 + mibIPforwardRow2DestinationPrefixOffset = 12 + mibIPforwardRow2NextHopOffset = 44 + mibIPforwardRow2SitePrefixLengthOffset = 72 + mibIPforwardRow2ValidLifetimeOffset = 76 + mibIPforwardRow2PreferredLifetimeOffset = 80 + mibIPforwardRow2MetricOffset = 84 + mibIPforwardRow2ProtocolOffset = 88 + mibIPforwardRow2LoopbackOffset = 92 + mibIPforwardRow2AutoconfigureAddressOffset = 93 + mibIPforwardRow2PublishOffset = 94 + mibIPforwardRow2ImmortalOffset = 95 + mibIPforwardRow2AgeOffset = 96 + mibIPforwardRow2OriginOffset = 100 + + mibIPforwardTable2Size = 112 + mibIPforwardTable2TableOffset = 8 +) + +func TestIPAdapterWINSServerAddress(t *testing.T) { + s := IPAdapterWINSServerAddress{} + sp := uintptr(unsafe.Pointer(&s)) + const actualIPAdapterWINSServerAddressSize = unsafe.Sizeof(s) + + if actualIPAdapterWINSServerAddressSize != ipAdapterWINSServerAddressSize { + t.Errorf("Size of IPAdapterWINSServerAddress is %d, although %d is expected.", actualIPAdapterWINSServerAddressSize, ipAdapterWINSServerAddressSize) + } + + offset := uintptr(unsafe.Pointer(&s.Next)) - sp + if offset != ipAdapterWINSServerAddressNextOffset { + t.Errorf("IPAdapterWINSServerAddress.Next offset is %d although %d is expected", offset, ipAdapterWINSServerAddressNextOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Address)) - sp + if offset != ipAdapterWINSServerAddressAddressOffset { + t.Errorf("IPAdapterWINSServerAddress.Address offset is %d although %d is expected", offset, ipAdapterWINSServerAddressAddressOffset) + } +} + +func TestIPAdapterGatewayAddress(t *testing.T) { + s := IPAdapterGatewayAddress{} + sp := uintptr(unsafe.Pointer(&s)) + const actualIPAdapterGatewayAddressSize = unsafe.Sizeof(s) + + if actualIPAdapterGatewayAddressSize != ipAdapterGatewayAddressSize { + t.Errorf("Size of IPAdapterGatewayAddress is %d, although %d is expected.", actualIPAdapterGatewayAddressSize, ipAdapterGatewayAddressSize) + } + + offset := uintptr(unsafe.Pointer(&s.Next)) - sp + if offset != ipAdapterGatewayAddressNextOffset { + t.Errorf("IPAdapterGatewayAddress.Next offset is %d although %d is expected", offset, ipAdapterGatewayAddressNextOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Address)) - sp + if offset != ipAdapterGatewayAddressAddressOffset { + t.Errorf("IPAdapterGatewayAddress.Address offset is %d although %d is expected", offset, ipAdapterGatewayAddressAddressOffset) + } +} + +func TestIPAdapterDNSSuffix(t *testing.T) { + s := IPAdapterDNSSuffix{} + sp := uintptr(unsafe.Pointer(&s)) + const actualIPAdapterDNSSuffixSize = unsafe.Sizeof(s) + + if actualIPAdapterDNSSuffixSize != ipAdapterDNSSuffixSize { + t.Errorf("Size of IPAdapterDNSSuffix is %d, although %d is expected.", actualIPAdapterDNSSuffixSize, ipAdapterDNSSuffixSize) + } + + offset := uintptr(unsafe.Pointer(&s.str)) - sp + if offset != ipAdapterDNSSuffixStringOffset { + t.Errorf("IPAdapterDNSSuffix.str offset is %d although %d is expected", offset, ipAdapterDNSSuffixStringOffset) + } +} + +func TestInAdapterAddresses(t *testing.T) { + s := IPAdapterAddresses{} + sp := uintptr(unsafe.Pointer(&s)) + const actualIn6AddrSize = unsafe.Sizeof(s) + + if actualIn6AddrSize != ipAdapterAddressesSize { + t.Errorf("Size of IPAdapterAddresses is %d, although %d is expected.", actualIn6AddrSize, ipAdapterAddressesSize) + } + + offset := uintptr(unsafe.Pointer(&s.IfIndex)) - sp + if offset != ipAdapterAddressesIfIndexOffset { + t.Errorf("IPAdapterAddresses.IfIndex offset is %d although %d is expected", offset, ipAdapterAddressesIfIndexOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Next)) - sp + if offset != ipAdapterAddressesNextOffset { + t.Errorf("IPAdapterAddresses.Next offset is %d although %d is expected", offset, ipAdapterAddressesNextOffset) + } + + offset = uintptr(unsafe.Pointer(&s.adapterName)) - sp + if offset != ipAdapterAddressesAdapterNameOffset { + t.Errorf("IPAdapterAddresses.adapterName offset is %d although %d is expected", offset, ipAdapterAddressesAdapterNameOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstUnicastAddress)) - sp + if offset != ipAdapterAddressesFirstUnicastAddressOffset { + t.Errorf("IPAdapterAddresses.FirstUnicastAddress offset is %d although %d is expected", offset, ipAdapterAddressesFirstUnicastAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstAnycastAddress)) - sp + if offset != ipAdapterAddressesFirstAnycastAddressOffset { + t.Errorf("IPAdapterAddresses.FirstAnycastAddress offset is %d although %d is expected", offset, ipAdapterAddressesFirstAnycastAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstMulticastAddress)) - sp + if offset != ipAdapterAddressesFirstMulticastAddressOffset { + t.Errorf("IPAdapterAddresses.FirstMulticastAddress offset is %d although %d is expected", offset, ipAdapterAddressesFirstMulticastAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstDNSServerAddress)) - sp + if offset != ipAdapterAddressesFirstDNSServerAddressOffset { + t.Errorf("IPAdapterAddresses.FirstDNSServerAddress offset is %d although %d is expected", offset, ipAdapterAddressesFirstDNSServerAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.dnsSuffix)) - sp + if offset != ipAdapterAddressesDNSSuffixOffset { + t.Errorf("IPAdapterAddresses.DNSSuffix offset is %d although %d is expected", offset, ipAdapterAddressesDNSSuffixOffset) + } + + offset = uintptr(unsafe.Pointer(&s.description)) - sp + if offset != ipAdapterAddressesDescriptionOffset { + t.Errorf("IPAdapterAddresses.Description offset is %d although %d is expected", offset, ipAdapterAddressesDescriptionOffset) + } + + offset = uintptr(unsafe.Pointer(&s.friendlyName)) - sp + if offset != ipAdapterAddressesFriendlyNameOffset { + t.Errorf("IPAdapterAddresses.FriendlyName offset is %d although %d is expected", offset, ipAdapterAddressesFriendlyNameOffset) + } + + offset = uintptr(unsafe.Pointer(&s.physicalAddress)) - sp + if offset != ipAdapterAddressesPhysicalAddressOffset { + t.Errorf("IPAdapterAddresses.PhysicalAddress offset is %d although %d is expected", offset, ipAdapterAddressesPhysicalAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.physicalAddressLength)) - sp + if offset != ipAdapterAddressesPhysicalAddressLengthOffset { + t.Errorf("IPAdapterAddresses.PhysicalAddressLength offset is %d although %d is expected", offset, ipAdapterAddressesPhysicalAddressLengthOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Flags)) - sp + if offset != ipAdapterAddressesFlagsOffset { + t.Errorf("IPAdapterAddresses.Flags offset is %d although %d is expected", offset, ipAdapterAddressesFlagsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.MTU)) - sp + if offset != ipAdapterAddressesMTUOffset { + t.Errorf("IPAdapterAddresses.MTU offset is %d although %d is expected", offset, ipAdapterAddressesMTUOffset) + } + + offset = uintptr(unsafe.Pointer(&s.IfType)) - sp + if offset != ipAdapterAddressesIfTypeOffset { + t.Errorf("IPAdapterAddresses.IfType offset is %d although %d is expected", offset, ipAdapterAddressesIfTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OperStatus)) - sp + if offset != ipAdapterAddressesOperStatusOffset { + t.Errorf("IPAdapterAddresses.OperStatus offset is %d although %d is expected", offset, ipAdapterAddressesOperStatusOffset) + } + + offset = uintptr(unsafe.Pointer(&s.IPv6IfIndex)) - sp + if offset != ipAdapterAddressesIPv6IfIndexOffset { + t.Errorf("IPAdapterAddresses.IPv6IfIndex offset is %d although %d is expected", offset, ipAdapterAddressesIPv6IfIndexOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ZoneIndices)) - sp + if offset != ipAdapterAddressesZoneIndicesOffset { + t.Errorf("IPAdapterAddresses.ZoneIndices offset is %d although %d is expected", offset, ipAdapterAddressesZoneIndicesOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstPrefix)) - sp + if offset != ipAdapterAddressesFirstPrefixOffset { + t.Errorf("IPAdapterAddresses.FirstPrefix offset is %d although %d is expected", offset, ipAdapterAddressesFirstPrefixOffset) + } + + offset = uintptr(unsafe.Pointer(&s.TransmitLinkSpeed)) - sp + if offset != ipAdapterAddressesTransmitLinkSpeedOffset { + t.Errorf("IPAdapterAddresses.TransmitLinkSpeed offset is %d although %d is expected", offset, ipAdapterAddressesTransmitLinkSpeedOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ReceiveLinkSpeed)) - sp + if offset != ipAdapterAddressesReceiveLinkSpeedOffset { + t.Errorf("IPAdapterAddresses.ReceiveLinkSpeed offset is %d although %d is expected", offset, ipAdapterAddressesReceiveLinkSpeedOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstWINSServerAddress)) - sp + if offset != ipAdapterAddressesFirstWINSServerAddressOffset { + t.Errorf("IPAdapterAddresses.FirstWINSServerAddress offset is %d although %d is expected", offset, ipAdapterAddressesFirstWINSServerAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstGatewayAddress)) - sp + if offset != ipAdapterAddressesFirstGatewayAddressOffset { + t.Errorf("IPAdapterAddresses.FirstGatewayAddress offset is %d although %d is expected", offset, ipAdapterAddressesFirstGatewayAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Ipv4Metric)) - sp + if offset != ipAdapterAddressesIPv4MetricOffset { + t.Errorf("IPAdapterAddresses.IPv4Metric offset is %d although %d is expected", offset, ipAdapterAddressesIPv4MetricOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Ipv6Metric)) - sp + if offset != ipAdapterAddressesIPv6MetricOffset { + t.Errorf("IPAdapterAddresses.IPv6Metric offset is %d although %d is expected", offset, ipAdapterAddressesIPv6MetricOffset) + } + + offset = uintptr(unsafe.Pointer(&s.LUID)) - sp + if offset != ipAdapterAddressesLUIDOffset { + t.Errorf("IPAdapterAddresses.LUID offset is %d although %d is expected", offset, ipAdapterAddressesLUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DHCPv4Server)) - sp + if offset != ipAdapterAddressesDHCPv4ServerOffset { + t.Errorf("IPAdapterAddresses.DHCPv4Server offset is %d although %d is expected", offset, ipAdapterAddressesDHCPv4ServerOffset) + } + + offset = uintptr(unsafe.Pointer(&s.CompartmentID)) - sp + if offset != ipAdapterAddressesCompartmentIDOffset { + t.Errorf("IPAdapterAddresses.CompartmentID offset is %d although %d is expected", offset, ipAdapterAddressesCompartmentIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.NetworkGUID)) - sp + if offset != ipAdapterAddressesNetworkGUIDOffset { + t.Errorf("IPAdapterAddresses.NetworkGUID offset is %d although %d is expected", offset, ipAdapterAddressesNetworkGUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ConnectionType)) - sp + if offset != ipAdapterAddressesConnectionTypeOffset { + t.Errorf("IPAdapterAddresses.ConnectionType offset is %d although %d is expected", offset, ipAdapterAddressesConnectionTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.TunnelType)) - sp + if offset != ipAdapterAddressesTunnelTypeOffset { + t.Errorf("IPAdapterAddresses.TunnelType offset is %d although %d is expected", offset, ipAdapterAddressesTunnelTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DHCPv6Server)) - sp + if offset != ipAdapterAddressesDHCPv6ServerOffset { + t.Errorf("IPAdapterAddresses.DHCPv6Server offset is %d although %d is expected", offset, ipAdapterAddressesDHCPv6ServerOffset) + } + + offset = uintptr(unsafe.Pointer(&s.dhcpv6ClientDUID)) - sp + if offset != ipAdapterAddressesDHCPv6ClientDUIDOffset { + t.Errorf("IPAdapterAddresses.DHCPv6ClientDUID offset is %d although %d is expected", offset, ipAdapterAddressesDHCPv6ClientDUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.dhcpv6ClientDUIDLength)) - sp + if offset != ipAdapterAddressesDHCPv6ClientDUIDLengthOffset { + t.Errorf("IPAdapterAddresses.DHCPv6ClientDUIDLength offset is %d although %d is expected", offset, ipAdapterAddressesDHCPv6ClientDUIDLengthOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DHCPv6IAID)) - sp + if offset != ipAdapterAddressesDHCPv6IAIDOffset { + t.Errorf("IPAdapterAddresses.DHCPv6IAID offset is %d although %d is expected", offset, ipAdapterAddressesDHCPv6IAIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.FirstDNSSuffix)) - sp + if offset != ipAdapterAddressesFirstDNSSuffixOffset { + t.Errorf("IPAdapterAddresses.FirstDNSSuffix offset is %d although %d is expected", offset, ipAdapterAddressesFirstDNSSuffixOffset) + } +} + +func TestMibIPInterfaceRow(t *testing.T) { + s := MibIPInterfaceRow{} + sp := uintptr(unsafe.Pointer(&s)) + const actualTestMibIPInterfaceRowSize = unsafe.Sizeof(s) + + if actualTestMibIPInterfaceRowSize != mibIPInterfaceRowSize { + t.Errorf("Size of MibIPInterfaceRow is %d, although %d is expected.", actualTestMibIPInterfaceRowSize, mibIPInterfaceRowSize) + } + + offset := uintptr(unsafe.Pointer(&s.InterfaceLUID)) - sp + if offset != mibIPInterfaceRowInterfaceLUIDOffset { + t.Errorf("MibIPInterfaceRow.InterfaceLUID offset is %d although %d is expected", offset, mibIPInterfaceRowInterfaceLUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InterfaceIndex)) - sp + if offset != mibIPInterfaceRowInterfaceIndexOffset { + t.Errorf("MibIPInterfaceRow.InterfaceIndex offset is %d although %d is expected", offset, mibIPInterfaceRowInterfaceIndexOffset) + } + + offset = uintptr(unsafe.Pointer(&s.MaxReassemblySize)) - sp + if offset != mibIPInterfaceRowMaxReassemblySizeOffset { + t.Errorf("mibIPInterfaceRow.MaxReassemblySize offset is %d although %d is expected", offset, mibIPInterfaceRowMaxReassemblySizeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InterfaceIdentifier)) - sp + if offset != mibIPInterfaceRowInterfaceIdentifierOffset { + t.Errorf("MibIPInterfaceRow.InterfaceIdentifier offset is %d although %d is expected", offset, mibIPInterfaceRowInterfaceIdentifierOffset) + } + + offset = uintptr(unsafe.Pointer(&s.MinRouterAdvertisementInterval)) - sp + if offset != mibIPInterfaceRowMinRouterAdvertisementIntervalOffset { + t.Errorf("MibIPInterfaceRow.MinRouterAdvertisementInterval offset is %d although %d is expected", offset, mibIPInterfaceRowMinRouterAdvertisementIntervalOffset) + } + + offset = uintptr(unsafe.Pointer(&s.MaxRouterAdvertisementInterval)) - sp + if offset != mibIPInterfaceRowMaxRouterAdvertisementIntervalOffset { + t.Errorf("MibIPInterfaceRow.MaxRouterAdvertisementInterval offset is %d although %d is expected", offset, mibIPInterfaceRowMaxRouterAdvertisementIntervalOffset) + } + + offset = uintptr(unsafe.Pointer(&s.AdvertisingEnabled)) - sp + if offset != mibIPInterfaceRowAdvertisingEnabledOffset { + t.Errorf("MibIPInterfaceRow.AdvertisingEnabled offset is %d although %d is expected", offset, mibIPInterfaceRowAdvertisingEnabledOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ForwardingEnabled)) - sp + if offset != mibIPInterfaceRowForwardingEnabledOffset { + t.Errorf("MibIPInterfaceRow.ForwardingEnabled offset is %d although %d is expected", offset, mibIPInterfaceRowForwardingEnabledOffset) + } + + offset = uintptr(unsafe.Pointer(&s.WeakHostSend)) - sp + if offset != mibIPInterfaceRowWeakHostSendOffset { + t.Errorf("MibIPInterfaceRow.WeakHostSend offset is %d although %d is expected", offset, mibIPInterfaceRowWeakHostSendOffset) + } + + offset = uintptr(unsafe.Pointer(&s.WeakHostReceive)) - sp + if offset != mibIPInterfaceRowWeakHostReceiveOffset { + t.Errorf("MibIPInterfaceRow.WeakHostReceive offset is %d although %d is expected", offset, mibIPInterfaceRowWeakHostReceiveOffset) + } + + offset = uintptr(unsafe.Pointer(&s.UseAutomaticMetric)) - sp + if offset != mibIPInterfaceRowUseAutomaticMetricOffset { + t.Errorf("MibIPInterfaceRow.UseAutomaticMetric offset is %d although %d is expected", offset, mibIPInterfaceRowUseAutomaticMetricOffset) + } + + offset = uintptr(unsafe.Pointer(&s.UseNeighborUnreachabilityDetection)) - sp + if offset != mibIPInterfaceRowUseNeighborUnreachabilityDetectionOffset { + t.Errorf("MibIPInterfaceRow.UseNeighborUnreachabilityDetection offset is %d although %d is expected", offset, mibIPInterfaceRowUseNeighborUnreachabilityDetectionOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ManagedAddressConfigurationSupported)) - sp + if offset != mibIPInterfaceRowManagedAddressConfigurationSupportedOffset { + t.Errorf("MibIPInterfaceRow.ManagedAddressConfigurationSupported offset is %d although %d is expected", offset, mibIPInterfaceRowManagedAddressConfigurationSupportedOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OtherStatefulConfigurationSupported)) - sp + if offset != mibIPInterfaceRowOtherStatefulConfigurationSupportedOffset { + t.Errorf("MibIPInterfaceRow.OtherStatefulConfigurationSupported offset is %d although %d is expected", offset, mibIPInterfaceRowOtherStatefulConfigurationSupportedOffset) + } + + offset = uintptr(unsafe.Pointer(&s.AdvertiseDefaultRoute)) - sp + if offset != mibIPInterfaceRowAdvertiseDefaultRouteOffset { + t.Errorf("MibIPInterfaceRow.AdvertiseDefaultRoute offset is %d although %d is expected", offset, mibIPInterfaceRowAdvertiseDefaultRouteOffset) + } + + offset = uintptr(unsafe.Pointer(&s.RouterDiscoveryBehavior)) - sp + if offset != mibIPInterfaceRowRouterDiscoveryBehaviorOffset { + t.Errorf("MibIPInterfaceRow.RouterDiscoveryBehavior offset is %d although %d is expected", offset, mibIPInterfaceRowRouterDiscoveryBehaviorOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DadTransmits)) - sp + if offset != mibIPInterfaceRowDadTransmitsOffset { + t.Errorf("MibIPInterfaceRow.DadTransmits offset is %d although %d is expected", offset, mibIPInterfaceRowDadTransmitsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.BaseReachableTime)) - sp + if offset != mibIPInterfaceRowBaseReachableTimeOffset { + t.Errorf("MibIPInterfaceRow.BaseReachableTime offset is %d although %d is expected", offset, mibIPInterfaceRowBaseReachableTimeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.RetransmitTime)) - sp + if offset != mibIPInterfaceRowRetransmitTimeOffset { + t.Errorf("MibIPInterfaceRow.RetransmitTime offset is %d although %d is expected", offset, mibIPInterfaceRowRetransmitTimeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.PathMTUDiscoveryTimeout)) - sp + if offset != mibIPInterfaceRowPathMTUDiscoveryTimeoutOffset { + t.Errorf("MibIPInterfaceRow.PathMTUDiscoveryTimeout offset is %d although %d is expected", offset, mibIPInterfaceRowPathMTUDiscoveryTimeoutOffset) + } + + offset = uintptr(unsafe.Pointer(&s.LinkLocalAddressBehavior)) - sp + if offset != mibIPInterfaceRowLinkLocalAddressBehaviorOffset { + t.Errorf("MibIPInterfaceRow.LinkLocalAddressBehavior offset is %d although %d is expected", offset, mibIPInterfaceRowLinkLocalAddressBehaviorOffset) + } + + offset = uintptr(unsafe.Pointer(&s.LinkLocalAddressTimeout)) - sp + if offset != mibIPInterfaceRowLinkLocalAddressTimeoutOffset { + t.Errorf("MibIPInterfaceRow.LinkLocalAddressTimeout offset is %d although %d is expected", offset, mibIPInterfaceRowLinkLocalAddressTimeoutOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ZoneIndices)) - sp + if offset != mibIPInterfaceRowZoneIndicesOffset { + t.Errorf("MibIPInterfaceRow.ZoneIndices offset is %d although %d is expected", offset, mibIPInterfaceRowZoneIndicesOffset) + } + + offset = uintptr(unsafe.Pointer(&s.SitePrefixLength)) - sp + if offset != mibIPInterfaceRowSitePrefixLengthOffset { + t.Errorf("MibIPInterfaceRow.SitePrefixLength offset is %d although %d is expected", offset, mibIPInterfaceRowSitePrefixLengthOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Metric)) - sp + if offset != mibIPInterfaceRowMetricOffset { + t.Errorf("MibIPInterfaceRow.Metric offset is %d although %d is expected", offset, mibIPInterfaceRowMetricOffset) + } + + offset = uintptr(unsafe.Pointer(&s.NLMTU)) - sp + if offset != mibIPInterfaceRowNLMTUOffset { + t.Errorf("MibIPInterfaceRow.NLMTU offset is %d although %d is expected", offset, mibIPInterfaceRowNLMTUOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Connected)) - sp + if offset != mibIPInterfaceRowConnectedOffset { + t.Errorf("MibIPInterfaceRow.Connected offset is %d although %d is expected", offset, mibIPInterfaceRowConnectedOffset) + } + + offset = uintptr(unsafe.Pointer(&s.SupportsWakeUpPatterns)) - sp + if offset != mibIPInterfaceRowSupportsWakeUpPatternsOffset { + t.Errorf("MibIPInterfaceRow.SupportsWakeUpPatterns offset is %d although %d is expected", offset, mibIPInterfaceRowSupportsWakeUpPatternsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.SupportsNeighborDiscovery)) - sp + if offset != mibIPInterfaceRowSupportsNeighborDiscoveryOffset { + t.Errorf("MibIPInterfaceRow.SupportsNeighborDiscovery offset is %d although %d is expected", offset, mibIPInterfaceRowSupportsNeighborDiscoveryOffset) + } + + offset = uintptr(unsafe.Pointer(&s.SupportsRouterDiscovery)) - sp + if offset != mibIPInterfaceRowSupportsRouterDiscoveryOffset { + t.Errorf("MibIPInterfaceRow.SupportsRouterDiscovery offset is %d although %d is expected", offset, mibIPInterfaceRowSupportsRouterDiscoveryOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ReachableTime)) - sp + if offset != mibIPInterfaceRowReachableTimeOffset { + t.Errorf("MibIPInterfaceRow.ReachableTime offset is %d although %d is expected", offset, mibIPInterfaceRowReachableTimeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.TransmitOffload)) - sp + if offset != mibIPInterfaceRowTransmitOffloadOffset { + t.Errorf("MibIPInterfaceRow.TransmitOffload offset is %d although %d is expected", offset, mibIPInterfaceRowTransmitOffloadOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ReceiveOffload)) - sp + if offset != mibIPInterfaceRowReceiveOffloadOffset { + t.Errorf("MibIPInterfaceRow.ReceiveOffload offset is %d although %d is expected", offset, mibIPInterfaceRowReceiveOffloadOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DisableDefaultRoutes)) - sp + if offset != mibIPInterfaceRowDisableDefaultRoutesOffset { + t.Errorf("MibIPInterfaceRow.DisableDefaultRoutes offset is %d although %d is expected", offset, mibIPInterfaceRowDisableDefaultRoutesOffset) + } +} + +func TestMibIPInterfaceTable(t *testing.T) { + s := mibIPInterfaceTable{} + sp := uintptr(unsafe.Pointer(&s)) + const actualmibIPInterfaceTableSize = unsafe.Sizeof(s) + + if actualmibIPInterfaceTableSize != mibIPInterfaceTableSize { + t.Errorf("Size of mibIPInterfaceTable is %d, although %d is expected.", actualmibIPInterfaceTableSize, mibIPInterfaceTableSize) + } + + offset := uintptr(unsafe.Pointer(&s.table)) - sp + if offset != mibIPInterfaceTableTableOffset { + t.Errorf("mibIPInterfaceTable.table offset is %d although %d is expected", offset, mibIPInterfaceTableTableOffset) + } +} + +func TestMibIfRow2(t *testing.T) { + s := MibIfRow2{} + sp := uintptr(unsafe.Pointer(&s)) + const actualMibIfRow2Size = unsafe.Sizeof(s) + + if actualMibIfRow2Size != mibIfRow2Size { + t.Errorf("Size of MibIfRow2 is %d, although %d is expected.", actualMibIfRow2Size, mibIfRow2Size) + } + + offset := uintptr(unsafe.Pointer(&s.InterfaceIndex)) - sp + if offset != mibIfRow2InterfaceIndexOffset { + t.Errorf("MibIfRow2.InterfaceIndex offset is %d although %d is expected", offset, mibIfRow2InterfaceIndexOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InterfaceGUID)) - sp + if offset != mibIfRow2InterfaceGUIDOffset { + t.Errorf("MibIfRow2.InterfaceGUID offset is %d although %d is expected", offset, mibIfRow2InterfaceGUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.alias)) - sp + if offset != mibIfRow2AliasOffset { + t.Errorf("MibIfRow2.alias offset is %d although %d is expected", offset, mibIfRow2AliasOffset) + } + + offset = uintptr(unsafe.Pointer(&s.description)) - sp + if offset != mibIfRow2DescriptionOffset { + t.Errorf("MibIfRow2.description offset is %d although %d is expected", offset, mibIfRow2DescriptionOffset) + } + + offset = uintptr(unsafe.Pointer(&s.physicalAddressLength)) - sp + if offset != mibIfRow2PhysicalAddressLengthOffset { + t.Errorf("MibIfRow2.physicalAddressLength offset is %d although %d is expected", offset, mibIfRow2PhysicalAddressLengthOffset) + } + + offset = uintptr(unsafe.Pointer(&s.physicalAddress)) - sp + if offset != mibIfRow2PhysicalAddressOffset { + t.Errorf("MibIfRow2.physicalAddress offset is %d although %d is expected", offset, mibIfRow2PhysicalAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.permanentPhysicalAddress)) - sp + if offset != mibIfRow2PermanentPhysicalAddressOffset { + t.Errorf("MibIfRow2.permanentPhysicalAddress offset is %d although %d is expected", offset, mibIfRow2PermanentPhysicalAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.MTU)) - sp + if offset != mibIfRow2MTUOffset { + t.Errorf("MibIfRow2.MTU offset is %d although %d is expected", offset, mibIfRow2MTUOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Type)) - sp + if offset != mibIfRow2TypeOffset { + t.Errorf("MibIfRow2.Type offset is %d although %d is expected", offset, mibIfRow2TypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.TunnelType)) - sp + if offset != mibIfRow2TunnelTypeOffset { + t.Errorf("MibIfRow2.TunnelType offset is %d although %d is expected", offset, mibIfRow2TunnelTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.MediaType)) - sp + if offset != mibIfRow2MediaTypeOffset { + t.Errorf("MibIfRow2.MediaType offset is %d although %d is expected", offset, mibIfRow2MediaTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.PhysicalMediumType)) - sp + if offset != mibIfRow2PhysicalMediumTypeOffset { + t.Errorf("MibIfRow2.PhysicalMediumType offset is %d although %d is expected", offset, mibIfRow2PhysicalMediumTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.AccessType)) - sp + if offset != mibIfRow2AccessTypeOffset { + t.Errorf("MibIfRow2.AccessType offset is %d although %d is expected", offset, mibIfRow2AccessTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DirectionType)) - sp + if offset != mibIfRow2DirectionTypeOffset { + t.Errorf("MibIfRow2.DirectionType offset is %d although %d is expected", offset, mibIfRow2DirectionTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InterfaceAndOperStatusFlags)) - sp + if offset != mibIfRow2InterfaceAndOperStatusFlagsOffset { + t.Errorf("MibIfRow2.InterfaceAndOperStatusFlags offset is %d although %d is expected", offset, mibIfRow2InterfaceAndOperStatusFlagsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OperStatus)) - sp + if offset != mibIfRow2OperStatusOffset { + t.Errorf("MibIfRow2.OperStatus offset is %d although %d is expected", offset, mibIfRow2OperStatusOffset) + } + + offset = uintptr(unsafe.Pointer(&s.AdminStatus)) - sp + if offset != mibIfRow2AdminStatusOffset { + t.Errorf("MibIfRow2.AdminStatus offset is %d although %d is expected", offset, mibIfRow2AdminStatusOffset) + } + + offset = uintptr(unsafe.Pointer(&s.MediaConnectState)) - sp + if offset != mibIfRow2MediaConnectStateOffset { + t.Errorf("MibIfRow2.MediaConnectState offset is %d although %d is expected", offset, mibIfRow2MediaConnectStateOffset) + } + + offset = uintptr(unsafe.Pointer(&s.NetworkGUID)) - sp + if offset != mibIfRow2NetworkGUIDOffset { + t.Errorf("MibIfRow2.NetworkGUID offset is %d although %d is expected", offset, mibIfRow2NetworkGUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ConnectionType)) - sp + if offset != mibIfRow2ConnectionTypeOffset { + t.Errorf("MibIfRow2.ConnectionType offset is %d although %d is expected", offset, mibIfRow2ConnectionTypeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.TransmitLinkSpeed)) - sp + if offset != mibIfRow2TransmitLinkSpeedOffset { + t.Errorf("MibIfRow2.TransmitLinkSpeed offset is %d although %d is expected", offset, mibIfRow2TransmitLinkSpeedOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ReceiveLinkSpeed)) - sp + if offset != mibIfRow2ReceiveLinkSpeedOffset { + t.Errorf("MibIfRow2.ReceiveLinkSpeed offset is %d although %d is expected", offset, mibIfRow2ReceiveLinkSpeedOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InOctets)) - sp + if offset != mibIfRow2InOctetsOffset { + t.Errorf("MibIfRow2.InOctets offset is %d although %d is expected", offset, mibIfRow2InOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InUcastPkts)) - sp + if offset != mibIfRow2InUcastPktsOffset { + t.Errorf("MibIfRow2.InUcastPkts offset is %d although %d is expected", offset, mibIfRow2InUcastPktsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InNUcastPkts)) - sp + if offset != mibIfRow2InNUcastPktsOffset { + t.Errorf("MibIfRow2.InNUcastPkts offset is %d although %d is expected", offset, mibIfRow2InNUcastPktsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InDiscards)) - sp + if offset != mibIfRow2InDiscardsOffset { + t.Errorf("MibIfRow2.InDiscards offset is %d although %d is expected", offset, mibIfRow2InDiscardsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InErrors)) - sp + if offset != mibIfRow2InErrorsOffset { + t.Errorf("MibIfRow2.InErrors offset is %d although %d is expected", offset, mibIfRow2InErrorsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InUnknownProtos)) - sp + if offset != mibIfRow2InUnknownProtosOffset { + t.Errorf("MibIfRow2.InUnknownProtos offset is %d although %d is expected", offset, mibIfRow2InUnknownProtosOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InUcastOctets)) - sp + if offset != mibIfRow2InUcastOctetsOffset { + t.Errorf("MibIfRow2.InUcastOctets offset is %d although %d is expected", offset, mibIfRow2InUcastOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InMulticastOctets)) - sp + if offset != mibIfRow2InMulticastOctetsOffset { + t.Errorf("MibIfRow2.InMulticastOctets offset is %d although %d is expected", offset, mibIfRow2InMulticastOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InBroadcastOctets)) - sp + if offset != mibIfRow2InBroadcastOctetsOffset { + t.Errorf("MibIfRow2.InBroadcastOctets offset is %d although %d is expected", offset, mibIfRow2InBroadcastOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutOctets)) - sp + if offset != mibIfRow2OutOctetsOffset { + t.Errorf("MibIfRow2.OutOctets offset is %d although %d is expected", offset, mibIfRow2OutOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutUcastPkts)) - sp + if offset != mibIfRow2OutUcastPktsOffset { + t.Errorf("MibIfRow2.OutUcastPkts offset is %d although %d is expected", offset, mibIfRow2OutUcastPktsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutNUcastPkts)) - sp + if offset != mibIfRow2OutNUcastPktsOffset { + t.Errorf("MibIfRow2.OutNUcastPkts offset is %d although %d is expected", offset, mibIfRow2OutNUcastPktsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutDiscards)) - sp + if offset != mibIfRow2OutDiscardsOffset { + t.Errorf("MibIfRow2.OutDiscards offset is %d although %d is expected", offset, mibIfRow2OutDiscardsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutErrors)) - sp + if offset != mibIfRow2OutErrorsOffset { + t.Errorf("MibIfRow2.OutErrors offset is %d although %d is expected", offset, mibIfRow2OutErrorsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutUcastOctets)) - sp + if offset != mibIfRow2OutUcastOctetsOffset { + t.Errorf("MibIfRow2.OutUcastOctets offset is %d although %d is expected", offset, mibIfRow2OutUcastOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutMulticastOctets)) - sp + if offset != mibIfRow2OutMulticastOctetsOffset { + t.Errorf("MibIfRow2.OutMulticastOctets offset is %d although %d is expected", offset, mibIfRow2OutMulticastOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutBroadcastOctets)) - sp + if offset != mibIfRow2OutBroadcastOctetsOffset { + t.Errorf("MibIfRow2.OutBroadcastOctets offset is %d although %d is expected", offset, mibIfRow2OutBroadcastOctetsOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OutQLen)) - sp + if offset != mibIfRow2OutQLenOffset { + t.Errorf("MibIfRow2.OutQLen offset is %d although %d is expected", offset, mibIfRow2OutQLenOffset) + } +} + +func TestMibIfTable2(t *testing.T) { + s := mibIfTable2{} + sp := uintptr(unsafe.Pointer(&s)) + const actualmibIfTable2Size = unsafe.Sizeof(s) + + if actualmibIfTable2Size != mibIfTable2Size { + t.Errorf("Size of mibIfTable2 is %d, although %d is expected.", actualmibIfTable2Size, mibIfTable2Size) + } + + offset := uintptr(unsafe.Pointer(&s.table)) - sp + if offset != mibIfTable2TableOffset { + t.Errorf("mibIfTable2.table offset is %d although %d is expected", offset, mibIfTable2TableOffset) + } +} + +func TestRawSockaddrInet(t *testing.T) { + s := RawSockaddrInet{} + sp := uintptr(unsafe.Pointer(&s)) + const actualRawSockaddrInetSize = unsafe.Sizeof(s) + + if actualRawSockaddrInetSize != rawSockaddrInetSize { + t.Errorf("Size of RawSockaddrInet is %d, although %d is expected.", actualRawSockaddrInetSize, rawSockaddrInetSize) + } + + offset := uintptr(unsafe.Pointer(&s.data)) - sp + if offset != rawSockaddrInetDataOffset { + t.Errorf("RawSockaddrInet.data offset is %d although %d is expected", offset, rawSockaddrInetDataOffset) + } +} + +func TestMibUnicastIPAddressRow(t *testing.T) { + s := MibUnicastIPAddressRow{} + sp := uintptr(unsafe.Pointer(&s)) + const actualMibUnicastIPAddressRowSize = unsafe.Sizeof(s) + + if actualMibUnicastIPAddressRowSize != mibUnicastIPAddressRowSize { + t.Errorf("Size of MibUnicastIPAddressRow is %d, although %d is expected.", actualMibUnicastIPAddressRowSize, mibUnicastIPAddressRowSize) + } + + offset := uintptr(unsafe.Pointer(&s.InterfaceLUID)) - sp + if offset != mibUnicastIPAddressRowInterfaceLUIDOffset { + t.Errorf("MibUnicastIPAddressRow.InterfaceLUID offset is %d although %d is expected", offset, mibUnicastIPAddressRowInterfaceLUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InterfaceIndex)) - sp + if offset != mibUnicastIPAddressRowInterfaceIndexOffset { + t.Errorf("MibUnicastIPAddressRow.InterfaceIndex offset is %d although %d is expected", offset, mibUnicastIPAddressRowInterfaceIndexOffset) + } + + offset = uintptr(unsafe.Pointer(&s.PrefixOrigin)) - sp + if offset != mibUnicastIPAddressRowPrefixOriginOffset { + t.Errorf("MibUnicastIPAddressRow.PrefixOrigin offset is %d although %d is expected", offset, mibUnicastIPAddressRowPrefixOriginOffset) + } + + offset = uintptr(unsafe.Pointer(&s.SuffixOrigin)) - sp + if offset != mibUnicastIPAddressRowSuffixOriginOffset { + t.Errorf("MibUnicastIPAddressRow.SuffixOrigin offset is %d although %d is expected", offset, mibUnicastIPAddressRowSuffixOriginOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ValidLifetime)) - sp + if offset != mibUnicastIPAddressRowValidLifetimeOffset { + t.Errorf("MibUnicastIPAddressRow.ValidLifetime offset is %d although %d is expected", offset, mibUnicastIPAddressRowValidLifetimeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.PreferredLifetime)) - sp + if offset != mibUnicastIPAddressRowPreferredLifetimeOffset { + t.Errorf("MibUnicastIPAddressRow.PreferredLifetime offset is %d although %d is expected", offset, mibUnicastIPAddressRowPreferredLifetimeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.OnLinkPrefixLength)) - sp + if offset != mibUnicastIPAddressRowOnLinkPrefixLengthOffset { + t.Errorf("MibUnicastIPAddressRow.OnLinkPrefixLength offset is %d although %d is expected", offset, mibUnicastIPAddressRowOnLinkPrefixLengthOffset) + } + + offset = uintptr(unsafe.Pointer(&s.SkipAsSource)) - sp + if offset != mibUnicastIPAddressRowSkipAsSourceOffset { + t.Errorf("MibUnicastIPAddressRow.SkipAsSource offset is %d although %d is expected", offset, mibUnicastIPAddressRowSkipAsSourceOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DadState)) - sp + if offset != mibUnicastIPAddressRowDadStateOffset { + t.Errorf("MibUnicastIPAddressRow.DadState offset is %d although %d is expected", offset, mibUnicastIPAddressRowDadStateOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ScopeID)) - sp + if offset != mibUnicastIPAddressRowScopeIDOffset { + t.Errorf("MibUnicastIPAddressRow.ScopeID offset is %d although %d is expected", offset, mibUnicastIPAddressRowScopeIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.CreationTimeStamp)) - sp + if offset != mibUnicastIPAddressRowCreationTimeStampOffset { + t.Errorf("MibUnicastIPAddressRow.CreationTimeStamp offset is %d although %d is expected", offset, mibUnicastIPAddressRowCreationTimeStampOffset) + } +} + +func TestMibUnicastIPAddressTable(t *testing.T) { + s := mibUnicastIPAddressTable{} + sp := uintptr(unsafe.Pointer(&s)) + const actualmibUnicastIPAddressTableSize = unsafe.Sizeof(s) + + if actualmibUnicastIPAddressTableSize != mibUnicastIPAddressTableSize { + t.Errorf("Size of mibUnicastIPAddressTable is %d, although %d is expected.", actualmibUnicastIPAddressTableSize, mibUnicastIPAddressTableSize) + } + + offset := uintptr(unsafe.Pointer(&s.table)) - sp + if offset != mibUnicastIPAddressTableTableOffset { + t.Errorf("mibUnicastIPAddressTable.table offset is %d although %d is expected", offset, mibUnicastIPAddressTableTableOffset) + } +} + +func TestMibAnycastIPAddressRow(t *testing.T) { + s := MibAnycastIPAddressRow{} + sp := uintptr(unsafe.Pointer(&s)) + const actualMibAnycastIPAddressRowSize = unsafe.Sizeof(s) + + if actualMibAnycastIPAddressRowSize != mibAnycastIPAddressRowSize { + t.Errorf("Size of MibAnycastIPAddressRow is %d, although %d is expected.", actualMibAnycastIPAddressRowSize, mibAnycastIPAddressRowSize) + } + + offset := uintptr(unsafe.Pointer(&s.InterfaceLUID)) - sp + if offset != mibAnycastIPAddressRowInterfaceLUIDOffset { + t.Errorf("MibAnycastIPAddressRow.InterfaceLUID offset is %d although %d is expected", offset, mibAnycastIPAddressRowInterfaceLUIDOffset) + } + + offset = uintptr(unsafe.Pointer(&s.InterfaceIndex)) - sp + if offset != mibAnycastIPAddressRowInterfaceIndexOffset { + t.Errorf("MibAnycastIPAddressRow.InterfaceIndex offset is %d although %d is expected", offset, mibAnycastIPAddressRowInterfaceIndexOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ScopeID)) - sp + if offset != mibAnycastIPAddressRowScopeIDOffset { + t.Errorf("MibAnycastIPAddressRow.ScopeID offset is %d although %d is expected", offset, mibAnycastIPAddressRowScopeIDOffset) + } +} + +func TestMibAnycastIPAddressTable(t *testing.T) { + s := mibAnycastIPAddressTable{} + sp := uintptr(unsafe.Pointer(&s)) + const actualmibAnycastIPAddressTableSize = unsafe.Sizeof(s) + + if actualmibAnycastIPAddressTableSize != mibAnycastIPAddressTableSize { + t.Errorf("Size of mibAnycastIPAddressTable is %d, although %d is expected.", actualmibAnycastIPAddressTableSize, mibAnycastIPAddressTableSize) + } + + offset := uintptr(unsafe.Pointer(&s.table)) - sp + if offset != mibAnycastIPAddressTableTableOffset { + t.Errorf("mibAnycastIPAddressTable.table offset is %d although %d is expected", offset, mibAnycastIPAddressTableTableOffset) + } +} + +func TestIPAddressPrefix(t *testing.T) { + s := IPAddressPrefix{} + sp := uintptr(unsafe.Pointer(&s)) + const actualIPAddressPrefixSize = unsafe.Sizeof(s) + + if actualIPAddressPrefixSize != ipAddressPrefixSize { + t.Errorf("Size of IPAddressPrefix is %d, although %d is expected.", actualIPAddressPrefixSize, ipAddressPrefixSize) + } + + offset := uintptr(unsafe.Pointer(&s.PrefixLength)) - sp + if offset != ipAddressPrefixPrefixLengthOffset { + t.Errorf("IPAddressPrefix.PrefixLength offset is %d although %d is expected", offset, ipAddressPrefixPrefixLengthOffset) + + } +} + +func TestMibIPforwardRow2(t *testing.T) { + s := MibIPforwardRow2{} + sp := uintptr(unsafe.Pointer(&s)) + const actualMibIPforwardRow2Size = unsafe.Sizeof(s) + + if actualMibIPforwardRow2Size != mibIPforwardRow2Size { + t.Errorf("Size of MibIPforwardRow2 is %d, although %d is expected.", actualMibIPforwardRow2Size, mibIPforwardRow2Size) + } + + offset := uintptr(unsafe.Pointer(&s.InterfaceIndex)) - sp + if offset != mibIPforwardRow2InterfaceIndexOffset { + t.Errorf("MibIPforwardRow2.InterfaceIndex offset is %d although %d is expected", offset, mibIPforwardRow2InterfaceIndexOffset) + } + + offset = uintptr(unsafe.Pointer(&s.DestinationPrefix)) - sp + if offset != mibIPforwardRow2DestinationPrefixOffset { + t.Errorf("MibIPforwardRow2.DestinationPrefix offset is %d although %d is expected", offset, mibIPforwardRow2DestinationPrefixOffset) + } + + offset = uintptr(unsafe.Pointer(&s.NextHop)) - sp + if offset != mibIPforwardRow2NextHopOffset { + t.Errorf("MibIPforwardRow2.NextHop offset is %d although %d is expected", offset, mibIPforwardRow2NextHopOffset) + } + + offset = uintptr(unsafe.Pointer(&s.SitePrefixLength)) - sp + if offset != mibIPforwardRow2SitePrefixLengthOffset { + t.Errorf("MibIPforwardRow2.SitePrefixLength offset is %d although %d is expected", offset, mibIPforwardRow2SitePrefixLengthOffset) + } + + offset = uintptr(unsafe.Pointer(&s.ValidLifetime)) - sp + if offset != mibIPforwardRow2ValidLifetimeOffset { + t.Errorf("MibIPforwardRow2.ValidLifetime offset is %d although %d is expected", offset, mibIPforwardRow2ValidLifetimeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.PreferredLifetime)) - sp + if offset != mibIPforwardRow2PreferredLifetimeOffset { + t.Errorf("MibIPforwardRow2.PreferredLifetime offset is %d although %d is expected", offset, mibIPforwardRow2PreferredLifetimeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Metric)) - sp + if offset != mibIPforwardRow2MetricOffset { + t.Errorf("MibIPforwardRow2.Metric offset is %d although %d is expected", offset, mibIPforwardRow2MetricOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Protocol)) - sp + if offset != mibIPforwardRow2ProtocolOffset { + t.Errorf("MibIPforwardRow2.Protocol offset is %d although %d is expected", offset, mibIPforwardRow2ProtocolOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Loopback)) - sp + if offset != mibIPforwardRow2LoopbackOffset { + t.Errorf("MibIPforwardRow2.Loopback offset is %d although %d is expected", offset, mibIPforwardRow2LoopbackOffset) + } + + offset = uintptr(unsafe.Pointer(&s.AutoconfigureAddress)) - sp + if offset != mibIPforwardRow2AutoconfigureAddressOffset { + t.Errorf("MibIPforwardRow2.AutoconfigureAddress offset is %d although %d is expected", offset, mibIPforwardRow2AutoconfigureAddressOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Publish)) - sp + if offset != mibIPforwardRow2PublishOffset { + t.Errorf("MibIPforwardRow2.Publish offset is %d although %d is expected", offset, mibIPforwardRow2PublishOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Immortal)) - sp + if offset != mibIPforwardRow2ImmortalOffset { + t.Errorf("MibIPforwardRow2.Immortal offset is %d although %d is expected", offset, mibIPforwardRow2ImmortalOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Age)) - sp + if offset != mibIPforwardRow2AgeOffset { + t.Errorf("MibIPforwardRow2.Age offset is %d although %d is expected", offset, mibIPforwardRow2AgeOffset) + } + + offset = uintptr(unsafe.Pointer(&s.Origin)) - sp + if offset != mibIPforwardRow2OriginOffset { + t.Errorf("MibIPforwardRow2.Origin offset is %d although %d is expected", offset, mibIPforwardRow2OriginOffset) + } +} + +func TestMibIPforwardTable2(t *testing.T) { + s := mibIPforwardTable2{} + sp := uintptr(unsafe.Pointer(&s)) + const actualmibIPforwardTable2Size = unsafe.Sizeof(s) + + if actualmibIPforwardTable2Size != mibIPforwardTable2Size { + t.Errorf("Size of mibIPforwardTable2 is %d, although %d is expected.", actualmibIPforwardTable2Size, mibIPforwardTable2Size) + } + + offset := uintptr(unsafe.Pointer(&s.table)) - sp + if offset != mibIPforwardTable2TableOffset { + t.Errorf("mibIPforwardTable2.table offset is %d although %d is expected", offset, mibIPforwardTable2TableOffset) + } +} diff --git a/tunnel/winipcfg/types_test_386.go b/tunnel/winipcfg/types_test_386.go new file mode 100644 index 00000000..db5f5f86 --- /dev/null +++ b/tunnel/winipcfg/types_test_386.go @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +const ( + ipAdapterWINSServerAddressSize = 24 + ipAdapterWINSServerAddressNextOffset = 8 + ipAdapterWINSServerAddressAddressOffset = 12 + + ipAdapterGatewayAddressSize = 24 + ipAdapterGatewayAddressNextOffset = 8 + ipAdapterGatewayAddressAddressOffset = 12 + + ipAdapterDNSSuffixSize = 516 + ipAdapterDNSSuffixStringOffset = 4 + + ipAdapterAddressesSize = 376 + ipAdapterAddressesIfIndexOffset = 4 + ipAdapterAddressesNextOffset = 8 + ipAdapterAddressesAdapterNameOffset = 12 + ipAdapterAddressesFirstUnicastAddressOffset = 16 + ipAdapterAddressesFirstAnycastAddressOffset = 20 + ipAdapterAddressesFirstMulticastAddressOffset = 24 + ipAdapterAddressesFirstDNSServerAddressOffset = 28 + ipAdapterAddressesDNSSuffixOffset = 32 + ipAdapterAddressesDescriptionOffset = 36 + ipAdapterAddressesFriendlyNameOffset = 40 + ipAdapterAddressesPhysicalAddressOffset = 44 + ipAdapterAddressesPhysicalAddressLengthOffset = 52 + ipAdapterAddressesFlagsOffset = 56 + ipAdapterAddressesMTUOffset = 60 + ipAdapterAddressesIfTypeOffset = 64 + ipAdapterAddressesOperStatusOffset = 68 + ipAdapterAddressesIPv6IfIndexOffset = 72 + ipAdapterAddressesZoneIndicesOffset = 76 + ipAdapterAddressesFirstPrefixOffset = 140 + ipAdapterAddressesTransmitLinkSpeedOffset = 144 + ipAdapterAddressesReceiveLinkSpeedOffset = 152 + ipAdapterAddressesFirstWINSServerAddressOffset = 160 + ipAdapterAddressesFirstGatewayAddressOffset = 164 + ipAdapterAddressesIPv4MetricOffset = 168 + ipAdapterAddressesIPv6MetricOffset = 172 + ipAdapterAddressesLUIDOffset = 176 + ipAdapterAddressesDHCPv4ServerOffset = 184 + ipAdapterAddressesCompartmentIDOffset = 192 + ipAdapterAddressesNetworkGUIDOffset = 196 + ipAdapterAddressesConnectionTypeOffset = 212 + ipAdapterAddressesTunnelTypeOffset = 216 + ipAdapterAddressesDHCPv6ServerOffset = 220 + ipAdapterAddressesDHCPv6ClientDUIDOffset = 228 + ipAdapterAddressesDHCPv6ClientDUIDLengthOffset = 360 + ipAdapterAddressesDHCPv6IAIDOffset = 364 + ipAdapterAddressesFirstDNSSuffixOffset = 368 +) diff --git a/tunnel/winipcfg/types_test_amd64.go b/tunnel/winipcfg/types_test_amd64.go new file mode 100644 index 00000000..acc74118 --- /dev/null +++ b/tunnel/winipcfg/types_test_amd64.go @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +const ( + ipAdapterWINSServerAddressSize = 32 + ipAdapterWINSServerAddressNextOffset = 8 + ipAdapterWINSServerAddressAddressOffset = 16 + + ipAdapterGatewayAddressSize = 32 + ipAdapterGatewayAddressNextOffset = 8 + ipAdapterGatewayAddressAddressOffset = 16 + + ipAdapterDNSSuffixSize = 520 + ipAdapterDNSSuffixStringOffset = 8 + + ipAdapterAddressesSize = 448 + ipAdapterAddressesIfIndexOffset = 4 + ipAdapterAddressesNextOffset = 8 + ipAdapterAddressesAdapterNameOffset = 16 + ipAdapterAddressesFirstUnicastAddressOffset = 24 + ipAdapterAddressesFirstAnycastAddressOffset = 32 + ipAdapterAddressesFirstMulticastAddressOffset = 40 + ipAdapterAddressesFirstDNSServerAddressOffset = 48 + ipAdapterAddressesDNSSuffixOffset = 56 + ipAdapterAddressesDescriptionOffset = 64 + ipAdapterAddressesFriendlyNameOffset = 72 + ipAdapterAddressesPhysicalAddressOffset = 80 + ipAdapterAddressesPhysicalAddressLengthOffset = 88 + ipAdapterAddressesFlagsOffset = 92 + ipAdapterAddressesMTUOffset = 96 + ipAdapterAddressesIfTypeOffset = 100 + ipAdapterAddressesOperStatusOffset = 104 + ipAdapterAddressesIPv6IfIndexOffset = 108 + ipAdapterAddressesZoneIndicesOffset = 112 + ipAdapterAddressesFirstPrefixOffset = 176 + ipAdapterAddressesTransmitLinkSpeedOffset = 184 + ipAdapterAddressesReceiveLinkSpeedOffset = 192 + ipAdapterAddressesFirstWINSServerAddressOffset = 200 + ipAdapterAddressesFirstGatewayAddressOffset = 208 + ipAdapterAddressesIPv4MetricOffset = 216 + ipAdapterAddressesIPv6MetricOffset = 220 + ipAdapterAddressesLUIDOffset = 224 + ipAdapterAddressesDHCPv4ServerOffset = 232 + ipAdapterAddressesCompartmentIDOffset = 248 + ipAdapterAddressesNetworkGUIDOffset = 252 + ipAdapterAddressesConnectionTypeOffset = 268 + ipAdapterAddressesTunnelTypeOffset = 272 + ipAdapterAddressesDHCPv6ServerOffset = 280 + ipAdapterAddressesDHCPv6ClientDUIDOffset = 296 + ipAdapterAddressesDHCPv6ClientDUIDLengthOffset = 428 + ipAdapterAddressesDHCPv6IAIDOffset = 432 + ipAdapterAddressesFirstDNSSuffixOffset = 440 +) diff --git a/tunnel/winipcfg/unicast_address_change_handler.go b/tunnel/winipcfg/unicast_address_change_handler.go new file mode 100644 index 00000000..b0ae7950 --- /dev/null +++ b/tunnel/winipcfg/unicast_address_change_handler.go @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "sync" + + "golang.org/x/sys/windows" +) + +// UnicastAddressChangeCallback structure allows unicast address change callback handling. +type UnicastAddressChangeCallback struct { + cb func(notificationType MibNotificationType, addr *MibUnicastIPAddressRow) +} + +var ( + unicastAddressChangeMutex = sync.Mutex{} + unicastAddressChangeCallbacks = make(map[*UnicastAddressChangeCallback]bool) + unicastAddressChangeHandle = windows.Handle(0) +) + +// RegisterUnicastAddressChangeCallback registers a new UnicastAddressChangeCallback. If this particular callback is already +// registered, the function will silently return. Returned UnicastAddressChangeCallback.Unregister method should be used +// to unregister. +func RegisterUnicastAddressChangeCallback(callback func(notificationType MibNotificationType, addr *MibUnicastIPAddressRow)) (*UnicastAddressChangeCallback, error) { + cb := &UnicastAddressChangeCallback{callback} + + unicastAddressChangeMutex.Lock() + defer unicastAddressChangeMutex.Unlock() + + unicastAddressChangeCallbacks[cb] = true + + if unicastAddressChangeHandle == 0 { + err := notifyUnicastIPAddressChange(windows.AF_UNSPEC, windows.NewCallback(unicastAddressChanged), 0, false, &unicastAddressChangeHandle) + if err != nil { + delete(unicastAddressChangeCallbacks, cb) + unicastAddressChangeHandle = 0 + return nil, err + } + } + + return cb, nil +} + +// Unregister unregisters the callback. +func (callback *UnicastAddressChangeCallback) Unregister() error { + unicastAddressChangeMutex.Lock() + defer unicastAddressChangeMutex.Unlock() + + delete(unicastAddressChangeCallbacks, callback) + + if len(unicastAddressChangeCallbacks) < 1 && unicastAddressChangeHandle != 0 { + err := cancelMibChangeNotify2(unicastAddressChangeHandle) + if err != nil { + return err + } + unicastAddressChangeHandle = 0 + } + + return nil +} + +func unicastAddressChanged(callerContext uintptr, row *MibUnicastIPAddressRow, notificationType MibNotificationType) uintptr { + unicastAddressChangeMutex.Lock() + for cb := range unicastAddressChangeCallbacks { + cb.cb(notificationType, row) + } + unicastAddressChangeMutex.Unlock() + return 0 +} diff --git a/tunnel/winipcfg/utils.go b/tunnel/winipcfg/utils.go new file mode 100644 index 00000000..c841c40c --- /dev/null +++ b/tunnel/winipcfg/utils.go @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "net" + "unsafe" + + "golang.org/x/sys/windows" +) + +// SocketAddressToIP function returns IPv4 or IPv6 address from windows.SocketAddress. +// If the address is neither IPv4 not IPv6 nil is returned. +//TODO: Remove once https://go-review.googlesource.com/c/sys/+/178577 is merged. +func SocketAddressToIP(addr *windows.SocketAddress) net.IP { + if uintptr(addr.SockaddrLength) >= unsafe.Sizeof(windows.RawSockaddrInet4{}) && addr.Sockaddr.Addr.Family == windows.AF_INET { + return (*windows.RawSockaddrInet4)(unsafe.Pointer(addr.Sockaddr)).Addr[:] + } else if uintptr(addr.SockaddrLength) >= unsafe.Sizeof(windows.RawSockaddrInet6{}) && addr.Sockaddr.Addr.Family == windows.AF_INET6 { + return (*windows.RawSockaddrInet6)(unsafe.Pointer(addr.Sockaddr)).Addr[:] + } else { + return nil + } +} diff --git a/tunnel/winipcfg/winipcfg.go b/tunnel/winipcfg/winipcfg.go new file mode 100644 index 00000000..bc878606 --- /dev/null +++ b/tunnel/winipcfg/winipcfg.go @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +// +// Common functions +// + +//sys freeMibTable(memory unsafe.Pointer) = iphlpapi.FreeMibTable + +// +// Interface-related functions +// + +//sys getAdaptersAddresses(family uint32, flags GAAFlags, reserved uintptr, adapterAddresses *IPAdapterAddresses, sizePointer *uint32) (ret error) = iphlpapi.GetAdaptersAddresses +//sys initializeIPInterfaceEntry(row *MibIPInterfaceRow) = iphlpapi.InitializeIpInterfaceEntry +//sys getIPInterfaceTable(family AddressFamily, table **mibIPInterfaceTable) (ret error) = iphlpapi.GetIpInterfaceTable +//sys getIPInterfaceEntry(row *MibIPInterfaceRow) (ret error) = iphlpapi.GetIpInterfaceEntry +//sys setIPInterfaceEntry(row *MibIPInterfaceRow) (ret error) = iphlpapi.SetIpInterfaceEntry +//sys getIfEntry2(row *MibIfRow2) (ret error) = iphlpapi.GetIfEntry2 +//sys getIfTable2Ex(level MibIfEntryLevel, table **mibIfTable2) (ret error) = iphlpapi.GetIfTable2Ex +//sys convertInterfaceLUIDToGUID(interfaceLUID *LUID, interfaceGUID *windows.GUID) (ret error) = iphlpapi.ConvertInterfaceLuidToGuid +//sys convertInterfaceGUIDToLUID(interfaceGUID *windows.GUID, interfaceLUID *LUID) (ret error) = iphlpapi.ConvertInterfaceGuidToLuid + +// GetAdaptersAddresses function retrieves the addresses associated with the adapters on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getadaptersaddresses +func GetAdaptersAddresses(family uint32, flags GAAFlags) ([]*IPAdapterAddresses, error) { + var b []byte + size := uint32(15000) + + for { + b = make([]byte, size) + err := getAdaptersAddresses(family, flags, 0, (*IPAdapterAddresses)(unsafe.Pointer(&b[0])), &size) + if err == nil { + break + } + if err != windows.ERROR_BUFFER_OVERFLOW || size <= uint32(len(b)) { + return nil, err + } + } + + result := make([]*IPAdapterAddresses, 0, uintptr(size)/unsafe.Sizeof(IPAdapterAddresses{})) + for wtiaa := (*IPAdapterAddresses)(unsafe.Pointer(&b[0])); wtiaa != nil; wtiaa = wtiaa.Next { + result = append(result, wtiaa) + } + + return result, nil +} + +// GetIPInterfaceTable function retrieves the IP interface entries on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipinterfacetable +func GetIPInterfaceTable(family AddressFamily) ([]MibIPInterfaceRow, error) { + var tab *mibIPInterfaceTable + err := getIPInterfaceTable(family, &tab) + if err != nil { + return nil, err + } + t := append(make([]MibIPInterfaceRow, 0, tab.numEntries), tab.get()...) + tab.free() + return t, nil +} + +// GetIfTable2Ex function retrieves the MIB-II interface table. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getiftable2ex +func GetIfTable2Ex(level MibIfEntryLevel) ([]MibIfRow2, error) { + var tab *mibIfTable2 + err := getIfTable2Ex(level, &tab) + if err != nil { + return nil, err + } + t := append(make([]MibIfRow2, 0, tab.numEntries), tab.get()...) + tab.free() + return t, nil +} + +// +// Unicast IP address-related functions +// + +//sys getUnicastIPAddressTable(family AddressFamily, table **mibUnicastIPAddressTable) (ret error) = iphlpapi.GetUnicastIpAddressTable +//sys initializeUnicastIPAddressEntry(row *MibUnicastIPAddressRow) = iphlpapi.InitializeUnicastIpAddressEntry +//sys getUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.GetUnicastIpAddressEntry +//sys setUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.SetUnicastIpAddressEntry +//sys createUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.CreateUnicastIpAddressEntry +//sys deleteUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.DeleteUnicastIpAddressEntry + +// GetUnicastIPAddressTable function retrieves the unicast IP address table on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getunicastipaddresstable +func GetUnicastIPAddressTable(family AddressFamily) ([]MibUnicastIPAddressRow, error) { + var tab *mibUnicastIPAddressTable + err := getUnicastIPAddressTable(family, &tab) + if err != nil { + return nil, err + } + t := append(make([]MibUnicastIPAddressRow, 0, tab.numEntries), tab.get()...) + tab.free() + return t, nil +} + +// +// Anycast IP address-related functions +// + +//sys getAnycastIPAddressTable(family AddressFamily, table **mibAnycastIPAddressTable) (ret error) = iphlpapi.GetAnycastIpAddressTable +//sys getAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) = iphlpapi.GetAnycastIpAddressEntry +//sys createAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) = iphlpapi.CreateAnycastIpAddressEntry +//sys deleteAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) = iphlpapi.DeleteAnycastIpAddressEntry + +// GetAnycastIPAddressTable function retrieves the anycast IP address table on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getanycastipaddresstable +func GetAnycastIPAddressTable(family AddressFamily) ([]MibAnycastIPAddressRow, error) { + var tab *mibAnycastIPAddressTable + err := getAnycastIPAddressTable(family, &tab) + if err != nil { + return nil, err + } + t := append(make([]MibAnycastIPAddressRow, 0, tab.numEntries), tab.get()...) + tab.free() + return t, nil +} + +// +// Routing-related functions +// + +//sys getIPForwardTable2(family AddressFamily, table **mibIPforwardTable2) (ret error) = iphlpapi.GetIpForwardTable2 +//sys initializeIPForwardEntry(route *MibIPforwardRow2) = iphlpapi.InitializeIpForwardEntry +//sys getIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.GetIpForwardEntry2 +//sys setIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.SetIpForwardEntry2 +//sys createIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.CreateIpForwardEntry2 +//sys deleteIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.DeleteIpForwardEntry2 + +// GetIPForwardTable2 function retrieves the IP route entries on the local computer. +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipforwardtable2 +func GetIPForwardTable2(family AddressFamily) ([]MibIPforwardRow2, error) { + var tab *mibIPforwardTable2 + err := getIPForwardTable2(family, &tab) + if err != nil { + return nil, err + } + t := append(make([]MibIPforwardRow2, 0, tab.numEntries), tab.get()...) + tab.free() + return t, nil +} + +// +// Notifications-related functions +// + +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-notifyipinterfacechange +//sys notifyIPInterfaceChange(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) = iphlpapi.NotifyIpInterfaceChange + +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-notifyunicastipaddresschange +//sys notifyUnicastIPAddressChange(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) = iphlpapi.NotifyUnicastIpAddressChange + +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-notifyroutechange2 +//sys notifyRouteChange2(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) = iphlpapi.NotifyRouteChange2 + +// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-cancelmibchangenotify2 +//sys cancelMibChangeNotify2(notificationHandle windows.Handle) (ret error) = iphlpapi.CancelMibChangeNotify2 diff --git a/tunnel/winipcfg/winipcfg_test.go b/tunnel/winipcfg/winipcfg_test.go new file mode 100644 index 00000000..9da9f4c0 --- /dev/null +++ b/tunnel/winipcfg/winipcfg_test.go @@ -0,0 +1,705 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package winipcfg + +import ( + "bytes" + "net" + "strings" + "testing" + "time" + "unsafe" + + "golang.org/x/sys/windows" +) + +const ( + testInterfaceMarker = "winipcfg_test" // The interface we will use for testing must contain this string in its name +) + +// TODO: Add IPv6 tests. +var ( + unexistentIPAddresToAdd = net.IPNet{ + IP: net.IP{172, 16, 1, 114}, + Mask: net.IPMask{255, 255, 255, 0}, + } + unexistentRouteIPv4ToAdd = RouteData{ + Destination: net.IPNet{ + IP: net.IP{172, 16, 200, 0}, + Mask: net.IPMask{255, 255, 255, 0}, + }, + NextHop: net.IP{172, 16, 1, 2}, + Metric: 0, + } + dnsesToSet = []net.IP{ + net.IPv4(8, 8, 8, 8), + net.IPv4(8, 8, 4, 4), + } +) + +func runningAsAdmin() bool { + process, err := windows.OpenCurrentProcessToken() + if err != nil { + return false + } + defer process.Close() + var isElevated uint32 + var outLen uint32 + err = windows.GetTokenInformation(process, windows.TokenElevation, (*byte)(unsafe.Pointer(&isElevated)), uint32(unsafe.Sizeof(isElevated)), &outLen) + if err != nil { + return false + } + return outLen == uint32(unsafe.Sizeof(isElevated)) && isElevated != 0 +} + +func getTestInterface() (*IPAdapterAddresses, error) { + ifcs, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagIncludeAll) + if err != nil { + return nil, err + } + + marker := strings.ToLower(testInterfaceMarker) + for _, ifc := range ifcs { + if strings.Index(strings.ToLower(ifc.FriendlyName()), marker) != -1 { + return ifc, nil + } + } + + return nil, windows.ERROR_NOT_FOUND +} + +func getTestIPInterface(family AddressFamily) (*MibIPInterfaceRow, error) { + ifc, err := getTestInterface() + if err != nil { + return nil, err + } + + return ifc.LUID.IPInterface(family) +} + +func TestAdaptersAddresses(t *testing.T) { + ifcs, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagIncludeAll) + if err != nil { + t.Errorf("GetAdaptersAddresses() returned error: %v", err) + } else if ifcs == nil { + t.Errorf("GetAdaptersAddresses() returned nil.") + } else if len(ifcs) == 0 { + t.Errorf("GetAdaptersAddresses() returned empty.") + } else { + for _, i := range ifcs { + i.AdapterName() + i.DNSSuffix() + i.Description() + i.FriendlyName() + i.PhysicalAddress() + i.DHCPv6ClientDUID() + for dnsSuffix := i.FirstDNSSuffix; dnsSuffix != nil; dnsSuffix = dnsSuffix.Next { + dnsSuffix.String() + } + } + } + + ifcs, err = GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault) + + for _, i := range ifcs { + ifc, err := i.LUID.Interface() + if err != nil { + t.Errorf("LUID.Interface() returned an error: %v", err) + continue + } else if ifc == nil { + t.Errorf("LUID.Interface() returned nil.") + continue + } + } + + for _, i := range ifcs { + guid, err := i.LUID.GUID() + if err != nil { + t.Errorf("LUID.GUID() returned an error: %v", err) + continue + } + if guid == nil { + t.Error("LUID.GUID() returned nil.") + continue + } + + luid, err := LUIDFromGUID(guid) + if err != nil { + t.Errorf("LUIDFromGUID() returned an error: %v", err) + continue + } + if luid != i.LUID { + t.Errorf("LUIDFromGUID() returned LUID %d, although expected was %d.", luid, i.LUID) + continue + } + } +} + +func TestIPInterface(t *testing.T) { + ifcs, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault) + if err != nil { + t.Errorf("GetAdaptersAddresses() returned error: %v", err) + } + + for _, i := range ifcs { + _, err := i.LUID.IPInterface(windows.AF_INET) + if err == windows.ERROR_NOT_FOUND { + // Ignore isatap and similar adapters without IPv4. + continue + } + if err != nil { + t.Errorf("LUID.IPInterface(%s) returned an error: %v", i.FriendlyName(), err) + } + + _, err = i.LUID.IPInterface(windows.AF_INET6) + if err != nil { + t.Errorf("LUID.IPInterface(%s) returned an error: %v", i.FriendlyName(), err) + } + } +} + +func TestIPInterfaces(t *testing.T) { + tab, err := GetIPInterfaceTable(windows.AF_UNSPEC) + if err != nil { + t.Errorf("GetIPInterfaceTable() returned an error: %v", err) + return + } else if tab == nil { + t.Error("GetIPInterfaceTable() returned nil.") + } + + if len(tab) == 0 { + t.Error("GetIPInterfaceTable() returned an empty slice.") + return + } +} + +func TestIPChangeMetric(t *testing.T) { + ipifc, err := getTestIPInterface(windows.AF_INET) + if err != nil { + t.Errorf("getTestIPInterface() returned an error: %v", err) + return + } + if !runningAsAdmin() { + t.Errorf("%s requires elevation", t.Name()) + return + } + + var changed bool + cb, err := RegisterInterfaceChangeCallback(func(notificationType MibNotificationType, iface *MibIPInterfaceRow) { + if iface == nil || iface.InterfaceLUID != ipifc.InterfaceLUID { + return + } + switch notificationType { + case MibParameterNotification: + changed = true + } + }) + if err != nil { + t.Errorf("RegisterInterfaceChangeCallback() returned error: %v", err) + return + } + defer func() { + err = cb.Unregister() + if err != nil { + t.Errorf("UnregisterInterfaceChangeCallback() returned error: %v", err) + } + }() + + useAutomaticMetric := ipifc.UseAutomaticMetric + metric := ipifc.Metric + + newMetric := uint32(100) + if newMetric == metric { + newMetric = 200 + } + + ipifc.UseAutomaticMetric = false + ipifc.Metric = newMetric + err = ipifc.Set() + if err != nil { + t.Errorf("MibIPInterfaceRow.Set() returned an error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + ipifc, err = getTestIPInterface(windows.AF_INET) + if err != nil { + t.Errorf("getTestIPInterface() returned an error: %v", err) + return + } + if ipifc.Metric != newMetric { + t.Errorf("Expected metric: %d; actual metric: %d", newMetric, ipifc.Metric) + } + if ipifc.UseAutomaticMetric { + t.Error("UseAutomaticMetric is true although it's set to false.") + } + if !changed { + t.Errorf("Notification handler has not been called on metric change.") + } + changed = false + + ipifc.UseAutomaticMetric = useAutomaticMetric + ipifc.Metric = metric + err = ipifc.Set() + if err != nil { + t.Errorf("MibIPInterfaceRow.Set() returned an error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + ipifc, err = getTestIPInterface(windows.AF_INET) + if err != nil { + t.Errorf("getTestIPInterface() returned an error: %v", err) + return + } + if ipifc.Metric != metric { + t.Errorf("Expected metric: %d; actual metric: %d", metric, ipifc.Metric) + } + if ipifc.UseAutomaticMetric != useAutomaticMetric { + t.Errorf("UseAutomaticMetric is %v although %v is expected.", ipifc.UseAutomaticMetric, useAutomaticMetric) + } + if !changed { + t.Errorf("Notification handler has not been called on metric change.") + } +} + +func TestIPChangeMTU(t *testing.T) { + ipifc, err := getTestIPInterface(windows.AF_INET) + if err != nil { + t.Errorf("getTestIPInterface() returned an error: %v", err) + return + } + if !runningAsAdmin() { + t.Errorf("%s requires elevation", t.Name()) + return + } + + prevMTU := ipifc.NLMTU + mtuToSet := prevMTU - 1 + ipifc.NLMTU = mtuToSet + err = ipifc.Set() + if err != nil { + t.Errorf("Interface.Set() returned error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + ipifc, err = getTestIPInterface(windows.AF_INET) + if err != nil { + t.Errorf("getTestIPInterface() returned an error: %v", err) + return + } + if ipifc.NLMTU != mtuToSet { + t.Errorf("Interface.NLMTU is %d although %d is expected.", ipifc.NLMTU, mtuToSet) + } + + ipifc.NLMTU = prevMTU + err = ipifc.Set() + if err != nil { + t.Errorf("Interface.Set() returned error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + ipifc, err = getTestIPInterface(windows.AF_INET) + if err != nil { + t.Errorf("getTestIPInterface() returned an error: %v", err) + } + if ipifc.NLMTU != prevMTU { + t.Errorf("Interface.NLMTU is %d although %d is expected.", ipifc.NLMTU, prevMTU) + } +} + +func TestGetIfRow(t *testing.T) { + ifc, err := getTestInterface() + if err != nil { + t.Errorf("getTestInterface() returned an error: %v", err) + return + } + + row, err := ifc.LUID.Interface() + if err != nil { + t.Errorf("LUID.Interface() returned an error: %v", err) + return + } + + row.Alias() + row.Description() + row.PhysicalAddress() + row.PermanentPhysicalAddress() +} + +func TestGetIfRows(t *testing.T) { + tab, err := GetIfTable2Ex(MibIfEntryNormal) + if err != nil { + t.Errorf("GetIfTable2Ex() returned an error: %v", err) + return + } else if tab == nil { + t.Errorf("GetIfTable2Ex() returned nil") + return + } + + for i := range tab { + tab[i].Alias() + tab[i].Description() + tab[i].PhysicalAddress() + tab[i].PermanentPhysicalAddress() + } +} + +func TestUnicastIPAddress(t *testing.T) { + _, err := GetUnicastIPAddressTable(windows.AF_UNSPEC) + if err != nil { + t.Errorf("GetUnicastAddresses() returned an error: %v", err) + return + } +} + +func TestAddDeleteIPAddress(t *testing.T) { + ifc, err := getTestInterface() + if err != nil { + t.Errorf("getTestInterface() returned an error: %v", err) + return + } + if !runningAsAdmin() { + t.Errorf("%s requires elevation", t.Name()) + return + } + + addr, err := ifc.LUID.IPAddress(unexistentIPAddresToAdd.IP) + if err == nil { + t.Errorf("Unicast address %s already exists. Please set unexistentIPAddresToAdd appropriately.", unexistentIPAddresToAdd.IP.String()) + return + } else if err != windows.ERROR_NOT_FOUND { + t.Errorf("LUID.IPAddress() returned an error: %v", err) + return + } + + var created, deleted bool + cb, err := RegisterUnicastAddressChangeCallback(func(notificationType MibNotificationType, addr *MibUnicastIPAddressRow) { + if addr == nil || addr.InterfaceLUID != ifc.LUID { + return + } + switch notificationType { + case MibAddInstance: + created = true + case MibDeleteInstance: + deleted = true + } + }) + if err != nil { + t.Errorf("RegisterUnicastAddressChangeCallback() returned an error: %v", err) + } else { + defer cb.Unregister() + } + var count int + for addr := ifc.FirstUnicastAddress; addr != nil; addr = addr.Next { + count-- + } + err = ifc.LUID.AddIPAddresses([]net.IPNet{unexistentIPAddresToAdd}) + if err != nil { + t.Errorf("LUID.AddIPAddresses() returned an error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + ifc, _ = getTestInterface() + for addr := ifc.FirstUnicastAddress; addr != nil; addr = addr.Next { + count++ + } + if count != 1 { + t.Errorf("After adding there are %d new interface(s).", count) + } + addr, err = ifc.LUID.IPAddress(unexistentIPAddresToAdd.IP) + if err != nil { + t.Errorf("LUID.IPAddress() returned an error: %v", err) + } else if addr == nil { + t.Errorf("Unicast address %s still doesn't exist, although it's added successfully.", unexistentIPAddresToAdd.IP.String()) + } + if !created { + t.Errorf("Notification handler has not been called on add.") + } + + err = ifc.LUID.DeleteIPAddress(unexistentIPAddresToAdd.IP) + if err != nil { + t.Errorf("LUID.DeleteIPAddress() returned an error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + addr, err = ifc.LUID.IPAddress(unexistentIPAddresToAdd.IP) + if err == nil { + t.Errorf("Unicast address %s still exists, although it's deleted successfully.", unexistentIPAddresToAdd.IP.String()) + } else if err != windows.ERROR_NOT_FOUND { + t.Errorf("LUID.IPAddress() returned an error: %v", err) + } + if !deleted { + t.Errorf("Notification handler has not been called on delete.") + } +} + +func TestGetRoutes(t *testing.T) { + _, err := GetIPForwardTable2(windows.AF_UNSPEC) + if err != nil { + t.Errorf("GetIPForwardTable2() returned error: %v", err) + } +} + +func TestAddDeleteRoute(t *testing.T) { + findRoute := func(luid LUID, dest net.IPNet) ([]MibIPforwardRow2, error) { + var family AddressFamily + switch { + case dest.IP.To4() != nil: + family = windows.AF_INET + case dest.IP.To16() != nil: + family = windows.AF_INET6 + default: + return nil, windows.ERROR_INVALID_PARAMETER + } + r, err := GetIPForwardTable2(family) + if err != nil { + return nil, err + } + matches := make([]MibIPforwardRow2, 0, len(r)) + ones, _ := dest.Mask.Size() + for _, route := range r { + if route.InterfaceLUID == luid && route.DestinationPrefix.PrefixLength == uint8(ones) && route.DestinationPrefix.Prefix.Family == family && route.DestinationPrefix.Prefix.IP().Equal(dest.IP) { + matches = append(matches, route) + } + } + return matches, nil + } + + ifc, err := getTestInterface() + if err != nil { + t.Errorf("getTestInterface() returned an error: %v", err) + return + } + if !runningAsAdmin() { + t.Errorf("%s requires elevation", t.Name()) + return + } + + _, err = ifc.LUID.Route(unexistentRouteIPv4ToAdd.Destination, unexistentRouteIPv4ToAdd.NextHop) + if err == nil { + t.Error("LUID.Route() returned a route although it isn't added yet. Have you forgot to set unexistentRouteIPv4ToAdd appropriately?") + return + } else if err != windows.ERROR_NOT_FOUND { + t.Errorf("LUID.Route() returned an error: %v", err) + return + } + + routes, err := findRoute(ifc.LUID, unexistentRouteIPv4ToAdd.Destination) + if err != nil { + t.Errorf("findRoute() returned an error: %v", err) + } else if len(routes) != 0 { + t.Errorf("findRoute() returned %d items although the route isn't added yet. Have you forgot to set unexistentRouteIPv4ToAdd appropriately?", len(routes)) + } + + var created, deleted bool + cb, err := RegisterRouteChangeCallback(func(notificationType MibNotificationType, route *MibIPforwardRow2) { + switch notificationType { + case MibAddInstance: + created = true + case MibDeleteInstance: + deleted = true + } + }) + if err != nil { + t.Errorf("RegisterRouteChangeCallback() returned an error: %v", err) + } else { + defer cb.Unregister() + } + err = ifc.LUID.AddRoute(unexistentRouteIPv4ToAdd.Destination, unexistentRouteIPv4ToAdd.NextHop, unexistentRouteIPv4ToAdd.Metric) + if err != nil { + t.Errorf("LUID.AddRoute() returned an error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + route, err := ifc.LUID.Route(unexistentRouteIPv4ToAdd.Destination, unexistentRouteIPv4ToAdd.NextHop) + if err == windows.ERROR_NOT_FOUND { + t.Error("LUID.Route() returned nil although the route is added successfully.") + } else if err != nil { + t.Errorf("LUID.Route() returned an error: %v", err) + } else if !route.DestinationPrefix.Prefix.IP().Equal(unexistentRouteIPv4ToAdd.Destination.IP) || !route.NextHop.IP().Equal(unexistentRouteIPv4ToAdd.NextHop) { + t.Error("LUID.Route() returned a wrong route!") + } + if !created { + t.Errorf("Route handler has not been called on add.") + } + + routes, err = findRoute(ifc.LUID, unexistentRouteIPv4ToAdd.Destination) + if err != nil { + t.Errorf("findRoute() returned an error: %v", err) + } else if len(routes) != 1 { + t.Errorf("findRoute() returned %d items although %d is expected.", len(routes), 1) + } else if !routes[0].DestinationPrefix.Prefix.IP().Equal(unexistentRouteIPv4ToAdd.Destination.IP) { + t.Errorf("findRoute() returned a wrong route. Dest: %s; expected: %s.", routes[0].DestinationPrefix.Prefix.IP().String(), unexistentRouteIPv4ToAdd.Destination.IP.String()) + } + + err = ifc.LUID.DeleteRoute(unexistentRouteIPv4ToAdd.Destination, unexistentRouteIPv4ToAdd.NextHop) + if err != nil { + t.Errorf("LUID.DeleteRoute() returned an error: %v", err) + } + + time.Sleep(500 * time.Millisecond) + + _, err = ifc.LUID.Route(unexistentRouteIPv4ToAdd.Destination, unexistentRouteIPv4ToAdd.NextHop) + if err == nil { + t.Error("LUID.Route() returned a route although it is removed successfully.") + } else if err != windows.ERROR_NOT_FOUND { + t.Errorf("LUID.Route() returned an error: %v", err) + } + if !deleted { + t.Errorf("Route handler has not been called on delete.") + } + + routes, err = findRoute(ifc.LUID, unexistentRouteIPv4ToAdd.Destination) + if err != nil { + t.Errorf("findRoute() returned an error: %v", err) + } else if len(routes) != 0 { + t.Errorf("findRoute() returned %d items although the route is deleted successfully.", len(routes)) + } +} + +func TestFlushDNS(t *testing.T) { + ifc, err := getTestInterface() + if err != nil { + t.Errorf("getTestInterface() returned an error: %v", err) + return + } + if !runningAsAdmin() { + t.Errorf("%s requires elevation", t.Name()) + return + } + + prevDNSes, err := ifc.LUID.DNS() + if err != nil { + t.Errorf("LUID.DNS() returned an error: %v", err) + } + + err = ifc.LUID.FlushDNS() + if err != nil { + t.Errorf("LUID.FlushDNS() returned an error: %v", err) + } + + ifc, _ = getTestInterface() + + n := 0 + dns, err := ifc.LUID.DNS() + if err != nil { + t.Errorf("LUID.DNS() returned an error: %v", err) + } + for _, a := range dns { + if len(a) != 16 || a.To4() != nil || !((a[15] == 1 || a[15] == 2 || a[15] == 3) && bytes.HasPrefix(a, []byte{0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})) { + n++ + } + } + if n != 0 { + t.Errorf("DNSServerAddresses contains %d items, although FlushDNS is executed successfully.", n) + } + + err = ifc.LUID.SetDNS(prevDNSes) + if err != nil { + t.Errorf("LUID.SetDNS() returned an error: %v.", err) + } +} + +func TestAddDNS(t *testing.T) { + ifc, err := getTestInterface() + if err != nil { + t.Errorf("getTestInterface() returned an error: %v", err) + return + } + if !runningAsAdmin() { + t.Errorf("%s requires elevation", t.Name()) + return + } + + prevDNSes, err := ifc.LUID.DNS() + if err != nil { + t.Errorf("LUID.DNS() returned an error: %v", err) + } + expectedDNSes := append(prevDNSes, dnsesToSet...) + + err = ifc.LUID.AddDNS(dnsesToSet) + if err != nil { + t.Errorf("LUID.AddDNS() returned an error: %v", err) + return + } + + ifc, _ = getTestInterface() + + newDNSes, err := ifc.LUID.DNS() + if err != nil { + t.Errorf("LUID.DNS() returned an error: %v", err) + } else if len(newDNSes) != len(expectedDNSes) { + t.Errorf("expectedDNSes contains %d items, while DNSServerAddresses contains %d.", len(expectedDNSes), len(newDNSes)) + } else { + for i := range expectedDNSes { + if !expectedDNSes[i].Equal(newDNSes[i]) { + t.Errorf("expectedDNSes[%d] = %s while DNSServerAddresses[%d] = %s.", i, expectedDNSes[i].String(), i, newDNSes[i].String()) + } + } + } + + err = ifc.LUID.SetDNS(prevDNSes) + if err != nil { + t.Errorf("LUID.SetDNS() returned an error: %v.", err) + } +} + +func TestSetDNS(t *testing.T) { + ifc, err := getTestInterface() + if err != nil { + t.Errorf("getTestInterface() returned an error: %v", err) + return + } + if !runningAsAdmin() { + t.Errorf("%s requires elevation", t.Name()) + return + } + + prevDNSes, err := ifc.LUID.DNS() + if err != nil { + t.Errorf("LUID.DNS() returned an error: %v", err) + } + + err = ifc.LUID.SetDNS(dnsesToSet) + if err != nil { + t.Errorf("LUID.SetDNS() returned an error: %v", err) + return + } + + ifc, _ = getTestInterface() + + newDNSes, err := ifc.LUID.DNS() + if err != nil { + t.Errorf("LUID.DNS() returned an error: %v", err) + } else if len(newDNSes) != len(dnsesToSet) { + t.Errorf("dnsesToSet contains %d items, while DNSServerAddresses contains %d.", len(dnsesToSet), len(newDNSes)) + } else { + for i := range dnsesToSet { + if !dnsesToSet[i].Equal(newDNSes[i]) { + t.Errorf("dnsesToSet[%d] = %s while DNSServerAddresses[%d] = %s.", i, dnsesToSet[i].String(), i, newDNSes[i].String()) + } + } + } + + err = ifc.LUID.SetDNS(prevDNSes) + if err != nil { + t.Errorf("LUID.SetDNS() returned an error: %v.", err) + } +} + +func TestAnycastIPAddress(t *testing.T) { + _, err := GetAnycastIPAddressTable(windows.AF_UNSPEC) + if err != nil { + t.Errorf("GetAnycastIPAddressTable() returned an error: %v", err) + return + } +} diff --git a/tunnel/winipcfg/zwinipcfg_windows.go b/tunnel/winipcfg/zwinipcfg_windows.go new file mode 100644 index 00000000..b08f887f --- /dev/null +++ b/tunnel/winipcfg/zwinipcfg_windows.go @@ -0,0 +1,318 @@ +// Code generated by 'go generate'; DO NOT EDIT. + +package winipcfg + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return nil + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") + + procFreeMibTable = modiphlpapi.NewProc("FreeMibTable") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procInitializeIpInterfaceEntry = modiphlpapi.NewProc("InitializeIpInterfaceEntry") + procGetIpInterfaceTable = modiphlpapi.NewProc("GetIpInterfaceTable") + procGetIpInterfaceEntry = modiphlpapi.NewProc("GetIpInterfaceEntry") + procSetIpInterfaceEntry = modiphlpapi.NewProc("SetIpInterfaceEntry") + procGetIfEntry2 = modiphlpapi.NewProc("GetIfEntry2") + procGetIfTable2Ex = modiphlpapi.NewProc("GetIfTable2Ex") + procConvertInterfaceLuidToGuid = modiphlpapi.NewProc("ConvertInterfaceLuidToGuid") + procConvertInterfaceGuidToLuid = modiphlpapi.NewProc("ConvertInterfaceGuidToLuid") + procGetUnicastIpAddressTable = modiphlpapi.NewProc("GetUnicastIpAddressTable") + procInitializeUnicastIpAddressEntry = modiphlpapi.NewProc("InitializeUnicastIpAddressEntry") + procGetUnicastIpAddressEntry = modiphlpapi.NewProc("GetUnicastIpAddressEntry") + procSetUnicastIpAddressEntry = modiphlpapi.NewProc("SetUnicastIpAddressEntry") + procCreateUnicastIpAddressEntry = modiphlpapi.NewProc("CreateUnicastIpAddressEntry") + procDeleteUnicastIpAddressEntry = modiphlpapi.NewProc("DeleteUnicastIpAddressEntry") + procGetAnycastIpAddressTable = modiphlpapi.NewProc("GetAnycastIpAddressTable") + procGetAnycastIpAddressEntry = modiphlpapi.NewProc("GetAnycastIpAddressEntry") + procCreateAnycastIpAddressEntry = modiphlpapi.NewProc("CreateAnycastIpAddressEntry") + procDeleteAnycastIpAddressEntry = modiphlpapi.NewProc("DeleteAnycastIpAddressEntry") + procGetIpForwardTable2 = modiphlpapi.NewProc("GetIpForwardTable2") + procInitializeIpForwardEntry = modiphlpapi.NewProc("InitializeIpForwardEntry") + procGetIpForwardEntry2 = modiphlpapi.NewProc("GetIpForwardEntry2") + procSetIpForwardEntry2 = modiphlpapi.NewProc("SetIpForwardEntry2") + procCreateIpForwardEntry2 = modiphlpapi.NewProc("CreateIpForwardEntry2") + procDeleteIpForwardEntry2 = modiphlpapi.NewProc("DeleteIpForwardEntry2") + procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange") + procNotifyUnicastIpAddressChange = modiphlpapi.NewProc("NotifyUnicastIpAddressChange") + procNotifyRouteChange2 = modiphlpapi.NewProc("NotifyRouteChange2") + procCancelMibChangeNotify2 = modiphlpapi.NewProc("CancelMibChangeNotify2") +) + +func freeMibTable(memory unsafe.Pointer) { + syscall.Syscall(procFreeMibTable.Addr(), 1, uintptr(memory), 0, 0) + return +} + +func getAdaptersAddresses(family uint32, flags GAAFlags, reserved uintptr, adapterAddresses *IPAdapterAddresses, sizePointer *uint32) (ret error) { + r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func initializeIPInterfaceEntry(row *MibIPInterfaceRow) { + syscall.Syscall(procInitializeIpInterfaceEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + return +} + +func getIPInterfaceTable(family AddressFamily, table **mibIPInterfaceTable) (ret error) { + r0, _, _ := syscall.Syscall(procGetIpInterfaceTable.Addr(), 2, uintptr(family), uintptr(unsafe.Pointer(table)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func getIPInterfaceEntry(row *MibIPInterfaceRow) (ret error) { + r0, _, _ := syscall.Syscall(procGetIpInterfaceEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func setIPInterfaceEntry(row *MibIPInterfaceRow) (ret error) { + r0, _, _ := syscall.Syscall(procSetIpInterfaceEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func getIfEntry2(row *MibIfRow2) (ret error) { + r0, _, _ := syscall.Syscall(procGetIfEntry2.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func getIfTable2Ex(level MibIfEntryLevel, table **mibIfTable2) (ret error) { + r0, _, _ := syscall.Syscall(procGetIfTable2Ex.Addr(), 2, uintptr(level), uintptr(unsafe.Pointer(table)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func convertInterfaceLUIDToGUID(interfaceLUID *LUID, interfaceGUID *windows.GUID) (ret error) { + r0, _, _ := syscall.Syscall(procConvertInterfaceLuidToGuid.Addr(), 2, uintptr(unsafe.Pointer(interfaceLUID)), uintptr(unsafe.Pointer(interfaceGUID)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func convertInterfaceGUIDToLUID(interfaceGUID *windows.GUID, interfaceLUID *LUID) (ret error) { + r0, _, _ := syscall.Syscall(procConvertInterfaceGuidToLuid.Addr(), 2, uintptr(unsafe.Pointer(interfaceGUID)), uintptr(unsafe.Pointer(interfaceLUID)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func getUnicastIPAddressTable(family AddressFamily, table **mibUnicastIPAddressTable) (ret error) { + r0, _, _ := syscall.Syscall(procGetUnicastIpAddressTable.Addr(), 2, uintptr(family), uintptr(unsafe.Pointer(table)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func initializeUnicastIPAddressEntry(row *MibUnicastIPAddressRow) { + syscall.Syscall(procInitializeUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + return +} + +func getUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) { + r0, _, _ := syscall.Syscall(procGetUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func setUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) { + r0, _, _ := syscall.Syscall(procSetUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func createUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) { + r0, _, _ := syscall.Syscall(procCreateUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func deleteUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) { + r0, _, _ := syscall.Syscall(procDeleteUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func getAnycastIPAddressTable(family AddressFamily, table **mibAnycastIPAddressTable) (ret error) { + r0, _, _ := syscall.Syscall(procGetAnycastIpAddressTable.Addr(), 2, uintptr(family), uintptr(unsafe.Pointer(table)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func getAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) { + r0, _, _ := syscall.Syscall(procGetAnycastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func createAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) { + r0, _, _ := syscall.Syscall(procCreateAnycastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func deleteAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) { + r0, _, _ := syscall.Syscall(procDeleteAnycastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func getIPForwardTable2(family AddressFamily, table **mibIPforwardTable2) (ret error) { + r0, _, _ := syscall.Syscall(procGetIpForwardTable2.Addr(), 2, uintptr(family), uintptr(unsafe.Pointer(table)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func initializeIPForwardEntry(route *MibIPforwardRow2) { + syscall.Syscall(procInitializeIpForwardEntry.Addr(), 1, uintptr(unsafe.Pointer(route)), 0, 0) + return +} + +func getIPForwardEntry2(route *MibIPforwardRow2) (ret error) { + r0, _, _ := syscall.Syscall(procGetIpForwardEntry2.Addr(), 1, uintptr(unsafe.Pointer(route)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func setIPForwardEntry2(route *MibIPforwardRow2) (ret error) { + r0, _, _ := syscall.Syscall(procSetIpForwardEntry2.Addr(), 1, uintptr(unsafe.Pointer(route)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func createIPForwardEntry2(route *MibIPforwardRow2) (ret error) { + r0, _, _ := syscall.Syscall(procCreateIpForwardEntry2.Addr(), 1, uintptr(unsafe.Pointer(route)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func deleteIPForwardEntry2(route *MibIPforwardRow2) (ret error) { + r0, _, _ := syscall.Syscall(procDeleteIpForwardEntry2.Addr(), 1, uintptr(unsafe.Pointer(route)), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func notifyIPInterfaceChange(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) { + var _p0 uint32 + if initialNotification { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, _ := syscall.Syscall6(procNotifyIpInterfaceChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func notifyUnicastIPAddressChange(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) { + var _p0 uint32 + if initialNotification { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, _ := syscall.Syscall6(procNotifyUnicastIpAddressChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func notifyRouteChange2(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) { + var _p0 uint32 + if initialNotification { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, _ := syscall.Syscall6(procNotifyRouteChange2.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func cancelMibChangeNotify2(notificationHandle windows.Handle) (ret error) { + r0, _, _ := syscall.Syscall(procCancelMibChangeNotify2.Addr(), 1, uintptr(notificationHandle), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} -- cgit v1.2.3-59-g8ed1b