mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-13 22:47:30 +00:00
wgengine/magicsock: support self as candidate peer relay (#16499)
Updates tailscale/corp#30247 Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
@@ -2618,8 +2618,8 @@ func (c *Conn) onFilterUpdate(f FilterUpdate) {
|
||||
c.updateRelayServersSet(f.Filter, self, peers)
|
||||
}
|
||||
|
||||
// updateRelayServersSet iterates all peers, evaluating filt for each one in
|
||||
// order to determine which peers are relay server candidates. filt, self, and
|
||||
// updateRelayServersSet iterates all peers and self, evaluating filt for each
|
||||
// one in order to determine which are relay server candidates. filt, self, and
|
||||
// peers are passed as args (vs c.mu-guarded fields) to enable callers to
|
||||
// release c.mu before calling as this is O(m * n) (we iterate all cap rules 'm'
|
||||
// in filt for every peer 'n').
|
||||
@@ -2631,8 +2631,9 @@ func (c *Conn) onFilterUpdate(f FilterUpdate) {
|
||||
// the computed result over the eventbus instead.
|
||||
func (c *Conn) updateRelayServersSet(filt *filter.Filter, self tailcfg.NodeView, peers views.Slice[tailcfg.NodeView]) {
|
||||
relayServers := make(set.Set[netip.AddrPort])
|
||||
for _, peer := range peers.All() {
|
||||
peerAPI := peerAPIIfCandidateRelayServer(filt, self, peer)
|
||||
nodes := append(peers.AsSlice(), self)
|
||||
for _, maybeCandidate := range nodes {
|
||||
peerAPI := peerAPIIfCandidateRelayServer(filt, self, maybeCandidate)
|
||||
if peerAPI.IsValid() {
|
||||
relayServers.Add(peerAPI)
|
||||
}
|
||||
@@ -2640,33 +2641,34 @@ func (c *Conn) updateRelayServersSet(filt *filter.Filter, self tailcfg.NodeView,
|
||||
c.relayManager.handleRelayServersSet(relayServers)
|
||||
}
|
||||
|
||||
// peerAPIIfCandidateRelayServer returns the peer API address of peer if it
|
||||
// is considered to be a candidate relay server upon evaluation against filt and
|
||||
// self, otherwise it returns a zero value.
|
||||
func peerAPIIfCandidateRelayServer(filt *filter.Filter, self, peer tailcfg.NodeView) netip.AddrPort {
|
||||
// peerAPIIfCandidateRelayServer returns the peer API address of maybeCandidate
|
||||
// if it is considered to be a candidate relay server upon evaluation against
|
||||
// filt and self, otherwise it returns a zero value. self and maybeCandidate
|
||||
// may be equal.
|
||||
func peerAPIIfCandidateRelayServer(filt *filter.Filter, self, maybeCandidate tailcfg.NodeView) netip.AddrPort {
|
||||
if filt == nil ||
|
||||
!self.Valid() ||
|
||||
!peer.Valid() ||
|
||||
!capVerIsRelayServerCapable(peer.Cap()) ||
|
||||
!peer.Hostinfo().Valid() {
|
||||
!maybeCandidate.Valid() ||
|
||||
!capVerIsRelayServerCapable(maybeCandidate.Cap()) ||
|
||||
!maybeCandidate.Hostinfo().Valid() {
|
||||
return netip.AddrPort{}
|
||||
}
|
||||
for _, peerPrefix := range peer.Addresses().All() {
|
||||
if !peerPrefix.IsSingleIP() {
|
||||
for _, maybeCandidatePrefix := range maybeCandidate.Addresses().All() {
|
||||
if !maybeCandidatePrefix.IsSingleIP() {
|
||||
continue
|
||||
}
|
||||
peerAddr := peerPrefix.Addr()
|
||||
maybeCandidateAddr := maybeCandidatePrefix.Addr()
|
||||
for _, selfPrefix := range self.Addresses().All() {
|
||||
if !selfPrefix.IsSingleIP() {
|
||||
continue
|
||||
}
|
||||
selfAddr := selfPrefix.Addr()
|
||||
if selfAddr.BitLen() == peerAddr.BitLen() { // same address family
|
||||
if filt.CapsWithValues(peerAddr, selfAddr).HasCapability(tailcfg.PeerCapabilityRelayTarget) {
|
||||
for _, s := range peer.Hostinfo().Services().All() {
|
||||
if peerAddr.Is4() && s.Proto == tailcfg.PeerAPI4 ||
|
||||
peerAddr.Is6() && s.Proto == tailcfg.PeerAPI6 {
|
||||
return netip.AddrPortFrom(peerAddr, s.Port)
|
||||
if selfAddr.BitLen() == maybeCandidateAddr.BitLen() { // same address family
|
||||
if filt.CapsWithValues(maybeCandidateAddr, selfAddr).HasCapability(tailcfg.PeerCapabilityRelayTarget) {
|
||||
for _, s := range maybeCandidate.Hostinfo().Services().All() {
|
||||
if maybeCandidateAddr.Is4() && s.Proto == tailcfg.PeerAPI4 ||
|
||||
maybeCandidateAddr.Is6() && s.Proto == tailcfg.PeerAPI6 {
|
||||
return netip.AddrPortFrom(maybeCandidateAddr, s.Port)
|
||||
}
|
||||
}
|
||||
return netip.AddrPort{} // no peerAPI
|
||||
@@ -2674,10 +2676,11 @@ func peerAPIIfCandidateRelayServer(filt *filter.Filter, self, peer tailcfg.NodeV
|
||||
// [nodeBackend.peerCapsLocked] only returns/considers the
|
||||
// [tailcfg.PeerCapMap] between the passed src and the
|
||||
// _first_ host (/32 or /128) address for self. We are
|
||||
// consistent with that behavior here. If self and peer
|
||||
// host addresses are of the same address family they either
|
||||
// have the capability or not. We do not check against
|
||||
// additional host addresses of the same address family.
|
||||
// consistent with that behavior here. If self and
|
||||
// maybeCandidate host addresses are of the same address
|
||||
// family they either have the capability or not. We do not
|
||||
// check against additional host addresses of the same
|
||||
// address family.
|
||||
return netip.AddrPort{}
|
||||
}
|
||||
}
|
||||
|
@@ -3385,16 +3385,7 @@ func Test_virtualNetworkID(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
selfOnlyIPv4 := &tailcfg.Node{
|
||||
Cap: math.MinInt32,
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("1.1.1.1/32"),
|
||||
},
|
||||
}
|
||||
selfOnlyIPv6 := selfOnlyIPv4.Clone()
|
||||
selfOnlyIPv6.Addresses[0] = netip.MustParsePrefix("::1/128")
|
||||
|
||||
peerHostinfo := &tailcfg.Hostinfo{
|
||||
hostInfo := &tailcfg.Hostinfo{
|
||||
Services: []tailcfg.Service{
|
||||
{
|
||||
Proto: tailcfg.PeerAPI4,
|
||||
@@ -3406,12 +3397,23 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
selfOnlyIPv4 := &tailcfg.Node{
|
||||
Cap: math.MinInt32,
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("1.1.1.1/32"),
|
||||
},
|
||||
Hostinfo: hostInfo.View(),
|
||||
}
|
||||
selfOnlyIPv6 := selfOnlyIPv4.Clone()
|
||||
selfOnlyIPv6.Addresses[0] = netip.MustParsePrefix("::1/128")
|
||||
|
||||
peerOnlyIPv4 := &tailcfg.Node{
|
||||
Cap: math.MinInt32,
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("2.2.2.2/32"),
|
||||
},
|
||||
Hostinfo: peerHostinfo.View(),
|
||||
Hostinfo: hostInfo.View(),
|
||||
}
|
||||
|
||||
peerOnlyIPv6 := peerOnlyIPv4.Clone()
|
||||
@@ -3424,11 +3426,11 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
peerOnlyIPv4NilHostinfo.Hostinfo = tailcfg.HostinfoView{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
filt *filter.Filter
|
||||
self tailcfg.NodeView
|
||||
peer tailcfg.NodeView
|
||||
want netip.AddrPort
|
||||
name string
|
||||
filt *filter.Filter
|
||||
self tailcfg.NodeView
|
||||
maybeCandidate tailcfg.NodeView
|
||||
want netip.AddrPort
|
||||
}{
|
||||
{
|
||||
name: "match v4",
|
||||
@@ -3443,9 +3445,26 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv4.View(),
|
||||
peer: peerOnlyIPv4.View(),
|
||||
want: netip.MustParseAddrPort("2.2.2.2:4"),
|
||||
self: selfOnlyIPv4.View(),
|
||||
maybeCandidate: peerOnlyIPv4.View(),
|
||||
want: netip.MustParseAddrPort("2.2.2.2:4"),
|
||||
},
|
||||
{
|
||||
name: "match v4 self",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{selfOnlyIPv4.Addresses[0]},
|
||||
Caps: []filtertype.CapMatch{
|
||||
{
|
||||
Dst: selfOnlyIPv4.Addresses[0],
|
||||
Cap: tailcfg.PeerCapabilityRelayTarget,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv4.View(),
|
||||
maybeCandidate: selfOnlyIPv4.View(),
|
||||
want: netip.AddrPortFrom(selfOnlyIPv4.Addresses[0].Addr(), 4),
|
||||
},
|
||||
{
|
||||
name: "match v6",
|
||||
@@ -3460,9 +3479,26 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv6.View(),
|
||||
peer: peerOnlyIPv6.View(),
|
||||
want: netip.MustParseAddrPort("[::2]:6"),
|
||||
self: selfOnlyIPv6.View(),
|
||||
maybeCandidate: peerOnlyIPv6.View(),
|
||||
want: netip.MustParseAddrPort("[::2]:6"),
|
||||
},
|
||||
{
|
||||
name: "match v6 self",
|
||||
filt: filter.New([]filtertype.Match{
|
||||
{
|
||||
Srcs: []netip.Prefix{selfOnlyIPv6.Addresses[0]},
|
||||
Caps: []filtertype.CapMatch{
|
||||
{
|
||||
Dst: selfOnlyIPv6.Addresses[0],
|
||||
Cap: tailcfg.PeerCapabilityRelayTarget,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv6.View(),
|
||||
maybeCandidate: selfOnlyIPv6.View(),
|
||||
want: netip.AddrPortFrom(selfOnlyIPv6.Addresses[0].Addr(), 6),
|
||||
},
|
||||
{
|
||||
name: "no match dst",
|
||||
@@ -3477,8 +3513,8 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv6.View(),
|
||||
peer: peerOnlyIPv6.View(),
|
||||
self: selfOnlyIPv6.View(),
|
||||
maybeCandidate: peerOnlyIPv6.View(),
|
||||
},
|
||||
{
|
||||
name: "no match peer cap",
|
||||
@@ -3493,8 +3529,8 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv6.View(),
|
||||
peer: peerOnlyIPv6.View(),
|
||||
self: selfOnlyIPv6.View(),
|
||||
maybeCandidate: peerOnlyIPv6.View(),
|
||||
},
|
||||
{
|
||||
name: "cap ver not relay capable",
|
||||
@@ -3509,14 +3545,14 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: peerOnlyIPv4.View(),
|
||||
peer: peerOnlyIPv4ZeroCapVer.View(),
|
||||
self: peerOnlyIPv4.View(),
|
||||
maybeCandidate: peerOnlyIPv4ZeroCapVer.View(),
|
||||
},
|
||||
{
|
||||
name: "nil filt",
|
||||
filt: nil,
|
||||
self: selfOnlyIPv4.View(),
|
||||
peer: peerOnlyIPv4.View(),
|
||||
name: "nil filt",
|
||||
filt: nil,
|
||||
self: selfOnlyIPv4.View(),
|
||||
maybeCandidate: peerOnlyIPv4.View(),
|
||||
},
|
||||
{
|
||||
name: "nil self",
|
||||
@@ -3531,8 +3567,8 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: tailcfg.NodeView{},
|
||||
peer: peerOnlyIPv4.View(),
|
||||
self: tailcfg.NodeView{},
|
||||
maybeCandidate: peerOnlyIPv4.View(),
|
||||
},
|
||||
{
|
||||
name: "nil peer",
|
||||
@@ -3547,8 +3583,8 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv4.View(),
|
||||
peer: tailcfg.NodeView{},
|
||||
self: selfOnlyIPv4.View(),
|
||||
maybeCandidate: tailcfg.NodeView{},
|
||||
},
|
||||
{
|
||||
name: "nil peer hostinfo",
|
||||
@@ -3563,13 +3599,13 @@ func Test_peerAPIIfCandidateRelayServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, nil, nil, nil, nil, nil),
|
||||
self: selfOnlyIPv4.View(),
|
||||
peer: peerOnlyIPv4NilHostinfo.View(),
|
||||
self: selfOnlyIPv4.View(),
|
||||
maybeCandidate: peerOnlyIPv4NilHostinfo.View(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := peerAPIIfCandidateRelayServer(tt.filt, tt.self, tt.peer); !reflect.DeepEqual(got, tt.want) {
|
||||
if got := peerAPIIfCandidateRelayServer(tt.filt, tt.self, tt.maybeCandidate); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("peerAPIIfCandidateRelayServer() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
Reference in New Issue
Block a user