This commit is contained in:
JackDoan committed 2026-09-30 15:06:35 -05:00
1 parent e99e48cca7
commit ed8ae57fee
4 files changed
+49 -64

No files matched your search

+25 -33
View File
@@ -4,40 +4,32 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"hash"
"hash/fnv"
"io"
"log/slog"
"math"
"net/netip"
"slices"
"strings"
"github.com/slackhq/nebula/iputil"
)
// RulesBuilder collects the inbound and outbound rules, Build turns them into a Table for each direction
type RulesBuilder struct {
in, out tableRules
// in and out are each direction's rules in the order they were added
in, out []rule
// defaultLocalCIDRAny makes rules without a local cidr allow any local address, even with unsafe networks
defaultLocalCIDRAny bool
// ruleSHA and ruleFNV hash every rule as it's added, see Rules
ruleSHA hash.Hash
ruleFNV hash.Hash32
// ruleText describes every rule as it is added, one line each. Build hashes it; see Rules.
ruleText strings.Builder
l *slog.Logger
}
// tableRules are one direction's rules in the order they were added, waiting to be built into a Table
type tableRules []rule
func NewRulesBuilder(l *slog.Logger) *RulesBuilder {
return &RulesBuilder{
ruleSHA: sha256.New(),
ruleFNV: fnv.New32a(),
l: l,
}
return &RulesBuilder{l: l}
}
// AddRule adds a rule for incoming or outgoing traffic, on proto or on every protocol when proto is ProtoAny.
@@ -57,19 +49,19 @@ func (b *RulesBuilder) AddRule(incoming bool, proto uint8, startPort int32, endP
endPort = PortAny
}
r, err := parseRule(startPort, endPort, groups, host, cidr, localCidr, caName, caSha)
r, err := parseRule(proto, startPort, endPort, groups, host, cidr, localCidr, caName, caSha)
if err != nil {
return err
}
if incoming {
b.in.add(proto, r)
b.in = append(b.in, r)
} else {
b.out.add(proto, r)
b.out = append(b.out, r)
}
// The rule hashes are of these lines, changing them changes every hash
fmt.Fprintf(io.MultiWriter(b.ruleSHA, b.ruleFNV),
fmt.Fprintf(&b.ruleText,
"incoming: %v, proto: %v, startPort: %v, endPort: %v, groups: %v, host: %v, ip: %v, localIp: %v, caName: %v, caSha: %s\n",
incoming, proto, startPort, endPort, groups, host, cidr, localCidr, caName, caSha,
)
@@ -94,15 +86,20 @@ func (b *RulesBuilder) Build(vpnNetworks, unsafeNetworks []netip.Prefix) Rules {
defaultLocal = append([]netip.Prefix{}, vpnNetworks...)
}
text := []byte(b.ruleText.String())
sha := sha256.Sum256(text)
h := fnv.New32a()
h.Write(text)
return Rules{
In: b.in.build(defaultLocal),
Out: b.out.build(defaultLocal),
Hash: hex.EncodeToString(b.ruleSHA.Sum(nil)),
HashFNV: b.ruleFNV.Sum32(),
In: buildTable(b.in, defaultLocal),
Out: buildTable(b.out, defaultLocal),
Hash: hex.EncodeToString(sha[:]),
HashFNV: h.Sum32(),
}
}
func parseRule(startPort, endPort int32, groups []string, host, cidr, localCidr, caName, caSha string) (rule, error) {
func parseRule(proto uint8, startPort, endPort int32, groups []string, host, cidr, localCidr, caName, caSha string) (rule, error) {
if startPort > endPort {
return rule{}, fmt.Errorf("start port was lower than end port")
}
@@ -115,6 +112,7 @@ func parseRule(startPort, endPort int32, groups []string, host, cidr, localCidr,
}
r := rule{
proto: proto,
startPort: startPort,
endPort: endPort,
groups: groups,
@@ -146,18 +144,12 @@ func parseRule(startPort, endPort int32, groups []string, host, cidr, localCidr,
return r, nil
}
// add keeps r for proto, or for every protocol when proto is ProtoAny.
func (tr *tableRules) add(proto uint8, r rule) {
r.proto = proto
*tr = append(*tr, r)
}
// build turns the rules into a Table. Rules without a local cidr allow defaultLocal,
// buildTable turns one direction's rules into a Table. Rules without a local cidr allow defaultLocal,
// or any local address when defaultLocal is nil.
func (tr tableRules) build(defaultLocal []netip.Prefix) *Table {
t := &Table{rules: make([]rule, len(tr))}
func buildTable(rules []rule, defaultLocal []netip.Prefix) *Table {
t := &Table{rules: make([]rule, len(rules))}
var hasOwn [256]bool
for id, r := range tr {
for id, r := range rules {
t.rules[id] = r.withDefaultLocal(defaultLocal)
if r.proto != ProtoAny {
hasOwn[r.proto] = true