mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 16:36:52 +01:00
checkpt
This commit is contained in:
1 parent
e99e48cca7
commit
ed8ae57fee
4 files changed
+49
-64
No files matched your search
+3
-6
@@ -84,13 +84,10 @@ func addRulesFromConfig(l *slog.Logger, inbound bool, c *config.C, ra ruleAdder)
|
||||
}
|
||||
proto = uint8(n)
|
||||
}
|
||||
// ICMPv6 rules are ICMP rules, see RulesBuilder.AddRule
|
||||
if proto == iputil.IPProtocolICMPv6 {
|
||||
proto = iputil.IPProtocolICMP
|
||||
}
|
||||
|
||||
var startPort, endPort int32
|
||||
if proto == iputil.IPProtocolICMP {
|
||||
if proto == iputil.IPProtocolICMP || proto == iputil.IPProtocolICMPv6 {
|
||||
// RulesBuilder.AddRule coerces ICMP ports to `any` as well. This copy stays so that an ICMP rule's
|
||||
// port is warned about rather than parsed, whatever it holds.
|
||||
startPort = PortAny
|
||||
endPort = PortAny
|
||||
if sPort != "" {
|
||||
|
||||
+13
-5
@@ -170,13 +170,21 @@ func TestAddRulesFromConfig(t *testing.T) {
|
||||
assert.Equal(t, addRuleCall{incoming: false, proto: 47, startPort: PortAny, endPort: PortAny, groups: nil, host: "a", ip: "", localIp: ""}, mf.lastCall, proto)
|
||||
}
|
||||
|
||||
// Test ICMP and ICMPv6, by name and by number, still ignore ports. An ICMPv6 rule is added as an ICMP rule.
|
||||
for _, proto := range []any{"icmp", "icmpv6", iputil.IPProtocolICMP, iputil.IPProtocolICMPv6} {
|
||||
// Test ICMP and ICMPv6, by name and by number, still ignore ports
|
||||
for _, tc := range []struct {
|
||||
given any
|
||||
want uint8
|
||||
}{
|
||||
{"icmp", iputil.IPProtocolICMP},
|
||||
{"icmpv6", iputil.IPProtocolICMPv6},
|
||||
{iputil.IPProtocolICMP, iputil.IPProtocolICMP},
|
||||
{iputil.IPProtocolICMPv6, iputil.IPProtocolICMPv6},
|
||||
} {
|
||||
conf = config.NewC(test.NewLogger())
|
||||
mf = &mockFirewall{}
|
||||
conf.Settings["firewall"] = map[string]any{"outbound": []any{map[string]any{"port": "1", "proto": proto, "host": "a"}}}
|
||||
require.NoError(t, addRulesFromConfig(l, false, conf, mf), proto)
|
||||
assert.Equal(t, addRuleCall{incoming: false, proto: iputil.IPProtocolICMP, startPort: PortAny, endPort: PortAny, groups: nil, host: "a", ip: "", localIp: ""}, mf.lastCall, proto)
|
||||
conf.Settings["firewall"] = map[string]any{"outbound": []any{map[string]any{"port": "1", "proto": tc.given, "host": "a"}}}
|
||||
require.NoError(t, addRulesFromConfig(l, false, conf, mf), tc.given)
|
||||
assert.Equal(t, addRuleCall{incoming: false, proto: tc.want, startPort: PortAny, endPort: PortAny, groups: nil, host: "a", ip: "", localIp: ""}, mf.lastCall, tc.given)
|
||||
}
|
||||
|
||||
// Test protocols that aren't a known name or a number from 1 to 255
|
||||
|
||||
+25
-33
@@ -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
|
||||
|
||||
Reference in new issue
Block a user