summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorClaire Wang <claire@tailscale.com>2024-02-09 14:54:44 -0500
committerClaire Wang <claire@tailscale.com>2024-02-09 14:54:44 -0500
commit4684272ae0ecfc9a37add5494ff2e31c69a9bce0 (patch)
tree265aa2b642a76ed6e713f9a253aaa102e4ebbc18
parentc3b5ae55e60548fb18e5183927f0185b60fd0a26 (diff)
downloadtailscale-clairew/client-suggest-node-poc.tar.xz
tailscale-clairew/client-suggest-node-poc.zip
-rw-r--r--ipn/ipnlocal/local.go15
-rw-r--r--net/netcheck/netcheck.go45
-rw-r--r--wgengine/magicsock/magicsock.go14
3 files changed, 67 insertions, 7 deletions
diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go
index a1a4b6616..9b489a282 100644
--- a/ipn/ipnlocal/local.go
+++ b/ipn/ipnlocal/local.go
@@ -5920,19 +5920,24 @@ func (b *LocalBackend) SuggestExitNode() (*tailcfg.StableNodeID, error) {
return nil, errors.New("no netmap")
}
peers := netMap.Peers
- lastReport := b.MagicConn().GetLastNetcheckReport()
+ lastReport := b.MagicConn().GetLastNetcheckReport(b.ctx)
var fastestRegionLatency = time.Duration(math.MaxInt64)
var preferredExitNodeID tailcfg.StableNodeID
peerRegionMap := make(map[int][]tailcfg.NodeView)
+ b.logf("preferred self node derp %v", lastReport.PreferredDERP)
+ b.logf("preferred self node derp name %v", netMap.DERPMap.Regions[lastReport.PreferredDERP])
+ var mullvadCandidates []*tailcfg.NodeView
for _, peer := range peers {
if online := peer.Online(); online != nil && !*online {
continue
}
- if peer.Hostinfo().Location() != nil {
- b.logf("location %v %v", peer.Hostinfo().Location().Longitude, peer.Hostinfo().Location().Latitude)
- }
if tsaddr.ContainsExitRoutes(peer.AllowedIPs()) {
ipp, _ := netip.ParseAddrPort(peer.DERP())
+ if peer.DERP() == "" {
+ if peer.Hostinfo().Location().Country == "USA" {
+ mullvadCandidates = append(mullvadCandidates, &peer)
+ }
+ }
regionID := int(ipp.Port())
regionLatency, ok := lastReport.RegionLatency[regionID]
peerRegionMap[regionID] = append(peerRegionMap[regionID], peer)
@@ -5948,6 +5953,8 @@ func (b *LocalBackend) SuggestExitNode() (*tailcfg.StableNodeID, error) {
}
}
b.logf("self derp %v", b.netMap.SelfNode.DERP())
+ result := b.MagicConn().MeasureNodeICMPLatency(b.ctx, mullvadCandidates)
+ b.logf("result %v", result)
ipp, _ := netip.ParseAddrPort(netMap.SelfNode.DERP())
selfDerpRegionID := int(ipp.Port())
b.logf("self derp region id %v", selfDerpRegionID)
diff --git a/net/netcheck/netcheck.go b/net/netcheck/netcheck.go
index 0cea345c3..8b1a4ae85 100644
--- a/net/netcheck/netcheck.go
+++ b/net/netcheck/netcheck.go
@@ -1730,3 +1730,48 @@ var (
metricSTUNRecv6 = clientmetric.NewCounter("netcheck_stun_recv_ipv6")
metricHTTPSend = clientmetric.NewCounter("netcheck_https_measure")
)
+
+func (c *Client) MeasureICMPLatency(ctx context.Context, candidates []*tailcfg.NodeView) map[*tailcfg.NodeView]time.Duration {
+ p := ping.New(ctx, c.logf, netns.Listener(c.logf, c.NetMon))
+ defer p.Close()
+ var wg sync.WaitGroup
+ var results map[*tailcfg.NodeView]time.Duration
+ wg.Add(len(candidates))
+ for _, candidate := range candidates {
+ go func(candidate *tailcfg.NodeView) {
+ defer wg.Done()
+ if d, err := c.measureNodeICMPLatency(ctx, candidate, p); err != nil {
+ c.logf("error %v node %v", err, candidate.Name())
+ } else {
+ results[candidate] = d
+ c.logf("results %v", results)
+ }
+ }(candidate)
+ }
+
+ wg.Wait()
+ return results
+}
+
+func (c *Client) measureNodeICMPLatency(ctx context.Context, node *tailcfg.NodeView, p *ping.Pinger) (time.Duration, error) {
+ // Get the IPAddr by asking for the UDP address that we would use for
+ // STUN and then using that IP.
+ //
+ // TODO(andrew-d): this is a bit ugly
+ var nodeAddr netip.Addr
+ for i := range node.Addresses().LenIter() {
+ p := node.Addresses().At(i)
+ if p.Addr().Is4() {
+ nodeAddr = p.Addr()
+ break
+ }
+ }
+
+ addr := &net.IPAddr{
+ IP: net.IP(nodeAddr.AsSlice()),
+ Zone: nodeAddr.Zone(),
+ }
+ // Use the unique node.Name field as the packet data to reduce the
+ // likelihood that we get a mismatched echo response.
+ return p.Send(ctx, addr, []byte(node.Name()))
+}
diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go
index 7912e6256..aca47c584 100644
--- a/wgengine/magicsock/magicsock.go
+++ b/wgengine/magicsock/magicsock.go
@@ -3009,7 +3009,15 @@ func getPeerMTUsProbedMetric(mtu tstun.WireMTU) *clientmetric.Metric {
return mm
}
-func (c *Conn) GetLastNetcheckReport() *netcheck.Report {
- report, _ := c.updateNetInfo(c.connCtx)
- return report
+func (c *Conn) GetLastNetcheckReport(ctx context.Context) *netcheck.Report {
+ nr, err := c.updateNetInfo(ctx)
+ if err != nil {
+ c.logf("magicsock.Conn.determineEndpoints: updateNetInfo: %v", err)
+ return nil
+ }
+ return nr
+}
+
+func (c *Conn) MeasureNodeICMPLatency(ctx context.Context, candidates []*tailcfg.NodeView) map[*tailcfg.NodeView]time.Duration {
+ return c.netChecker.MeasureICMPLatency(ctx, candidates)
}