firewall: Key conntrack by the peer's first vpn address

This commit is contained in:
JackDoan committed 2026-10-16 16:35:06 -05:00
1 parent 56a1a94a54
commit 7aa6f6c7da
4 files changed
+10 -11

No files matched your search

+2 -3
View File
@@ -463,9 +463,8 @@ func (f *Firewall) Drop(fp firewall.Packet, incoming bool, h *HostInfo, caPool *
return ErrInvalidLocalIP return ErrInvalidLocalIP
} }
// The highest vpn address identifies the peer. v2 certs sort their networks and v1 certs have only one, // The first vpn address identifies the peer, as it does elsewhere. A host's v1 and v2 certs must agree on it
// so this is the peer's v6 address when it has one, which stays put while v4 addresses come and go. key := firewall.ConntrackKey{Packet: fp, Peer: h.vpnAddrs[0]}
key := firewall.ConntrackKey{Packet: fp, Peer: h.vpnAddrs[len(h.vpnAddrs)-1]}
// Check if we spoke to this tuple, if we did then allow this packet // Check if we spoke to this tuple, if we did then allow this packet
if f.inConns(key, h, caPool, localCache) { if f.inConns(key, h, caPool, localCache) {
+1 -1
View File
@@ -1198,7 +1198,7 @@ func TestFirewall_ConntrackPeerRehandshake(t *testing.T) {
RemotePort: 55000, RemotePort: 55000,
Protocol: iputil.IPProtocolTCP, Protocol: iputil.IPProtocolTCP,
} }
key := firewall.ConntrackKey{Packet: flow, Peer: netip.MustParseAddr("2001:db8::2")} key := firewall.ConntrackKey{Packet: flow, Peer: netip.MustParseAddr("192.0.2.2")}
t.Run("inbound flow follows the peer's groups", func(t *testing.T) { t.Run("inbound flow follows the peer's groups", func(t *testing.T) {
fw := NewFirewall(l, time.Second, time.Minute, time.Hour, owner) fw := NewFirewall(l, time.Second, time.Minute, time.Hour, owner)
+2 -2
View File
@@ -718,7 +718,7 @@ func (f *Interface) Close() error {
} }
// siblingPeers implements gatewaySiblings from the routes and tunnels we have now. Routes name a gateway by any of its // siblingPeers implements gatewaySiblings from the routes and tunnels we have now. Routes name a gateway by any of its
// vpn addresses, conntrack keys a peer by its highest one, so each gateway is resolved through its tunnel. A gateway // vpn addresses, conntrack keys a peer by its first one, so each gateway is resolved through its tunnel. A gateway
// we have no tunnel to can't be carrying a live flow. // we have no tunnel to can't be carrying a live flow.
func (f *Interface) siblingPeers(remote netip.Addr, h *HostInfo, buf []netip.Addr) []netip.Addr { func (f *Interface) siblingPeers(remote netip.Addr, h *HostInfo, buf []netip.Addr) []netip.Addr {
gateways := f.inside.RoutesFor(remote) gateways := f.inside.RoutesFor(remote)
@@ -732,7 +732,7 @@ func (f *Interface) siblingPeers(remote netip.Addr, h *HostInfo, buf []netip.Add
continue continue
} }
if s := f.hostMap.QueryVpnAddr(g.Addr()); s != nil && s != h { if s := f.hostMap.QueryVpnAddr(g.Addr()); s != nil && s != h {
buf = append(buf, s.vpnAddrs[len(s.vpnAddrs)-1]) buf = append(buf, s.vpnAddrs[0])
} }
} }
return buf return buf
+5 -5
View File
@@ -158,10 +158,10 @@ func (t routesTun) RoutesFor(ip netip.Addr) routing.Gateways {
func TestInterface_SiblingPeers(t *testing.T) { func TestInterface_SiblingPeers(t *testing.T) {
addr := netip.MustParseAddr addr := netip.MustParseAddr
routes := new(bart.Table[routing.Gateways]) routes := new(bart.Table[routing.Gateways])
// a and b carry 198.51.100.0/24, the route names a by its v4 address // a and b carry 198.51.100.0/24, the route names b by its v6 address
routes.Insert(netip.MustParsePrefix("198.51.100.0/24"), routing.Gateways{ routes.Insert(netip.MustParsePrefix("198.51.100.0/24"), routing.Gateways{
routing.NewGateway(addr("192.0.2.2"), 1), routing.NewGateway(addr("192.0.2.2"), 1),
routing.NewGateway(addr("192.0.2.3"), 1), routing.NewGateway(addr("fd00::3"), 1),
routing.NewGateway(addr("192.0.2.5"), 1), // no tunnel to this one routing.NewGateway(addr("192.0.2.5"), 1), // no tunnel to this one
}) })
routes.Insert(netip.MustParsePrefix("203.0.113.0/24"), routing.Gateways{routing.NewGateway(addr("192.0.2.2"), 1)}) routes.Insert(netip.MustParsePrefix("203.0.113.0/24"), routing.Gateways{routing.NewGateway(addr("192.0.2.2"), 1)})
@@ -175,9 +175,9 @@ func TestInterface_SiblingPeers(t *testing.T) {
} }
f := &Interface{inside: routesTun{routes: routes}, hostMap: hm} f := &Interface{inside: routesTun{routes: routes}, hostMap: hm}
// Siblings come back as their highest vpn address, the one conntrack keys on // Siblings come back as their first vpn address, the one conntrack keys on, whichever address the route names
assert.Equal(t, []netip.Addr{addr("fd00::3")}, f.siblingPeers(addr("198.51.100.5"), a, nil)) assert.Equal(t, []netip.Addr{addr("192.0.2.3")}, f.siblingPeers(addr("198.51.100.5"), a, nil))
assert.Equal(t, []netip.Addr{addr("fd00::2")}, f.siblingPeers(addr("198.51.100.5"), b, nil)) assert.Equal(t, []netip.Addr{addr("192.0.2.2")}, f.siblingPeers(addr("198.51.100.5"), b, nil))
assert.Empty(t, f.siblingPeers(addr("198.51.100.5"), c, nil), "not one of our gateways for the network") assert.Empty(t, f.siblingPeers(addr("198.51.100.5"), c, nil), "not one of our gateways for the network")
assert.Empty(t, f.siblingPeers(addr("203.0.113.5"), a, nil), "a single gateway route has no siblings") assert.Empty(t, f.siblingPeers(addr("203.0.113.5"), a, nil), "a single gateway route has no siblings")
assert.Empty(t, f.siblingPeers(addr("192.0.2.3"), a, nil), "no route") assert.Empty(t, f.siblingPeers(addr("192.0.2.3"), a, nil), "no route")