diff --git a/wgengine/router/router.go b/wgengine/router/router.go index a8f8d1ba9..c4486c519 100644 --- a/wgengine/router/router.go +++ b/wgengine/router/router.go @@ -41,7 +41,7 @@ func New(logf logger.Logf, wgdev *device.Device, tundev tun.Device) (Router, err // IP, etc in wgcfg.Config) plus the things that WireGuard doesn't do // itself, like DNS stuff. type RouteSettings struct { - LocalAddr wgcfg.CIDR // TODO: why is this here? how does it differ from wgcfg.Config's info? + LocalAddrs []wgcfg.CIDR DNS []wgcfg.IP DNSDomains []string SubnetRoutes []wgcfg.CIDR // subnets being advertised to other Tailscale nodes @@ -55,5 +55,5 @@ func (rs *RouteSettings) OnlyRelevantParts() string { peers = append(peers, p.AllowedIPs) } return fmt.Sprintf("%v %v %v %v %v", - rs.LocalAddr, rs.DNS, rs.DNSDomains, rs.SubnetRoutes, peers) + rs.LocalAddrs, rs.DNS, rs.DNSDomains, rs.SubnetRoutes, peers) } diff --git a/wgengine/router/router_freebsd.go b/wgengine/router/router_freebsd.go index a0be4c141..d120044ea 100644 --- a/wgengine/router/router_freebsd.go +++ b/wgengine/router/router_freebsd.go @@ -5,6 +5,7 @@ package router import ( + "errors" "fmt" "log" "os/exec" @@ -55,14 +56,19 @@ func (r *freebsdRouter) Up() error { } func (r *freebsdRouter) SetRoutes(rs RouteSettings) error { - if rs.LocalAddr == (wgcfg.CIDR{}) { + if len(rs.LocalAddrs) == 0 { return nil } + // TODO: support configuring multiple local addrs on interface. + if len(rs.LocalAddrs) != 1 { + return errors.New("freebsd doesn't support setting multiple local addrs yet") + } + localAddr := rs.LocalAddrs[0] var errq error // Update the address. - if rs.LocalAddr != r.local { + if localAddr != r.local { // If the interface is already set, remove it. if r.local != (wgcfg.CIDR{}) { addrdel := []string{"ifconfig", r.tunname, @@ -78,7 +84,7 @@ func (r *freebsdRouter) SetRoutes(rs RouteSettings) error { // Add the interface. addradd := []string{"ifconfig", r.tunname, - "inet", rs.LocalAddr.String(), rs.LocalAddr.IP.String()} + "inet", localAddr.String(), localAddr.IP.String()} out, err := cmd(addradd...).CombinedOutput() if err != nil { r.logf("addr add failed: %v: %v\n%s", addradd, err, out) @@ -132,7 +138,7 @@ func (r *freebsdRouter) SetRoutes(rs RouteSettings) error { } // Store the interface and routes so we know what to change on an update. - r.local = rs.LocalAddr + r.local = localAddr r.routes = newRoutes if err := r.replaceResolvConf(rs.DNS, rs.DNSDomains); err != nil { diff --git a/wgengine/router/router_linux.go b/wgengine/router/router_linux.go index 36223be28..389b09c2c 100644 --- a/wgengine/router/router_linux.go +++ b/wgengine/router/router_linux.go @@ -51,7 +51,7 @@ type linuxRouter struct { logf func(fmt string, args ...interface{}) tunname string - local wgcfg.CIDR + addrs map[wgcfg.CIDR]bool routes map[wgcfg.CIDR]bool subnetRoutes map[wgcfg.CIDR]bool @@ -117,8 +117,9 @@ func (r *linuxRouter) down() error { return err } - r.routes = map[wgcfg.CIDR]bool{} - r.local = wgcfg.CIDR{} + r.addrs = nil + r.routes = nil + r.subnetRoutes = nil return nil } @@ -140,16 +141,26 @@ func (r *linuxRouter) Close() error { func (r *linuxRouter) SetRoutes(rs RouteSettings) error { var errq error - if rs.LocalAddr != r.local { - if r.local != (wgcfg.CIDR{}) { - if err := r.delAddress(r.local); err != nil { - r.logf("addr del failed: %v", err) - if errq == nil { - errq = err - } + newAddrs := make(map[wgcfg.CIDR]bool) + for _, addr := range rs.LocalAddrs { + newAddrs[addr] = true + } + for addr := range r.addrs { + if newAddrs[addr] { + continue + } + if err := r.delAddress(addr); err != nil { + r.logf("addr del failed: %v", err) + if errq == nil { + errq = err } } - if err := r.addAddress(rs.LocalAddr); err != nil { + } + for addr := range newAddrs { + if r.addrs[addr] { + continue + } + if err := r.addAddress(addr); err != nil { r.logf("addr add failed: %v", err) if errq == nil { errq = err @@ -213,7 +224,7 @@ func (r *linuxRouter) SetRoutes(rs RouteSettings) error { } } - r.local = rs.LocalAddr + r.addrs = newAddrs r.routes = newRoutes r.subnetRoutes = newSubnetRoutes diff --git a/wgengine/router/router_openbsd.go b/wgengine/router/router_openbsd.go index 96befa8bd..84b54effe 100644 --- a/wgengine/router/router_openbsd.go +++ b/wgengine/router/router_openbsd.go @@ -6,6 +6,7 @@ import ( "bytes" + "errors" "fmt" "io/ioutil" "log" @@ -60,9 +61,15 @@ func (r *openbsdRouter) Up() error { } func (r *openbsdRouter) SetRoutes(rs RouteSettings) error { + // TODO: support configuring multiple local addrs on interface. + if len(rs.LocalAddrs) != 1 { + return errors.New("freebsd doesn't support setting multiple local addrs yet") + } + localAddr := rs.LocalAddrs[0] + var errq error - if rs.LocalAddr != r.local { + if localAddr != r.local { if r.local != (wgcfg.CIDR{}) { addrdel := []string{"ifconfig", r.tunname, "inet", r.local.String(), "-alias"} @@ -86,7 +93,7 @@ func (r *openbsdRouter) SetRoutes(rs RouteSettings) error { } addradd := []string{"ifconfig", r.tunname, - "inet", rs.LocalAddr.String(), "alias"} + "inet", localAddr.String(), "alias"} out, err := cmd(addradd...).CombinedOutput() if err != nil { r.logf("addr add failed: %v: %v\n%s", addradd, err, out) @@ -96,8 +103,8 @@ func (r *openbsdRouter) SetRoutes(rs RouteSettings) error { } routeadd := []string{"route", "-q", "-n", - "add", "-inet", rs.LocalAddr.String(), - "-iface", rs.LocalAddr.IP.String()} + "add", "-inet", localAddr.String(), + "-iface", localAddr.IP.String()} if out, err := cmd(routeadd...).CombinedOutput(); err != nil { r.logf("route add failed: %v: %v\n%s", routeadd, err, out) if errq == nil { @@ -119,7 +126,7 @@ func (r *openbsdRouter) SetRoutes(rs RouteSettings) error { nstr := fmt.Sprintf("%v/%d", nip, route.Mask) routedel := []string{"route", "-q", "-n", "del", "-inet", nstr, - "-iface", rs.LocalAddr.IP.String()} + "-iface", localAddr.IP.String()} out, err := cmd(routedel...).CombinedOutput() if err != nil { r.logf("route del failed: %v: %v\n%s", routedel, err, out) @@ -136,7 +143,7 @@ func (r *openbsdRouter) SetRoutes(rs RouteSettings) error { nstr := fmt.Sprintf("%v/%d", nip, route.Mask) routeadd := []string{"route", "-q", "-n", "add", "-inet", nstr, - "-iface", rs.LocalAddr.IP.String()} + "-iface", localAddr.IP.String()} out, err := cmd(routeadd...).CombinedOutput() if err != nil { r.logf("addr add failed: %v: %v\n%s", routeadd, err, out) @@ -147,7 +154,7 @@ func (r *openbsdRouter) SetRoutes(rs RouteSettings) error { } } - r.local = rs.LocalAddr + r.local = localAddr r.routes = newRoutes if err := r.replaceResolvConf(rs.DNS, rs.DNSDomains); err != nil { diff --git a/wgengine/userspace.go b/wgengine/userspace.go index b9c0e911e..010592aa8 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -378,15 +378,20 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, dnsDomains []string, local // TODO(apenwarr): only handling the first local address. // Currently we never use more than one anyway. - var cidr wgcfg.CIDR - if len(cfg.Addresses) > 0 { - cidr = cfg.Addresses[0] - // TODO(apenwarr): this shouldn't be hardcoded in the client - cidr.Mask = 10 // route the whole cgnat range + var addrs []wgcfg.CIDR + for _, addr := range cfg.Addresses { + addrs = append(addrs, wgcfg.CIDR{ + IP: addr.IP, + // TODO(apenwarr): this shouldn't be hardcoded in the client + // TODO(danderson): fairly sure we can make this a /32 or + // /128 based on address family. Need to check behavior on + // !linux OSes. + Mask: 10, + }) } rs := router.RouteSettings{ - LocalAddr: cidr, + LocalAddrs: addrs, Cfg: cfg, DNS: cfg.DNS, DNSDomains: dnsDomains, @@ -403,7 +408,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, dnsDomains []string, local rss := rs.OnlyRelevantParts() if rss != e.lastRoutes { e.logf("wgengine: Reconfig: reconfiguring router. la=%v dns=%v dom=%v; new routes: %v", - rs.LocalAddr, rs.DNS, rs.DNSDomains, rss) + rs.LocalAddrs, rs.DNS, rs.DNSDomains, rss) e.lastRoutes = rss err = e.router.SetRoutes(rs) if err != nil {