clairew/client-suggest-node-poc
Claire Wang 3 months ago
parent c3b5ae55e6
commit 4684272ae0

@ -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)

@ -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()))
}

@ -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)
}

Loading…
Cancel
Save