|
|
|
@ -306,8 +306,10 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
}
|
|
|
|
|
if st.NetMap != nil {
|
|
|
|
|
if b.keepOneExitNodeLocked(st.NetMap) {
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
}
|
|
|
|
|
b.setNetMapLocked(st.NetMap)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if st.URL != "" {
|
|
|
|
|
b.authURL = st.URL
|
|
|
|
@ -365,6 +367,57 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|
|
|
|
b.authReconfig()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// keepOneExitNodeLocked edits nm to retain only the default
|
|
|
|
|
// routes provided by the exit node specified in b.prefs. It returns
|
|
|
|
|
// whether prefs was mutated as part of the process, due to an exit
|
|
|
|
|
// node IP being converted into a node ID.
|
|
|
|
|
func (b *LocalBackend) keepOneExitNodeLocked(nm *controlclient.NetworkMap) (prefsChanged bool) {
|
|
|
|
|
if b.prefs.ExitNodeID == "" && b.prefs.ExitNodeIP.IsZero() {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have a desired IP on file, try to find the corresponding
|
|
|
|
|
// node.
|
|
|
|
|
if !b.prefs.ExitNodeIP.IsZero() {
|
|
|
|
|
// IP takes precedence over ID, so if both are set, clear ID.
|
|
|
|
|
if b.prefs.ExitNodeID != "" {
|
|
|
|
|
b.prefs.ExitNodeID = ""
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
peerLoop:
|
|
|
|
|
for _, peer := range nm.Peers {
|
|
|
|
|
for _, addr := range peer.Addresses {
|
|
|
|
|
if !addr.IsSingleIP() || addr.IP != b.prefs.ExitNodeIP {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// Found the node being referenced, upgrade prefs to
|
|
|
|
|
// reference it directly for next time.
|
|
|
|
|
b.prefs.ExitNodeID = peer.StableID
|
|
|
|
|
b.prefs.ExitNodeIP = netaddr.IP{}
|
|
|
|
|
prefsChanged = true
|
|
|
|
|
break peerLoop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// At this point, we have a node ID if the requested node is in
|
|
|
|
|
// the netmap. If not, the ID will be empty, and we'll strip out
|
|
|
|
|
// all default routes.
|
|
|
|
|
for _, peer := range nm.Peers {
|
|
|
|
|
out := peer.AllowedIPs[:0]
|
|
|
|
|
for _, allowedIP := range peer.AllowedIPs {
|
|
|
|
|
if allowedIP.Bits == 0 && peer.StableID != b.prefs.ExitNodeID {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
out = append(out, allowedIP)
|
|
|
|
|
}
|
|
|
|
|
peer.AllowedIPs = out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return prefsChanged
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setWgengineStatus is the callback by the wireguard engine whenever it posts a new status.
|
|
|
|
|
// This updates the endpoints both in the backend and in the control client.
|
|
|
|
|
func (b *LocalBackend) setWgengineStatus(s *wgengine.Status, err error) {
|
|
|
|
@ -1203,8 +1256,6 @@ func (b *LocalBackend) authReconfig() {
|
|
|
|
|
|
|
|
|
|
var flags controlclient.WGConfigFlags
|
|
|
|
|
if uc.RouteAll {
|
|
|
|
|
flags |= controlclient.AllowDefaultRoute
|
|
|
|
|
// TODO(apenwarr): Make subnet routes a different pref?
|
|
|
|
|
flags |= controlclient.AllowSubnetRoutes
|
|
|
|
|
}
|
|
|
|
|
if uc.AllowSingleHosts {
|
|
|
|
@ -1256,6 +1307,11 @@ func magicDNSRootDomains(nm *controlclient.NetworkMap) []string {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
ipv4Default = netaddr.MustParseIPPrefix("0.0.0.0/0")
|
|
|
|
|
ipv6Default = netaddr.MustParseIPPrefix("::/0")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// routerConfig produces a router.Config from a wireguard config and IPN prefs.
|
|
|
|
|
func routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs) *router.Config {
|
|
|
|
|
rs := &router.Config{
|
|
|
|
@ -1269,6 +1325,32 @@ func routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs) *router.Config {
|
|
|
|
|
rs.Routes = append(rs.Routes, unmapIPPrefixes(peer.AllowedIPs)...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sanity check: we expect the control server to program both a v4
|
|
|
|
|
// and a v6 default route, if default routing is on. Fill in
|
|
|
|
|
// blackhole routes appropriately if we're missing some. This is
|
|
|
|
|
// likely to break some functionality, but if the user expressed a
|
|
|
|
|
// preference for routing remotely, we want to avoid leaking
|
|
|
|
|
// traffic at the expense of functionality.
|
|
|
|
|
if prefs.ExitNodeID != "" || !prefs.ExitNodeIP.IsZero() {
|
|
|
|
|
var default4, default6 bool
|
|
|
|
|
for _, route := range rs.Routes {
|
|
|
|
|
if route == ipv4Default {
|
|
|
|
|
default4 = true
|
|
|
|
|
} else if route == ipv6Default {
|
|
|
|
|
default6 = true
|
|
|
|
|
}
|
|
|
|
|
if default4 && default6 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !default4 {
|
|
|
|
|
rs.Routes = append(rs.Routes, ipv4Default)
|
|
|
|
|
}
|
|
|
|
|
if !default6 {
|
|
|
|
|
rs.Routes = append(rs.Routes, ipv6Default)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rs.Routes = append(rs.Routes, netaddr.IPPrefix{
|
|
|
|
|
IP: tsaddr.TailscaleServiceIP(),
|
|
|
|
|
Bits: 32,
|
|
|
|
|