aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-05-22 20:18:38 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-22 20:26:57 +0200
commit2bb661dc7c70420c3e5c97c5fff70f954a4bb5e6 (patch)
treea4298e53f0956188e78c529a78c4ad0e8a698b7e
parentui: trade one hack for another in confview (diff)
downloadwireguard-windows-2bb661dc7c70420c3e5c97c5fff70f954a4bb5e6.tar.xz
wireguard-windows-2bb661dc7c70420c3e5c97c5fff70f954a4bb5e6.zip
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 <simon@rozman.si> Signed-off-by: Aleksandar Pesic <peske.nis@gmail.com>
-rw-r--r--go.mod1
-rw-r--r--tunnel/defaultroutemonitor.go45
-rw-r--r--tunnel/ifaceconfig.go69
-rw-r--r--tunnel/service.go2
-rw-r--r--tunnel/winipcfg/interface_change_handler.go73
-rw-r--r--tunnel/winipcfg/luid.go355
-rw-r--r--tunnel/winipcfg/mksyscall.go8
-rw-r--r--tunnel/winipcfg/netsh.go48
-rw-r--r--tunnel/winipcfg/route_change_handler.go80
-rw-r--r--tunnel/winipcfg/types.go952
-rw-r--r--tunnel/winipcfg/types_386.go230
-rw-r--r--tunnel/winipcfg/types_amd64.go218
-rw-r--r--tunnel/winipcfg/types_test.go1057
-rw-r--r--tunnel/winipcfg/types_test_386.go57
-rw-r--r--tunnel/winipcfg/types_test_amd64.go57
-rw-r--r--tunnel/winipcfg/unicast_address_change_handler.go73
-rw-r--r--tunnel/winipcfg/utils.go26
-rw-r--r--tunnel/winipcfg/winipcfg.go169
-rw-r--r--tunnel/winipcfg/winipcfg_test.go705
-rw-r--r--tunnel/winipcfg/zwinipcfg_windows.go318
20 files changed, 4479 insertions, 64 deletions
diff --git a/go.mod b/go.mod
index b261fb42..187448f3 100644
--- a/go.mod
+++ b/go.mod
@@ -1,7 +1,6 @@
module golang.zx2c4.com/wireguard/windows
require (
- golang.zx2c4.com/winipcfg latest
golang.zx2c4.com/wireguard v0.0.20190517
golang.org/x/crypto latest
diff --git a/tunnel/defaultroutemonitor.go b/tunnel/defaultroutemonitor.go
index 1ffce5fa..8dd3273c 100644
--- a/tunnel/defaultroutemonitor.go
+++ b/tunnel/defaultroutemonitor.go
@@ -10,32 +10,33 @@ import (
"time"
"golang.org/x/sys/windows"
- "golang.zx2c4.com/winipcfg"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
+
+ "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
-func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLUID uint64, lastLUID *uint64, lastIndex *uint32) error {
- routes, err := winipcfg.GetRoutes(family)
+func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLUID winipcfg.LUID, lastLUID *winipcfg.LUID, lastIndex *uint32) error {
+ r, err := winipcfg.GetIPForwardTable2(family)
if err != nil {
return err
}
lowestMetric := ^uint32(0)
- index := uint32(0) // Zero is "unspecified", which for IP_UNICAST_IF resets the value, which is what we want.
- luid := uint64(0) // Hopefully luid zero is unspecified, but hard to find docs saying so.
- for _, route := range routes {
- if route.DestinationPrefix.PrefixLength != 0 || route.InterfaceLUID == ourLUID {
+ index := uint32(0) // Zero is "unspecified", which for IP_UNICAST_IF resets the value, which is what we want.
+ luid := winipcfg.LUID(0) // Hopefully luid zero is unspecified, but hard to find docs saying so.
+ for i := range r {
+ if r[i].DestinationPrefix.PrefixLength != 0 || r[i].InterfaceLUID == ourLUID {
continue
}
- ifrow, err := winipcfg.GetIfRow(route.InterfaceLUID)
+ ifrow, err := r[i].InterfaceLUID.Interface()
if err != nil || ifrow.OperStatus != winipcfg.IfOperStatusUp {
- log.Printf("Found default route for interface %d, but not up, so skipping", route.InterfaceIndex)
+ log.Printf("Found default route for interface %d, but not up, so skipping", r[i].InterfaceIndex)
continue
}
- if route.Metric < lowestMetric {
- lowestMetric = route.Metric
- index = route.InterfaceIndex
- luid = route.InterfaceLUID
+ if r[i].Metric < lowestMetric {
+ lowestMetric = r[i].Metric
+ index = r[i].InterfaceIndex
+ luid = r[i].InterfaceLUID
}
}
if luid == *lastLUID && index == *lastIndex {
@@ -53,10 +54,10 @@ func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLU
return nil
}
-func getIPInterfaceRetry(luid uint64, family winipcfg.AddressFamily, retry bool) (ipi *winipcfg.IPInterface, err error) {
+func getIPInterfaceRetry(luid winipcfg.LUID, family winipcfg.AddressFamily, retry bool) (ipi *winipcfg.MibIPInterfaceRow, err error) {
const maxRetries = 100
for i := 0; i < maxRetries; i++ {
- ipi, err = winipcfg.GetIPInterface(luid, family)
+ ipi, err = luid.IPInterface(family)
if retry && i != maxRetries-1 && err == windows.ERROR_NOT_FOUND {
time.Sleep(time.Millisecond * 50)
continue
@@ -67,9 +68,9 @@ func getIPInterfaceRetry(luid uint64, family winipcfg.AddressFamily, retry bool)
}
func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTun) (*winipcfg.RouteChangeCallback, error) {
- ourLUID := tun.LUID()
- lastLUID4 := uint64(0)
- lastLUID6 := uint64(0)
+ ourLUID := winipcfg.LUID(tun.LUID())
+ lastLUID4 := winipcfg.LUID(0)
+ lastLUID6 := winipcfg.LUID(0)
lastIndex4 := uint32(0)
lastIndex6 := uint32(0)
lastMTU := uint32(0)
@@ -87,7 +88,7 @@ func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTu
}
mtu := uint32(0)
if lastLUID4 != 0 {
- iface, err := winipcfg.InterfaceFromLUID(lastLUID4)
+ iface, err := lastLUID4.Interface()
if err != nil {
return err
}
@@ -96,7 +97,7 @@ func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTu
}
}
if lastLUID6 != 0 {
- iface, err := winipcfg.InterfaceFromLUID(lastLUID6)
+ iface, err := lastLUID6.Interface()
if err != nil {
return err
}
@@ -138,8 +139,8 @@ func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTu
if err != nil {
return nil, err
}
- cb, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.Route) {
- if route.DestinationPrefix.PrefixLength == 0 {
+ cb, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) {
+ if route != nil && route.DestinationPrefix.PrefixLength == 0 {
_ = doIt(false)
}
})
diff --git a/tunnel/ifaceconfig.go b/tunnel/ifaceconfig.go
index 7d0f1187..917d0aab 100644
--- a/tunnel/ifaceconfig.go
+++ b/tunnel/ifaceconfig.go
@@ -12,18 +12,18 @@ import (
"sort"
"golang.org/x/sys/windows"
- "golang.zx2c4.com/winipcfg"
"golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/windows/conf"
"golang.zx2c4.com/wireguard/windows/tunnel/firewall"
+ "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
-func cleanupAddressesOnDisconnectedInterfaces(addresses []*net.IPNet) {
+func cleanupAddressesOnDisconnectedInterfaces(addresses []net.IPNet) {
if len(addresses) == 0 {
return
}
- includedInAddresses := func(a *net.IPNet) bool {
+ includedInAddresses := func(a net.IPNet) bool {
//TODO: this makes the whole algorithm O(n^2). But we can't stick net.IPNet in a Go hashmap. Bummer!
for _, addr := range addresses {
ip := addr.IP
@@ -38,7 +38,7 @@ func cleanupAddressesOnDisconnectedInterfaces(addresses []*net.IPNet) {
}
return false
}
- interfaces, err := winipcfg.GetInterfaces()
+ interfaces, err := winipcfg.GetAdaptersAddresses(windows.AF_UNSPEC, winipcfg.GAAFlagDefault)
if err != nil {
return
}
@@ -46,29 +46,19 @@ func cleanupAddressesOnDisconnectedInterfaces(addresses []*net.IPNet) {
if iface.OperStatus == winipcfg.IfOperStatusUp {
continue
}
- addressesToKeep := make([]*net.IPNet, 0, len(iface.UnicastAddresses))
- for _, address := range iface.UnicastAddresses {
- ip := address.Address.Address
- if ip4 := ip.To4(); ip4 != nil {
- ip = ip4
+ for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
+ ip := winipcfg.SocketAddressToIP(&address.Address)
+ ipnet := net.IPNet{IP: ip, Mask: net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))}
+ if includedInAddresses(ipnet) {
+ log.Printf("Cleaning up stale address %s from interface '%s'", ip.String(), iface.FriendlyName())
+ iface.LUID.DeleteIPAddress(ip)
}
- ipnet := &net.IPNet{ip, net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))}
- if !includedInAddresses(ipnet) {
- addressesToKeep = append(addressesToKeep, ipnet)
- }
- }
- if len(addressesToKeep) < len(iface.UnicastAddresses) {
- log.Printf("Cleaning up stale addresses from interface '%s'", iface.FriendlyName)
- iface.SetAddresses(addressesToKeep)
}
}
}
func configureInterface(conf *conf.Config, tun *tun.NativeTun) error {
- iface, err := winipcfg.InterfaceFromLUID(tun.LUID())
- if err != nil {
- return err
- }
+ luid := winipcfg.LUID(tun.LUID())
estimatedRouteCount := len(conf.Interface.Addresses)
for _, peer := range conf.Peers {
@@ -77,10 +67,10 @@ func configureInterface(conf *conf.Config, tun *tun.NativeTun) error {
routes := make([]winipcfg.RouteData, 0, estimatedRouteCount)
var firstGateway4 *net.IP
var firstGateway6 *net.IP
- addresses := make([]*net.IPNet, len(conf.Interface.Addresses))
+ addresses := make([]net.IPNet, len(conf.Interface.Addresses))
for i, addr := range conf.Interface.Addresses {
ipnet := addr.IPNet()
- addresses[i] = &ipnet
+ addresses[i] = ipnet
gateway := ipnet.IP.Mask(ipnet.Mask)
if addr.Bits() == 32 && firstGateway4 == nil {
firstGateway4 = &gateway
@@ -123,10 +113,10 @@ func configureInterface(conf *conf.Config, tun *tun.NativeTun) error {
}
}
- err = iface.SetAddresses(addresses)
+ err := luid.SetIPAddresses(addresses)
if err == windows.ERROR_OBJECT_ALREADY_EXISTS {
cleanupAddressesOnDisconnectedInterfaces(addresses)
- err = iface.SetAddresses(addresses)
+ err = luid.SetIPAddresses(addresses)
}
if err != nil {
return err
@@ -149,17 +139,12 @@ func configureInterface(conf *conf.Config, tun *tun.NativeTun) error {
deduplicatedRoutes = append(deduplicatedRoutes, &routes[i])
}
- err = iface.SetRoutes(deduplicatedRoutes)
+ err = luid.SetRoutes(deduplicatedRoutes)
if err != nil {
return nil
}
- err = iface.SetDNS(conf.Interface.DNS)
- if err != nil {
- return err
- }
-
- ipif, err := iface.GetIPInterface(windows.AF_INET)
+ ipif, err := luid.IPInterface(windows.AF_INET)
if err != nil {
return err
}
@@ -176,7 +161,7 @@ func configureInterface(conf *conf.Config, tun *tun.NativeTun) error {
return err
}
- ipif, err = iface.GetIPInterface(windows.AF_INET6)
+ ipif, err = luid.IPInterface(windows.AF_INET6)
if err != nil {
return err
}
@@ -194,19 +179,23 @@ func configureInterface(conf *conf.Config, tun *tun.NativeTun) error {
return err
}
+ err = luid.SetDNS(conf.Interface.DNS)
+ if err != nil {
+ return err
+ }
+
return nil
}
func unconfigureInterface(tun *tun.NativeTun) {
// It seems that the Windows networking stack doesn't like it when we destroy interfaces that have active
// routes, so to be certain, just remove everything before destroying.
- luid := tun.LUID()
- winipcfg.FlushInterfaceRoutes(luid, windows.AF_INET)
- winipcfg.FlushInterfaceIPAddresses(luid, windows.AF_INET)
- winipcfg.FlushInterfaceRoutes(luid, windows.AF_INET6)
- winipcfg.FlushInterfaceIPAddresses(luid, windows.AF_INET6)
-
- //TODO: also flush DNS servers once rozmansi fixes the API for that to take a LUID
+ luid := winipcfg.LUID(tun.LUID())
+ luid.FlushRoutes(windows.AF_INET)
+ luid.FlushIPAddresses(windows.AF_INET)
+ luid.FlushRoutes(windows.AF_INET6)
+ luid.FlushIPAddresses(windows.AF_INET6)
+ luid.FlushDNS()
firewall.DisableFirewall()
}
diff --git a/tunnel/service.go b/tunnel/service.go
index ef947ba5..99bb3497 100644
--- a/tunnel/service.go
+++ b/tunnel/service.go
@@ -18,7 +18,6 @@ import (
"time"
"golang.org/x/sys/windows/svc"
- "golang.zx2c4.com/winipcfg"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
@@ -26,6 +25,7 @@ import (
"golang.zx2c4.com/wireguard/windows/conf"
"golang.zx2c4.com/wireguard/windows/ringlogger"
"golang.zx2c4.com/wireguard/windows/services"
+ "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"golang.zx2c4.com/wireguard/windows/version"
)
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
+}