aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tunnel/winipcfg/luid.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tunnel/winipcfg/luid.go355
1 files changed, 355 insertions, 0 deletions
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)
+}