net/portmapper: don't return unspecified/local external IPs

We were previously not checking that the external IP that we got back
from a UPnP portmap was a valid endpoint; add minimal validation that
this endpoint is something that is routeable by another host.

Updates tailscale/corp#23538

Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
Change-Id: Id9649e7683394aced326d5348f4caa24d0efd532
This commit is contained in:
Andrew Dunham
2024-10-01 12:17:59 -04:00
parent 1eaad7d3de
commit 16ef88754d
2 changed files with 92 additions and 21 deletions

View File

@@ -638,6 +638,19 @@ func (c *Client) tryUPnPPortmapWithDevice(
return netip.AddrPort{}, nil, err
}
// Do a bit of validation on the external IP; we've seen cases where
// UPnP devices return the public IP 0.0.0.0, which obviously doesn't
// work as an endpoint.
//
// See: https://github.com/tailscale/corp/issues/23538
if externalIP.IsUnspecified() {
c.logf("UPnP returned unspecified external IP %v", externalIP)
return netip.AddrPort{}, nil, fmt.Errorf("UPnP returned unspecified external IP")
} else if externalIP.IsLoopback() {
c.logf("UPnP returned loopback external IP %v", externalIP)
return netip.AddrPort{}, nil, fmt.Errorf("UPnP returned loopback external IP")
}
return netip.AddrPortFrom(externalIP, newPort), client, nil
}