aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tunnel/ifaceconfig.go
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-06-17 13:08:13 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-06-18 12:08:51 +0200
commit6e48647318edad7540c4e99be5aed10ac898893f (patch)
tree13a2d97bcb3ad8e44f288d3220fd9030d9eb968c /tunnel/ifaceconfig.go
parentversion: bump (diff)
downloadwireguard-windows-6e48647318edad7540c4e99be5aed10ac898893f.tar.xz
wireguard-windows-6e48647318edad7540c4e99be5aed10ac898893f.zip
tunnel: wait for IP service to attach to wintun
This helps fix startup races without needing to poll, as well as reconfiguring interfaces after wintun destroys and re-adds. It also deals gracefully with IPv6 being disabled. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'tunnel/ifaceconfig.go')
-rw-r--r--tunnel/ifaceconfig.go244
1 files changed, 0 insertions, 244 deletions
diff --git a/tunnel/ifaceconfig.go b/tunnel/ifaceconfig.go
deleted file mode 100644
index a71b612e..00000000
--- a/tunnel/ifaceconfig.go
+++ /dev/null
@@ -1,244 +0,0 @@
-/* SPDX-License-Identifier: MIT
- *
- * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
- */
-
-package tunnel
-
-import (
- "bytes"
- "log"
- "net"
- "sort"
- "time"
-
- "golang.org/x/sys/windows"
- "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) {
- if len(addresses) == 0 {
- return
- }
- 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
- if ip4 := ip.To4(); ip4 != nil {
- ip = ip4
- }
- mA, _ := addr.Mask.Size()
- mB, _ := a.Mask.Size()
- if bytes.Equal(ip, a.IP) && mA == mB {
- return true
- }
- }
- return false
- }
- interfaces, err := winipcfg.GetAdaptersAddresses(windows.AF_UNSPEC, winipcfg.GAAFlagDefault)
- if err != nil {
- return
- }
- for _, iface := range interfaces {
- if iface.OperStatus == winipcfg.IfOperStatusUp {
- continue
- }
- for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
- ip := address.Address.IP()
- 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'", ipnet.String(), iface.FriendlyName())
- iface.LUID.DeleteIPAddress(ipnet)
- }
- }
- }
-}
-
-func configureInterface(conf *conf.Config, tun *tun.NativeTun) error {
- luid := winipcfg.LUID(tun.LUID())
-
- estimatedRouteCount := len(conf.Interface.Addresses)
- for _, peer := range conf.Peers {
- estimatedRouteCount += len(peer.AllowedIPs)
- }
- routes := make([]winipcfg.RouteData, 0, estimatedRouteCount)
- var firstGateway4 *net.IP
- var firstGateway6 *net.IP
- addresses := make([]net.IPNet, len(conf.Interface.Addresses))
- for i, addr := range conf.Interface.Addresses {
- ipnet := addr.IPNet()
- addresses[i] = ipnet
- gateway := ipnet.IP.Mask(ipnet.Mask)
- if addr.Bits() == 32 && firstGateway4 == nil {
- firstGateway4 = &gateway
- } else if addr.Bits() == 128 && firstGateway6 == nil {
- firstGateway6 = &gateway
- }
- routes = append(routes, winipcfg.RouteData{
- Destination: net.IPNet{
- IP: gateway,
- Mask: ipnet.Mask,
- },
- NextHop: gateway,
- Metric: 0,
- })
- }
-
- foundDefault4 := false
- foundDefault6 := false
- for _, peer := range conf.Peers {
- for _, allowedip := range peer.AllowedIPs {
- if (allowedip.Bits() == 32 && firstGateway4 == nil) || (allowedip.Bits() == 128 && firstGateway6 == nil) {
- continue
- }
- route := winipcfg.RouteData{
- Destination: allowedip.IPNet(),
- Metric: 0,
- }
- if allowedip.Bits() == 32 {
- if allowedip.Cidr == 0 {
- foundDefault4 = true
- }
- route.NextHop = *firstGateway4
- } else if allowedip.Bits() == 128 {
- if allowedip.Cidr == 0 {
- foundDefault6 = true
- }
- route.NextHop = *firstGateway6
- }
- routes = append(routes, route)
- }
- }
-
- err := luid.SetIPAddresses(addresses)
- if err == windows.ERROR_OBJECT_ALREADY_EXISTS {
- cleanupAddressesOnDisconnectedInterfaces(addresses)
- err = luid.SetIPAddresses(addresses)
- }
- if err != nil {
- return err
- }
-
- deduplicatedRoutes := make([]*winipcfg.RouteData, 0, len(routes))
- sort.Slice(routes, func(i, j int) bool {
- return routes[i].Metric < routes[j].Metric ||
- bytes.Compare(routes[i].NextHop, routes[j].NextHop) == -1 ||
- bytes.Compare(routes[i].Destination.IP, routes[j].Destination.IP) == -1 ||
- bytes.Compare(routes[i].Destination.Mask, routes[j].Destination.Mask) == -1
- })
- for i := 0; i < len(routes); i++ {
- if i > 0 && routes[i].Metric == routes[i-1].Metric &&
- bytes.Equal(routes[i].NextHop, routes[i-1].NextHop) &&
- bytes.Equal(routes[i].Destination.IP, routes[i-1].Destination.IP) &&
- bytes.Equal(routes[i].Destination.Mask, routes[i-1].Destination.Mask) {
- continue
- }
- deduplicatedRoutes = append(deduplicatedRoutes, &routes[i])
- }
-
- err = luid.SetRoutes(deduplicatedRoutes)
- if err != nil {
- return nil
- }
-
- ipif, err := luid.IPInterface(windows.AF_INET)
- if err != nil {
- return err
- }
- if foundDefault4 {
- ipif.UseAutomaticMetric = false
- ipif.Metric = 0
- }
- if conf.Interface.MTU > 0 {
- ipif.NLMTU = uint32(conf.Interface.MTU)
- tun.ForceMTU(int(ipif.NLMTU))
- }
- err = ipif.Set()
- if err != nil {
- return err
- }
-
- ipif, err = luid.IPInterface(windows.AF_INET6)
- if err != nil && firstGateway6 != nil {
- log.Printf("Is IPv6 disabled by Windows?")
- return err
- } else if err == nil { // People seem to like to disable IPv6, so we make this non-fatal.
- if foundDefault6 {
- ipif.UseAutomaticMetric = false
- ipif.Metric = 0
- }
- if conf.Interface.MTU > 0 {
- ipif.NLMTU = uint32(conf.Interface.MTU)
- }
- ipif.DadTransmits = 0
- ipif.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
- err = ipif.Set()
- if err != nil {
- 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 := 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()
-}
-
-func enableFirewall(conf *conf.Config, tun *tun.NativeTun) error {
- restrictAll := false
- if len(conf.Peers) == 1 {
- nextallowedip:
- for _, allowedip := range conf.Peers[0].AllowedIPs {
- if allowedip.Cidr == 0 {
- for _, b := range allowedip.IP {
- if b != 0 {
- continue nextallowedip
- }
- }
- restrictAll = true
- break
- }
- }
- }
- if restrictAll && len(conf.Interface.DNS) == 0 {
- log.Println("Warning: no DNS server specified, despite having an allowed IPs of 0.0.0.0/0 or ::/0. There may be connectivity issues.")
- }
- return firewall.EnableFirewall(tun.LUID(), conf.Interface.DNS, restrictAll)
-}
-
-func waitForFamilies(tun *tun.NativeTun) {
- // TODO: This whole thing is a disgusting hack that shouldn't be neccessary.
-
- f := func(luid winipcfg.LUID, family winipcfg.AddressFamily, maxRetries int) {
- for i := 0; i < maxRetries; i++ {
- _, err := luid.IPInterface(family)
- if i != maxRetries-1 && err == windows.ERROR_NOT_FOUND {
- time.Sleep(time.Millisecond * 50)
- continue
- }
- break
- }
- }
- luid := winipcfg.LUID(tun.LUID())
- f(luid, windows.AF_INET, 100)
- f(luid, windows.AF_INET6, 3)
-}