Skip to content

Commit 8d0c690

Browse files
committed
net/netcheck: clean up ICMP probe AddrPort lookup
Fixes tailscale#14200 Change-Id: Ib086814cf63dda5de021403fe1db4fb2a798eaae Signed-off-by: Brad Fitzpatrick <[email protected]>
1 parent 24095e4 commit 8d0c690

File tree

2 files changed

+36
-29
lines changed

2 files changed

+36
-29
lines changed

net/netcheck/netcheck.go

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,17 +1221,19 @@ func (c *Client) measureICMPLatency(ctx context.Context, reg *tailcfg.DERPRegion
12211221
// Try pinging the first node in the region
12221222
node := reg.Nodes[0]
12231223

1224-
// Get the IPAddr by asking for the UDP address that we would use for
1225-
// STUN and then using that IP.
1226-
//
1227-
// TODO(andrew-d): this is a bit ugly
1228-
nodeAddr := c.nodeAddr(ctx, node, probeIPv4)
1229-
if !nodeAddr.IsValid() {
1224+
if node.STUNPort < 0 {
1225+
// If STUN is disabled on a node, interpret that as meaning don't measure latency.
1226+
return 0, false, nil
1227+
}
1228+
const unusedPort = 0
1229+
stunAddrPort, ok := c.nodeAddrPort(ctx, node, unusedPort, probeIPv4)
1230+
if !ok {
12301231
return 0, false, fmt.Errorf("no address for node %v (v4-for-icmp)", node.Name)
12311232
}
1233+
ip := stunAddrPort.Addr()
12321234
addr := &net.IPAddr{
1233-
IP: net.IP(nodeAddr.Addr().AsSlice()),
1234-
Zone: nodeAddr.Addr().Zone(),
1235+
IP: net.IP(ip.AsSlice()),
1236+
Zone: ip.Zone(),
12351237
}
12361238

12371239
// Use the unique node.Name field as the packet data to reduce the
@@ -1478,8 +1480,8 @@ func (rs *reportState) runProbe(ctx context.Context, dm *tailcfg.DERPMap, probe
14781480
return
14791481
}
14801482

1481-
addr := c.nodeAddr(ctx, node, probe.proto)
1482-
if !addr.IsValid() {
1483+
addr, ok := c.nodeAddrPort(ctx, node, node.STUNPort, probe.proto)
1484+
if !ok {
14831485
c.logf("netcheck.runProbe: named node %q has no %v address", probe.node, probe.proto)
14841486
return
14851487
}
@@ -1528,12 +1530,17 @@ func (rs *reportState) runProbe(ctx context.Context, dm *tailcfg.DERPMap, probe
15281530
c.vlogf("sent to %v", addr)
15291531
}
15301532

1531-
// proto is 4 or 6
1532-
// If it returns nil, the node is skipped.
1533-
func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeProto) (ap netip.AddrPort) {
1534-
port := cmp.Or(n.STUNPort, 3478)
1533+
// nodeAddrPort returns the IP:port to send a STUN queries to for a given node.
1534+
//
1535+
// The provided port should be n.STUNPort, which may be negative to disable STUN.
1536+
// If STUN is disabled for this node, it returns ok=false.
1537+
// The port parameter is separate for the ICMP caller to provide a fake value.
1538+
//
1539+
// proto is [probeIPv4] or [probeIPv6].
1540+
func (c *Client) nodeAddrPort(ctx context.Context, n *tailcfg.DERPNode, port int, proto probeProto) (_ netip.AddrPort, ok bool) {
1541+
var zero netip.AddrPort
15351542
if port < 0 || port > 1<<16-1 {
1536-
return
1543+
return zero, false
15371544
}
15381545
if n.STUNTestIP != "" {
15391546
ip, err := netip.ParseAddr(n.STUNTestIP)
@@ -1546,28 +1553,28 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
15461553
if proto == probeIPv6 && ip.Is4() {
15471554
return
15481555
}
1549-
return netip.AddrPortFrom(ip, uint16(port))
1556+
return netip.AddrPortFrom(ip, uint16(port)), true
15501557
}
15511558

15521559
switch proto {
15531560
case probeIPv4:
15541561
if n.IPv4 != "" {
15551562
ip, _ := netip.ParseAddr(n.IPv4)
15561563
if !ip.Is4() {
1557-
return
1564+
return zero, false
15581565
}
1559-
return netip.AddrPortFrom(ip, uint16(port))
1566+
return netip.AddrPortFrom(ip, uint16(port)), true
15601567
}
15611568
case probeIPv6:
15621569
if n.IPv6 != "" {
15631570
ip, _ := netip.ParseAddr(n.IPv6)
15641571
if !ip.Is6() {
1565-
return
1572+
return zero, false
15661573
}
1567-
return netip.AddrPortFrom(ip, uint16(port))
1574+
return netip.AddrPortFrom(ip, uint16(port)), true
15681575
}
15691576
default:
1570-
return
1577+
return zero, false
15711578
}
15721579

15731580
// The default lookup function if we don't set UseDNSCache is to use net.DefaultResolver.
@@ -1609,13 +1616,13 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
16091616
addrs, err := lookupIPAddr(ctx, n.HostName)
16101617
for _, a := range addrs {
16111618
if (a.Is4() && probeIsV4) || (a.Is6() && !probeIsV4) {
1612-
return netip.AddrPortFrom(a, uint16(port))
1619+
return netip.AddrPortFrom(a, uint16(port)), true
16131620
}
16141621
}
16151622
if err != nil {
16161623
c.logf("netcheck: DNS lookup error for %q (node %q region %v): %v", n.HostName, n.Name, n.RegionID, err)
16171624
}
1618-
return
1625+
return zero, false
16191626
}
16201627

16211628
func regionHasDERPNode(r *tailcfg.DERPRegion) bool {

net/netcheck/netcheck_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -887,8 +887,8 @@ func TestNodeAddrResolve(t *testing.T) {
887887
c.UseDNSCache = tt
888888

889889
t.Run("IPv4", func(t *testing.T) {
890-
ap := c.nodeAddr(ctx, dn, probeIPv4)
891-
if !ap.IsValid() {
890+
ap, ok := c.nodeAddrPort(ctx, dn, dn.STUNPort, probeIPv4)
891+
if !ok {
892892
t.Fatal("expected valid AddrPort")
893893
}
894894
if !ap.Addr().Is4() {
@@ -902,8 +902,8 @@ func TestNodeAddrResolve(t *testing.T) {
902902
t.Skipf("IPv6 may not work on this machine")
903903
}
904904

905-
ap := c.nodeAddr(ctx, dn, probeIPv6)
906-
if !ap.IsValid() {
905+
ap, ok := c.nodeAddrPort(ctx, dn, dn.STUNPort, probeIPv6)
906+
if !ok {
907907
t.Fatal("expected valid AddrPort")
908908
}
909909
if !ap.Addr().Is6() {
@@ -912,8 +912,8 @@ func TestNodeAddrResolve(t *testing.T) {
912912
t.Logf("got IPv6 addr: %v", ap)
913913
})
914914
t.Run("IPv6 Failure", func(t *testing.T) {
915-
ap := c.nodeAddr(ctx, dnV4Only, probeIPv6)
916-
if ap.IsValid() {
915+
ap, ok := c.nodeAddrPort(ctx, dnV4Only, dn.STUNPort, probeIPv6)
916+
if ok {
917917
t.Fatalf("expected no addr but got: %v", ap)
918918
}
919919
t.Logf("correctly got invalid addr")

0 commit comments

Comments
 (0)