From 9e96894bd79f298c57823b4b7de88c2552faeaf8 Mon Sep 17 00:00:00 2001 From: JackDoan Date: Tue, 29 Sep 2026 17:18:11 -0500 Subject: [PATCH] Pass firewall packets by pointer through conntrack and rule matching --- firewall.go | 38 +++++++++++++++++++------------------- firewall_test.go | 24 ++++++++++++------------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/firewall.go b/firewall.go index 5fb2d6de..160fd504 100644 --- a/firewall.go +++ b/firewall.go @@ -458,7 +458,7 @@ func (f *Firewall) Drop(fp firewall.Packet, incoming bool, h *HostInfo, caPool * } // Check if we spoke to this tuple, if we did then allow this packet - if f.inConns(fp, h, caPool, localCache) { + if f.inConns(&fp, h, caPool, localCache) { return nil } @@ -468,13 +468,13 @@ func (f *Firewall) Drop(fp firewall.Packet, incoming bool, h *HostInfo, caPool * } // We now know which firewall table to check against - if !table.match(fp, incoming, h.ConnectionState.peerCert, caPool) { + if !table.match(&fp, incoming, h.ConnectionState.peerCert, caPool) { f.metrics(incoming).droppedNoRule.Inc(1) return ErrNoMatchingRule } // We always want to conntrack since it is a faster operation - f.addConn(fp, incoming) + f.addConn(&fp, incoming) return nil } @@ -503,9 +503,9 @@ func (f *Firewall) EmitStats() { metrics.GetOrRegisterGauge("firewall.rules.hash", nil).Update(int64(f.GetRuleHashFNV())) } -func (f *Firewall) inConns(fp firewall.Packet, h *HostInfo, caPool *cert.CAPool, localCache firewall.ConntrackCache) bool { +func (f *Firewall) inConns(fp *firewall.Packet, h *HostInfo, caPool *cert.CAPool, localCache firewall.ConntrackCache) bool { if localCache != nil { - if _, ok := localCache[fp]; ok { + if _, ok := localCache[*fp]; ok { return true } } @@ -518,7 +518,7 @@ func (f *Firewall) inConns(fp firewall.Packet, h *HostInfo, caPool *cert.CAPool, f.evict(ep) } - c, ok := conntrack.Conns[fp] + c, ok := conntrack.Conns[*fp] if !ok { conntrack.Unlock() @@ -537,20 +537,20 @@ func (f *Firewall) inConns(fp firewall.Packet, h *HostInfo, caPool *cert.CAPool, if !table.match(fp, c.incoming, h.ConnectionState.peerCert, caPool) { if f.l.Enabled(context.Background(), slog.LevelDebug) { h.logger(f.l).Debug("dropping old conntrack entry, does not match new ruleset", - "fwPacket", fp, + "fwPacket", *fp, "incoming", c.incoming, "rulesVersion", f.rulesVersion, "oldRulesVersion", c.rulesVersion, ) } - delete(conntrack.Conns, fp) + delete(conntrack.Conns, *fp) conntrack.Unlock() return false } if f.l.Enabled(context.Background(), slog.LevelDebug) { h.logger(f.l).Debug("keeping old conntrack entry, does match new ruleset", - "fwPacket", fp, + "fwPacket", *fp, "incoming", c.incoming, "rulesVersion", f.rulesVersion, "oldRulesVersion", c.rulesVersion, @@ -572,13 +572,13 @@ func (f *Firewall) inConns(fp firewall.Packet, h *HostInfo, caPool *cert.CAPool, conntrack.Unlock() if localCache != nil { - localCache[fp] = struct{}{} + localCache[*fp] = struct{}{} } return true } -func (f *Firewall) addConn(fp firewall.Packet, incoming bool) { +func (f *Firewall) addConn(fp *firewall.Packet, incoming bool) { var timeout time.Duration c := &conn{} @@ -593,9 +593,9 @@ func (f *Firewall) addConn(fp firewall.Packet, incoming bool) { conntrack := f.Conntrack conntrack.Lock() - if _, ok := conntrack.Conns[fp]; !ok { + if _, ok := conntrack.Conns[*fp]; !ok { conntrack.TimerWheel.Advance(time.Now()) - conntrack.TimerWheel.Add(fp, timeout) + conntrack.TimerWheel.Add(*fp, timeout) } // Record which rulesVersion allowed this connection, so we can retest after @@ -603,7 +603,7 @@ func (f *Firewall) addConn(fp firewall.Packet, incoming bool) { c.incoming = incoming c.rulesVersion = f.rulesVersion c.Expires = time.Now().Add(timeout) - conntrack.Conns[fp] = c + conntrack.Conns[*fp] = c conntrack.Unlock() } @@ -630,7 +630,7 @@ func (f *Firewall) evict(p firewall.Packet) { delete(conntrack.Conns, p) } -func (ft *FirewallTable) match(p firewall.Packet, incoming bool, c *cert.CachedCertificate, caPool *cert.CAPool) bool { +func (ft *FirewallTable) match(p *firewall.Packet, incoming bool, c *cert.CachedCertificate, caPool *cert.CAPool) bool { if ft.AnyProto.match(p, incoming, c, caPool) { return true } @@ -674,7 +674,7 @@ func (fp firewallPort) addRule(f *Firewall, startPort int32, endPort int32, grou return nil } -func (fp firewallPort) match(p firewall.Packet, incoming bool, c *cert.CachedCertificate, caPool *cert.CAPool) bool { +func (fp firewallPort) match(p *firewall.Packet, incoming bool, c *cert.CachedCertificate, caPool *cert.CAPool) bool { // We don't have any allowed ports, bail if fp == nil { return false @@ -744,7 +744,7 @@ func (fc *FirewallCA) addRule(f *Firewall, groups []string, host string, cidr, l return nil } -func (fc *FirewallCA) match(p firewall.Packet, c *cert.CachedCertificate, caPool *cert.CAPool) bool { +func (fc *FirewallCA) match(p *firewall.Packet, c *cert.CachedCertificate, caPool *cert.CAPool) bool { if fc == nil { return false } @@ -846,7 +846,7 @@ func (fr *FirewallRule) isAny(groups []string, host string, cidr string) bool { return false } -func (fr *FirewallRule) match(p firewall.Packet, c *cert.CachedCertificate) bool { +func (fr *FirewallRule) match(p *firewall.Packet, c *cert.CachedCertificate) bool { if fr == nil { return false } @@ -918,7 +918,7 @@ func (flc *firewallLocalCIDR) addRule(f *Firewall, localCidr string) error { return nil } -func (flc *firewallLocalCIDR) match(p firewall.Packet, c *cert.CachedCertificate) bool { +func (flc *firewallLocalCIDR) match(p *firewall.Packet, c *cert.CachedCertificate) bool { if flc == nil { return false } diff --git a/firewall_test.go b/firewall_test.go index b8727915..eb688a09 100644 --- a/firewall_test.go +++ b/firewall_test.go @@ -351,7 +351,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { Certificate: &dummyCert{}, } for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolUDP}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolUDP}, true, c, cp)) } }) @@ -361,7 +361,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { Certificate: &dummyCert{}, } for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 1}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 1}, true, c, cp)) } }) @@ -371,7 +371,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { } ip := netip.MustParsePrefix("9.254.254.254/32") for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: ip.Addr()}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: ip.Addr()}, true, c, cp)) } }) b.Run("pass proto, port, fail on local CIDRv6", func(b *testing.B) { @@ -380,7 +380,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { } ip := netip.MustParsePrefix("fd99::99/128") for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: ip.Addr()}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: ip.Addr()}, true, c, cp)) } }) @@ -393,7 +393,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"nope": {}}, } for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp)) } }) b.Run("pass proto, port, any local CIDRv6, fail all group, name, and cidr", func(b *testing.B) { @@ -405,7 +405,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"nope": {}}, } for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp)) } }) @@ -418,7 +418,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"nope": {}}, } for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp)) } }) b.Run("pass proto, port, specific local CIDRv6, fail all group, name, and cidr", func(b *testing.B) { @@ -430,7 +430,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"nope": {}}, } for n := 0; n < b.N; n++ { - assert.False(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix6.Addr()}, true, c, cp)) + assert.False(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix6.Addr()}, true, c, cp)) } }) @@ -442,7 +442,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"good-group": {}}, } for n := 0; n < b.N; n++ { - assert.True(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp)) + assert.True(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp)) } }) @@ -454,7 +454,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"good-group": {}}, } for n := 0; n < b.N; n++ { - assert.True(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp)) + assert.True(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp)) } }) b.Run("pass on group on specific local cidr6", func(b *testing.B) { @@ -465,7 +465,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"good-group": {}}, } for n := 0; n < b.N; n++ { - assert.True(b, ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix6.Addr()}, true, c, cp)) + assert.True(b, ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 100, LocalAddr: pfix6.Addr()}, true, c, cp)) } }) @@ -477,7 +477,7 @@ func BenchmarkFirewallTable_match(b *testing.B) { InvertedGroups: map[string]struct{}{"nope": {}}, } for n := 0; n < b.N; n++ { - ft.match(firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp) + ft.match(&firewall.Packet{Protocol: iputil.IPProtocolTCP, LocalPort: 10}, true, c, cp) } }) }