diff options
Diffstat (limited to 'tunnel/winipcfg/luid.go')
-rw-r--r-- | tunnel/winipcfg/luid.go | 242 |
1 files changed, 86 insertions, 156 deletions
diff --git a/tunnel/winipcfg/luid.go b/tunnel/winipcfg/luid.go index 8f5ba61b..0c898b89 100644 --- a/tunnel/winipcfg/luid.go +++ b/tunnel/winipcfg/luid.go @@ -1,17 +1,16 @@ /* SPDX-License-Identifier: MIT * - * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. */ package winipcfg import ( "errors" - "fmt" - "net" + "net/netip" + "strings" "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" ) // LUID represents a network interface. @@ -64,12 +63,23 @@ func LUIDFromGUID(guid *windows.GUID) (LUID, error) { return luid, nil } +// LUIDFromIndex function converts a local index 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-convertinterfaceindextoluid +func LUIDFromIndex(index uint32) (LUID, error) { + var luid LUID + err := convertInterfaceIndexToLUID(index, &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) { +func (luid LUID) IPAddress(addr netip.Addr) (*MibUnicastIPAddressRow, error) { row := &MibUnicastIPAddressRow{InterfaceLUID: luid} - err := row.Address.SetIP(ip, 0) + err := row.Address.SetAddr(addr) if err != nil { return nil, err } @@ -84,22 +94,24 @@ func (luid LUID) IPAddress(ip net.IP) (*MibUnicastIPAddressRow, error) { // 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 { +func (luid LUID) AddIPAddress(address netip.Prefix) error { row := &MibUnicastIPAddressRow{} row.Init() row.InterfaceLUID = luid - err := row.Address.SetIP(address.IP, 0) + row.DadState = DadStatePreferred + row.ValidLifetime = 0xffffffff + row.PreferredLifetime = 0xffffffff + err := row.Address.SetAddr(address.Addr()) if err != nil { return err } - ones, _ := address.Mask.Size() - row.OnLinkPrefixLength = uint8(ones) + row.OnLinkPrefixLength = uint8(address.Bits()) 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 { +func (luid LUID) AddIPAddresses(addresses []netip.Prefix) error { for i := range addresses { err := luid.AddIPAddress(addresses[i]) if err != nil { @@ -110,7 +122,7 @@ func (luid LUID) AddIPAddresses(addresses []net.IPNet) error { } // SetIPAddresses method sets new unicast IP addresses to the interface. -func (luid LUID) SetIPAddresses(addresses []net.IPNet) error { +func (luid LUID) SetIPAddresses(addresses []netip.Prefix) error { err := luid.FlushIPAddresses(windows.AF_UNSPEC) if err != nil { return err @@ -119,16 +131,15 @@ func (luid LUID) SetIPAddresses(addresses []net.IPNet) error { } // SetIPAddressesForFamily method sets new unicast IP addresses for a specific family to the interface. -func (luid LUID) SetIPAddressesForFamily(family AddressFamily, addresses []net.IPNet) error { +func (luid LUID) SetIPAddressesForFamily(family AddressFamily, addresses []netip.Prefix) error { err := luid.FlushIPAddresses(family) if err != nil { return err } for i := range addresses { - asV4 := addresses[i].IP.To4() - if asV4 == nil && family == windows.AF_INET { + if !addresses[i].Addr().Is4() && family == windows.AF_INET { continue - } else if asV4 != nil && family == windows.AF_INET6 { + } else if !addresses[i].Addr().Is6() && family == windows.AF_INET6 { continue } err := luid.AddIPAddress(addresses[i]) @@ -141,17 +152,16 @@ func (luid LUID) SetIPAddressesForFamily(family AddressFamily, addresses []net.I // 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(address net.IPNet) error { +func (luid LUID) DeleteIPAddress(address netip.Prefix) error { row := &MibUnicastIPAddressRow{} row.Init() row.InterfaceLUID = luid - err := row.Address.SetIP(address.IP, 0) + err := row.Address.SetAddr(address.Addr()) if err != nil { return err } // Note: OnLinkPrefixLength member is ignored by DeleteUnicastIpAddressEntry(). - ones, _ := address.Mask.Size() - row.OnLinkPrefixLength = uint8(ones) + row.OnLinkPrefixLength = uint8(address.Bits()) return row.Delete() } @@ -175,15 +185,17 @@ func (luid LUID) FlushIPAddresses(family AddressFamily) error { // 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) { +func (luid LUID) Route(destination netip.Prefix, nextHop netip.Addr) (*MibIPforwardRow2, error) { row := &MibIPforwardRow2{} row.Init() row.InterfaceLUID = luid - err := row.DestinationPrefix.SetIPNet(destination) + row.ValidLifetime = 0xffffffff + row.PreferredLifetime = 0xffffffff + err := row.DestinationPrefix.SetPrefix(destination) if err != nil { return nil, err } - err = row.NextHop.SetIP(nextHop, 0) + err = row.NextHop.SetAddr(nextHop) if err != nil { return nil, err } @@ -197,15 +209,15 @@ func (luid LUID) Route(destination net.IPNet, nextHop net.IP) (*MibIPforwardRow2 // 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 { +func (luid LUID) AddRoute(destination netip.Prefix, nextHop netip.Addr, metric uint32) error { row := &MibIPforwardRow2{} row.Init() row.InterfaceLUID = luid - err := row.DestinationPrefix.SetIPNet(destination) + err := row.DestinationPrefix.SetPrefix(destination) if err != nil { return err } - err = row.NextHop.SetIP(nextHop, 0) + err = row.NextHop.SetAddr(nextHop) if err != nil { return err } @@ -240,10 +252,9 @@ func (luid LUID) SetRoutesForFamily(family AddressFamily, routesData []*RouteDat return err } for _, rd := range routesData { - asV4 := rd.Destination.IP.To4() - if asV4 == nil && family == windows.AF_INET { + if !rd.Destination.Addr().Is4() && family == windows.AF_INET { continue - } else if asV4 != nil && family == windows.AF_INET6 { + } else if !rd.Destination.Addr().Is6() && family == windows.AF_INET6 { continue } err := luid.AddRoute(rd.Destination, rd.NextHop, rd.Metric) @@ -256,15 +267,15 @@ func (luid LUID) SetRoutesForFamily(family AddressFamily, routesData []*RouteDat // 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 { +func (luid LUID) DeleteRoute(destination netip.Prefix, nextHop netip.Addr) error { row := &MibIPforwardRow2{} row.Init() row.InterfaceLUID = luid - err := row.DestinationPrefix.SetIPNet(destination) + err := row.DestinationPrefix.SetPrefix(destination) if err != nil { return err } - err = row.NextHop.SetIP(nextHop, 0) + err = row.NextHop.SetAddr(nextHop) if err != nil { return err } @@ -297,17 +308,19 @@ func (luid LUID) FlushRoutes(family AddressFamily) error { } // DNS method returns all DNS server addresses associated with the adapter. -func (luid LUID) DNS() ([]net.IP, error) { +func (luid LUID) DNS() ([]netip.Addr, error) { addresses, err := GetAdaptersAddresses(windows.AF_UNSPEC, GAAFlagDefault) if err != nil { return nil, err } - r := make([]net.IP, 0, len(addresses)) + r := make([]netip.Addr, 0, len(addresses)) for _, addr := range addresses { if addr.LUID == luid { for dns := addr.FirstDNSServerAddress; dns != nil; dns = dns.Next { if ip := dns.Address.IP(); ip != nil { - r = append(r, ip) + if a, ok := netip.AddrFromSlice(ip); ok { + r = append(r, a) + } } else { return nil, windows.ERROR_INVALID_PARAMETER } @@ -317,141 +330,58 @@ func (luid LUID) DNS() ([]net.IP, error) { 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 +// SetDNS method clears previous and associates new DNS servers and search domains with the adapter for a specific family. +func (luid LUID) SetDNS(family AddressFamily, servers []netip.Addr, domains []string) error { + if family != windows.AF_INET && family != windows.AF_INET6 { + return windows.ERROR_PROTOCOL_UNREACHABLE } - 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())) + var filteredServers []string + for _, server := range servers { + if (server.Is4() && family == windows.AF_INET) || (server.Is6() && family == windows.AF_INET6) { + filteredServers = append(filteredServers, server.String()) } } - - if len(cmds) == 0 { - return nil - } - return runNetsh(cmds) -} - -// SetDNSForFamily method clears previous and associates new DNS servers with the adapter for a specific family. -func (luid LUID) SetDNSForFamily(family AddressFamily, dnses []net.IP) error { - var templateFlush string - if family == windows.AF_INET { - templateFlush = netshCmdTemplateFlush4 - } else if family == windows.AF_INET6 { - templateFlush = netshCmdTemplateFlush6 - } - - cmds := make([]string, 0, 1+len(dnses)) - ipif, err := luid.IPInterface(family) + servers16, err := windows.UTF16PtrFromString(strings.Join(filteredServers, ",")) if err != nil { return err } - cmds = append(cmds, fmt.Sprintf(templateFlush, ipif.InterfaceIndex)) - for i := 0; i < len(dnses); i++ { - if v4 := dnses[i].To4(); v4 != nil && family == windows.AF_INET { - cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd4, ipif.InterfaceIndex, v4.String())) - } else if v6 := dnses[i].To16(); v4 == nil && v6 != nil && family == windows.AF_INET6 { - cmds = append(cmds, fmt.Sprintf(netshCmdTemplateAdd6, ipif.InterfaceIndex, v6.String())) - } + domains16, err := windows.UTF16PtrFromString(strings.Join(domains, ",")) + if err != nil { + return err } - return runNetsh(cmds) -} - -// SetDNSDomain method sets the interface-specific DNS domain. -func (luid LUID) SetDNSDomain(domain string) error { guid, err := luid.GUID() if err != nil { - return fmt.Errorf("Error converting luid to guid: %v", err) + return err } - key, err := registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%v", guid), registry.QUERY_VALUE) - if err != nil { - return fmt.Errorf("Error opening adapter-specific TCP/IP network registry key: %v", err) + dnsInterfaceSettings := &DnsInterfaceSettings{ + Version: DnsInterfaceSettingsVersion1, + Flags: DnsInterfaceSettingsFlagNameserver | DnsInterfaceSettingsFlagSearchList, + NameServer: servers16, + SearchList: domains16, } - paths, _, err := key.GetStringsValue("IpConfig") - key.Close() - if err != nil { - return fmt.Errorf("Error reading IpConfig registry key: %v", err) + if family == windows.AF_INET6 { + dnsInterfaceSettings.Flags |= DnsInterfaceSettingsFlagIPv6 } - if len(paths) == 0 { - return errors.New("No TCP/IP interfaces found on adapter") + // For >= Windows 10 1809 + err = SetInterfaceDnsSettings(*guid, dnsInterfaceSettings) + if err == nil || !errors.Is(err, windows.ERROR_PROC_NOT_FOUND) { + return err } - key, err = registry.OpenKey(registry.LOCAL_MACHINE, fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\%s", paths[0]), registry.SET_VALUE) + + // For < Windows 10 1809 + err = luid.fallbackSetDNSForFamily(family, servers) if err != nil { - return fmt.Errorf("Unable to open TCP/IP network registry key: %v", err) + return err } - err = key.SetStringValue("Domain", domain) - key.Close() - return err + if len(domains) > 0 { + return luid.fallbackSetDNSDomain(domains[0]) + } else { + return luid.fallbackSetDNSDomain("") + } +} + +// FlushDNS method clears all DNS servers associated with the adapter. +func (luid LUID) FlushDNS(family AddressFamily) error { + return luid.SetDNS(family, nil, nil) } |