From e2eb6eb87093b4821a1458946d5cff75a70ace63 Mon Sep 17 00:00:00 2001 From: Fran Bull Date: Wed, 2 Apr 2025 08:58:13 -0700 Subject: [PATCH] cmd/natc: separate perPeerState from connector Make the perPeerState objects able to function independently without a shared reference to the connector. We don't currently change the values from connector that perPeerState uses at runtime. Explicitly copying them at perPeerState creation allows us to, for example, put the perPeerState into a consensus algorithm in the future. Updates #14667 Signed-off-by: Fran Bull --- cmd/natc/natc.go | 16 ++++++++++++---- cmd/natc/natc_test.go | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cmd/natc/natc.go b/cmd/natc/natc.go index a8168ce6d..bff9bce87 100644 --- a/cmd/natc/natc.go +++ b/cmd/natc/natc.go @@ -359,7 +359,7 @@ var tsMBox = dnsmessage.MustNewName("support.tailscale.com.") // generateDNSResponse generates a DNS response for the given request. The from // argument is the NodeID of the node that sent the request. func (c *connector) generateDNSResponse(req *dnsmessage.Message, from tailcfg.NodeID) ([]byte, error) { - pm, _ := c.perPeerMap.LoadOrStore(from, &perPeerState{c: c}) + pm, _ := c.perPeerMap.LoadOrStore(from, newPerPeerState(c)) var addrs []netip.Addr if len(req.Questions) > 0 { switch req.Questions[0].Type { @@ -509,7 +509,8 @@ func proxyTCPConn(c net.Conn, dest string) { // perPeerState holds the state for a single peer. type perPeerState struct { - c *connector + v6ULA netip.Prefix + ipset *netipx.IPSet mu sync.Mutex addrInUse *big.Int @@ -517,6 +518,13 @@ type perPeerState struct { addrToDomain *bart.Table[string] } +func newPerPeerState(c *connector) *perPeerState { + return &perPeerState{ + ipset: c.ipset, + v6ULA: c.v6ULA, + } +} + // domainForIP returns the domain name assigned to the given IP address and // whether it was found. func (ps *perPeerState) domainForIP(ip netip.Addr) (_ string, ok bool) { @@ -555,7 +563,7 @@ func (ps *perPeerState) unusedIPv4Locked() netip.Addr { if ps.addrInUse == nil { ps.addrInUse = big.NewInt(0) } - return allocAddr(ps.c.ipset, ps.addrInUse) + return allocAddr(ps.ipset, ps.addrInUse) } // assignAddrsLocked assigns a pair of unique IP addresses for the given domain @@ -570,7 +578,7 @@ func (ps *perPeerState) assignAddrsLocked(domain string) []netip.Addr { if !v4.IsValid() { return nil } - as16 := ps.c.v6ULA.Addr().As16() + as16 := ps.v6ULA.Addr().As16() as4 := v4.As4() copy(as16[12:], as4[:]) v6 := netip.AddrFrom16(as16) diff --git a/cmd/natc/natc_test.go b/cmd/natc/natc_test.go index ddd2d1894..66e0141b9 100644 --- a/cmd/natc/natc_test.go +++ b/cmd/natc/natc_test.go @@ -220,7 +220,7 @@ func TestPerPeerState(t *testing.T) { } c.setPrefixes([]netip.Prefix{netip.MustParsePrefix("100.64.1.0/24")}) - ps := &perPeerState{c: c} + ps := newPerPeerState(c) addrs, err := ps.ipForDomain("example.com") if err != nil { @@ -360,7 +360,7 @@ func TestIPPoolExhaustion(t *testing.T) { } c.setPrefixes([]netip.Prefix{smallPrefix}) - ps := &perPeerState{c: c} + ps := newPerPeerState(c) assignedIPs := make(map[netip.Addr]string)