diff --git a/overlay/tun_darwin.go b/overlay/tun_darwin.go index a0834590..3a7b85cd 100644 --- a/overlay/tun_darwin.go +++ b/overlay/tun_darwin.go @@ -271,6 +271,7 @@ func (t *tun) Activate() error { return t.addRoutes(false) } +// activate4 assigns our vpn address as a /32 and routes the vpn network to the tun explicitly. func (t *tun) activate4(network netip.Prefix) error { s, err := unix.Socket( unix.AF_INET, @@ -297,22 +298,32 @@ func (t *tun) activate4(network netip.Prefix) error { MaskAddr: unix.RawSockaddrInet4{ Len: unix.SizeofSockaddrInet4, Family: unix.AF_INET, - Addr: prefixToMask(network).As4(), + Addr: [4]byte{255, 255, 255, 255}, //always make the address a /32 }, } + // On Darwin, VPNs don't edit the routing table directly. + // A network extension hands its routes to the system, and configd installs them. + // configd replaces any route already holding the same prefix, including ours. + // As an example, Tailscale with an exit node treats any interface prefix wider than one address as a LAN. + // With LAN access off, it routes each LAN into Tailscale's utun. + // With LAN access on, it excludes each LAN from its tunnel. + // configd routes an excluded prefix like its own routes would, ignoring ours, so it goes out the default route. + // Either way our route is replaced, and traffic for the vpn network no longer reaches nebula. + // A single address isn't a LAN to Tailscale, so our route is left alone. + // We route the vpn network to the tun explicitly instead. + if err := ioctl(uintptr(s), unix.SIOCAIFADDR, uintptr(unsafe.Pointer(&ifr))); err != nil { return fmt.Errorf("failed to set tun v4 address: %s", err) } - err = addRoute(network, t.linkAddr.Load()) - if err != nil { - return err + if err := addRoute(network, t.linkAddr.Load()); err != nil { + return fmt.Errorf("failed to add route for %v: %w", network.Masked(), err) } - return nil } +// activate6 is activate4 for IPv6 func (t *tun) activate6(network netip.Prefix) error { s, err := unix.Socket( unix.AF_INET6, @@ -334,20 +345,24 @@ func (t *tun) activate6(network netip.Prefix) error { PrefixMask: unix.RawSockaddrInet6{ Len: unix.SizeofSockaddrInet6, Family: unix.AF_INET6, - Addr: prefixToMask(network).As16(), + // Always set the netmask to be a /128. See activate4 for why we do this. + Addr: [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, }, Lifetime: addrLifetime{ // never expires Vltime: 0xffffffff, Pltime: 0xffffffff, }, - Flags: _IN6_IFF_NODAD, + Flags: _IN6_IFF_NODAD, // No DAD, a utun has no neighbors. } if err := ioctl(uintptr(s), _SIOCAIFADDR_IN6, uintptr(unsafe.Pointer(&ifr))); err != nil { return fmt.Errorf("failed to set tun address: %s", err) } + if err := addRoute(network, t.linkAddr.Load()); err != nil { + return fmt.Errorf("failed to add route for %v: %w", network.Masked(), err) + } return nil }