ipn/ipnlocal: only filter out default routes when computing the local wg config.

UIs need to see the full unedited netmap in order to know what exit nodes they
can offer to the user.

Signed-off-by: David Anderson <danderson@tailscale.com>
pull/1302/head
David Anderson 3 years ago committed by Dave Anderson
parent ebf3f2fd9f
commit 2404c0ffad

@ -310,7 +310,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
prefsChanged = true prefsChanged = true
} }
if st.NetMap != nil { if st.NetMap != nil {
if b.keepOneExitNodeLocked(st.NetMap) { if b.findExitNodeID(st.NetMap) {
prefsChanged = true prefsChanged = true
} }
b.setNetMapLocked(st.NetMap) b.setNetMapLocked(st.NetMap)
@ -371,51 +371,35 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
b.authReconfig() b.authReconfig()
} }
// keepOneExitNodeLocked edits nm to retain only the default // findExitNodeID updates b.prefs to reference an exit node by ID,
// routes provided by the exit node specified in b.prefs. It returns // rather than by IP. It returns whether prefs was mutated.
// whether prefs was mutated as part of the process, due to an exit func (b *LocalBackend) findExitNodeID(nm *netmap.NetworkMap) (prefsChanged bool) {
// node IP being converted into a node ID.
func (b *LocalBackend) keepOneExitNodeLocked(nm *netmap.NetworkMap) (prefsChanged bool) {
// If we have a desired IP on file, try to find the corresponding // If we have a desired IP on file, try to find the corresponding
// node. // node.
if !b.prefs.ExitNodeIP.IsZero() { if b.prefs.ExitNodeIP.IsZero() {
// IP takes precedence over ID, so if both are set, clear ID. return false
if b.prefs.ExitNodeID != "" { }
b.prefs.ExitNodeID = ""
prefsChanged = true
}
peerLoop: // IP takes precedence over ID, so if both are set, clear ID.
for _, peer := range nm.Peers { if b.prefs.ExitNodeID != "" {
for _, addr := range peer.Addresses { b.prefs.ExitNodeID = ""
if !addr.IsSingleIP() || addr.IP != b.prefs.ExitNodeIP { prefsChanged = true
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 { for _, peer := range nm.Peers {
out := peer.AllowedIPs[:0] for _, addr := range peer.Addresses {
for _, allowedIP := range peer.AllowedIPs { if !addr.IsSingleIP() || addr.IP != b.prefs.ExitNodeIP {
if allowedIP.Bits == 0 && peer.StableID != b.prefs.ExitNodeID {
continue continue
} }
out = append(out, allowedIP) // Found the node being referenced, upgrade prefs to
// reference it directly for next time.
b.prefs.ExitNodeID = peer.StableID
b.prefs.ExitNodeIP = netaddr.IP{}
return true
} }
peer.AllowedIPs = out
} }
return prefsChanged return false
} }
// setWgengineStatus is the callback by the wireguard engine whenever it posts a new status. // setWgengineStatus is the callback by the wireguard engine whenever it posts a new status.
@ -1274,7 +1258,7 @@ func (b *LocalBackend) authReconfig() {
} }
} }
cfg, err := nmcfg.WGCfg(nm, b.logf, flags) cfg, err := nmcfg.WGCfg(nm, b.logf, flags, uc.ExitNodeID)
if err != nil { if err != nil {
b.logf("wgcfg: %v", err) b.logf("wgcfg: %v", err)
return return

@ -297,7 +297,7 @@ func meshStacks(logf logger.Logf, ms []*magicStack) (cleanup func()) {
peerSet[key.Public(peer.Key)] = struct{}{} peerSet[key.Public(peer.Key)] = struct{}{}
} }
m.conn.UpdatePeers(peerSet) m.conn.UpdatePeers(peerSet)
wg, err := nmcfg.WGCfg(nm, logf, netmap.AllowSingleHosts) wg, err := nmcfg.WGCfg(nm, logf, netmap.AllowSingleHosts, "")
if err != nil { if err != nil {
// We're too far from the *testing.T to be graceful, // We're too far from the *testing.T to be graceful,
// blow up. Shouldn't happen anyway. // blow up. Shouldn't happen anyway.

@ -52,7 +52,7 @@ func cidrIsSubnet(node *tailcfg.Node, cidr netaddr.IPPrefix) bool {
} }
// WGCfg returns the NetworkMaps's Wireguard configuration. // WGCfg returns the NetworkMaps's Wireguard configuration.
func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags) (*wgcfg.Config, error) { func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags, exitNode tailcfg.StableNodeID) (*wgcfg.Config, error) {
cfg := &wgcfg.Config{ cfg := &wgcfg.Config{
Name: "tailscale", Name: "tailscale",
PrivateKey: wgcfg.PrivateKey(nm.PrivateKey), PrivateKey: wgcfg.PrivateKey(nm.PrivateKey),
@ -89,7 +89,10 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags)
} }
} }
for _, allowedIP := range peer.AllowedIPs { for _, allowedIP := range peer.AllowedIPs {
if allowedIP.IsSingleIP() && tsaddr.IsTailscaleIP(allowedIP.IP) && (flags&netmap.AllowSingleHosts) == 0 { if allowedIP.Bits == 0 && peer.StableID != exitNode {
logf("[v1] wgcfg: skipping unselected default route from %q (%v)", nodeDebugName(peer), peer.Key.ShortString())
continue
} else if allowedIP.IsSingleIP() && tsaddr.IsTailscaleIP(allowedIP.IP) && (flags&netmap.AllowSingleHosts) == 0 {
logf("[v1] wgcfg: skipping node IP %v from %q (%v)", logf("[v1] wgcfg: skipping node IP %v from %q (%v)",
allowedIP.IP, nodeDebugName(peer), peer.Key.ShortString()) allowedIP.IP, nodeDebugName(peer), peer.Key.ShortString())
continue continue

Loading…
Cancel
Save