From 629801870495de58210aacc5627c8e281a5c8f61 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 3 Aug 2020 10:00:16 -0700 Subject: [PATCH] control/controlclient: print disco keys NetworkMap diffs (debug change only) NetworkMap text diffs being empty were currently used to short-circuit calling magicsock's SetNetworkMap (via Engine.SetNetworkMap), but that went away in c7582dc2 (0.100.0-230) Prior to c7582dc2 (notably, in 0.100.0-225 and below, down to 0.100.0), a change in only disco key (as when a node restarts) but without endpoint changes (as would happen for a client not behind a NAT with random ports) could result in a "netmap diff: (none)" being printed, as well as Engine.SetNetworkMap being skipped, leading to broken discovery endpoints. c7582dc2 fixed the Engine.SetNetworkMap skippage. This change fixes the "netmap diff: (none)" print so we'll actually see when a peer restarts with identical endpoints but a new discovery key. --- control/controlclient/netmap.go | 11 ++++- control/controlclient/netmap_test.go | 67 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/control/controlclient/netmap.go b/control/controlclient/netmap.go index 1ef0bb12f..d1a0b9d37 100644 --- a/control/controlclient/netmap.go +++ b/control/controlclient/netmap.go @@ -132,12 +132,18 @@ func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) { if strings.HasPrefix(derp, derpPrefix) { derp = "D" + derp[len(derpPrefix):] } + var discoShort string + if !p.DiscoKey.IsZero() { + discoShort = p.DiscoKey.ShortString() + " " + } // Most of the time, aip is just one element, so format the // table to look good in that case. This will also make multi- // subnet nodes stand out visually. - fmt.Fprintf(buf, " %v %-2v %-15v : %v\n", - p.Key.ShortString(), derp, + fmt.Fprintf(buf, " %v %s%-2v %-15v : %v\n", + p.Key.ShortString(), + discoShort, + derp, strings.Join(aip, " "), strings.Join(ep, " ")) } @@ -146,6 +152,7 @@ func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) { func nodeConciseEqual(a, b *tailcfg.Node) bool { return a.Key == b.Key && a.DERP == b.DERP && + a.DiscoKey == b.DiscoKey && eqCIDRsIgnoreNil(a.AllowedIPs, b.AllowedIPs) && eqStringsIgnoreNil(a.Endpoints, b.Endpoints) } diff --git a/control/controlclient/netmap_test.go b/control/controlclient/netmap_test.go index 33cfdd201..6a386589a 100644 --- a/control/controlclient/netmap_test.go +++ b/control/controlclient/netmap_test.go @@ -5,8 +5,10 @@ package controlclient import ( + "encoding/hex" "testing" + "github.com/tailscale/wireguard-go/wgcfg" "tailscale.com/tailcfg" ) @@ -17,6 +19,15 @@ func testNodeKey(b byte) (ret tailcfg.NodeKey) { return } +func testDiscoKey(hexPrefix string) (ret tailcfg.DiscoKey) { + b, err := hex.DecodeString(hexPrefix) + if err != nil { + panic(err) + } + copy(ret[:], b) + return +} + func TestNetworkMapConcise(t *testing.T) { for _, tt := range []struct { name string @@ -202,6 +213,62 @@ func TestConciseDiffFrom(t *testing.T) { }, want: "- [AQEBA] D1 : 192.168.0.100:12 192.168.0.100:12354\n- [AwMDA] D3 : 192.168.0.100:12 192.168.0.100:12354\n", }, + { + name: "peer_port_change", + a: &NetworkMap{ + NodeKey: testNodeKey(1), + Peers: []*tailcfg.Node{ + { + ID: 2, + Key: testNodeKey(2), + DERP: "127.3.3.40:2", + Endpoints: []string{"192.168.0.100:12", "1.1.1.1:1"}, + }, + }, + }, + b: &NetworkMap{ + NodeKey: testNodeKey(1), + Peers: []*tailcfg.Node{ + { + ID: 2, + Key: testNodeKey(2), + DERP: "127.3.3.40:2", + Endpoints: []string{"192.168.0.100:12", "1.1.1.1:2"}, + }, + }, + }, + want: "- [AgICA] D2 : 192.168.0.100:12 1.1.1.1:1 \n+ [AgICA] D2 : 192.168.0.100:12 1.1.1.1:2 \n", + }, + { + name: "disco_key_only_change", + a: &NetworkMap{ + NodeKey: testNodeKey(1), + Peers: []*tailcfg.Node{ + { + ID: 2, + Key: testNodeKey(2), + DERP: "127.3.3.40:2", + Endpoints: []string{"192.168.0.100:41641", "1.1.1.1:41641"}, + DiscoKey: testDiscoKey("f00f00f00f"), + AllowedIPs: []wgcfg.CIDR{{IP: wgcfg.IPv4(100, 102, 103, 104), Mask: 32}}, + }, + }, + }, + b: &NetworkMap{ + NodeKey: testNodeKey(1), + Peers: []*tailcfg.Node{ + { + ID: 2, + Key: testNodeKey(2), + DERP: "127.3.3.40:2", + Endpoints: []string{"192.168.0.100:41641", "1.1.1.1:41641"}, + DiscoKey: testDiscoKey("ba4ba4ba4b"), + AllowedIPs: []wgcfg.CIDR{{IP: wgcfg.IPv4(100, 102, 103, 104), Mask: 32}}, + }, + }, + }, + want: "- [AgICA] d:f00f00f00f000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n+ [AgICA] d:ba4ba4ba4b000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n", + }, } { t.Run(tt.name, func(t *testing.T) { var got string