Skip to content

Commit 2a2d4ae

Browse files
kerumetogvisor-bot
authored andcommitted
Refactor nftables package and exposed it to tcpip/stack/
Moved higher-level structs in nftables package to be under tcpip/stack package in anticipation of implementing netlink netfilter sockets. These sockets need to reference the system-wide nftables structure, which requires exposing it to all processes. Because there were circular dependencies between the nftables and stack packages and because NetStack needs to be kept separate from the sentry, an interface was introduced to allow NetStack users to interact with nftables while keeping linux specific implementation details within the nftables package. The interface is simply introduced and implemented for a struct in the nftables package, and will be integrated in future work. PiperOrigin-RevId: 771162442
1 parent fb842aa commit 2a2d4ae

File tree

14 files changed

+474
-365
lines changed

14 files changed

+474
-365
lines changed

pkg/tcpip/nftables/nft_comparison.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,6 @@ func (op comparison) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule *
111111
}
112112
if !result {
113113
// Comparison is false, so break from the rule.
114-
regs.verdict = Verdict{Code: VC(linux.NFT_BREAK)}
114+
regs.verdict = stack.NFVerdict{Code: VC(linux.NFT_BREAK)}
115115
}
116116
}

pkg/tcpip/nftables/nft_metaload.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func (op metaLoad) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule *Ru
159159
// Netfilter (Family) Protocol (8-bit, single byte).
160160
case linux.NFT_META_NFPROTO:
161161
family := rule.chain.GetAddressFamily()
162-
target = []byte{family.Protocol()}
162+
target = []byte{AfProtocol(family)}
163163

164164
// L4 Transport Layer Protocol (8-bit, single byte).
165165
case linux.NFT_META_L4PROTO:
@@ -225,7 +225,7 @@ func (op metaLoad) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule *Ru
225225

226226
// Breaks if could not retrieve meta data.
227227
if target == nil {
228-
regs.verdict = Verdict{Code: VC(linux.NFT_BREAK)}
228+
regs.verdict = stack.NFVerdict{Code: VC(linux.NFT_BREAK)}
229229
return
230230
}
231231

pkg/tcpip/nftables/nft_metaset.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,6 @@ func (op metaSet) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule *Rul
8181
}
8282

8383
// Breaks if could not set the meta data.
84-
regs.verdict = Verdict{Code: VC(linux.NFT_BREAK)}
84+
regs.verdict = stack.NFVerdict{Code: VC(linux.NFT_BREAK)}
8585
return
8686
}

pkg/tcpip/nftables/nft_payload_load.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (op payloadLoad) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule
114114

115115
// Breaks if could not retrieve packet data.
116116
if payload == nil || len(payload) < int(op.offset+op.blen) {
117-
regs.verdict = Verdict{Code: VC(linux.NFT_BREAK)}
117+
regs.verdict = stack.NFVerdict{Code: VC(linux.NFT_BREAK)}
118118
return
119119
}
120120

pkg/tcpip/nftables/nft_payload_set.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (op payloadSet) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule *
9696

9797
// Breaks if could not retrieve packet data.
9898
if payload == nil || len(payload) < int(op.offset+op.blen) {
99-
regs.verdict = Verdict{Code: VC(linux.NFT_BREAK)}
99+
regs.verdict = stack.NFVerdict{Code: VC(linux.NFT_BREAK)}
100100
return
101101
}
102102

pkg/tcpip/nftables/nft_ranged.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,6 @@ func (op ranged) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule *Rule
107107
// Determines the comparison result depending on the operator.
108108
if (d1 >= 0 && d2 <= 0) != (op.rop == linux.NFT_RANGE_EQ) {
109109
// Comparison is false, so break from the rule.
110-
regs.verdict = Verdict{Code: VC(linux.NFT_BREAK)}
110+
regs.verdict = stack.NFVerdict{Code: VC(linux.NFT_BREAK)}
111111
}
112112
}

pkg/tcpip/nftables/nft_route.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func (op route) evaluate(regs *registerSet, pkt *stack.PacketBuffer, rule *Rule)
125125

126126
// Breaks if could not retrieve target data.
127127
if target == nil {
128-
regs.verdict = Verdict{Code: VC(linux.NFT_BREAK)}
128+
regs.verdict = stack.NFVerdict{Code: VC(linux.NFT_BREAK)}
129129
return
130130
}
131131

pkg/tcpip/nftables/nftables.go

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,86 @@ import (
2424
"gvisor.dev/gvisor/pkg/tcpip/stack"
2525
)
2626

27+
//
28+
// Interface-Related Methods
29+
//
30+
31+
// CheckPrerouting checks at the Prerouting hook if the packet should continue traversing the stack.
32+
func (nf *NFTables) CheckPrerouting(pkt *stack.PacketBuffer, af stack.AddressFamily) bool {
33+
return nf.checkHook(pkt, af, stack.NFPrerouting)
34+
}
35+
36+
// CheckInput checks at the Input hook if the packet should continue traversing the stack.
37+
func (nf *NFTables) CheckInput(pkt *stack.PacketBuffer, af stack.AddressFamily) bool {
38+
return nf.checkHook(pkt, af, stack.NFInput)
39+
}
40+
41+
// CheckForward checks at the Forward hook if the packet should continue traversing the stack.
42+
func (nf *NFTables) CheckForward(pkt *stack.PacketBuffer, af stack.AddressFamily) bool {
43+
return nf.checkHook(pkt, af, stack.NFForward)
44+
}
45+
46+
// CheckOutput checks at the Output hook if the packet should continue traversing the stack.
47+
func (nf *NFTables) CheckOutput(pkt *stack.PacketBuffer, af stack.AddressFamily) bool {
48+
return nf.checkHook(pkt, af, stack.NFOutput)
49+
}
50+
51+
// CheckPostrouting checks at the Postrouting hook if the packet should continue traversing the stack.
52+
func (nf *NFTables) CheckPostrouting(pkt *stack.PacketBuffer, af stack.AddressFamily) bool {
53+
return nf.checkHook(pkt, af, stack.NFPostrouting)
54+
}
55+
56+
// CheckIngress checks at the Ingress hook if the packet should continue traversing the stack.
57+
func (nf *NFTables) CheckIngress(pkt *stack.PacketBuffer, af stack.AddressFamily) bool {
58+
return nf.checkHook(pkt, af, stack.NFIngress)
59+
}
60+
61+
// CheckEgress checks at the Egress hook if the packet should continue traversing the stack.
62+
func (nf *NFTables) CheckEgress(pkt *stack.PacketBuffer, af stack.AddressFamily) bool {
63+
return nf.checkHook(pkt, af, stack.NFEgress)
64+
}
65+
66+
// checkHook returns true if the packet should continue traversing the stack or false
67+
// if the packet should be dropped.
68+
func (nf *NFTables) checkHook(pkt *stack.PacketBuffer, af stack.AddressFamily, hook stack.NFHook) bool {
69+
v, err := nf.EvaluateHook(af, hook, pkt)
70+
71+
if err != nil {
72+
return false
73+
}
74+
75+
return v.Code == VC(linux.NF_ACCEPT)
76+
}
77+
78+
//
79+
// Core Evaluation Functions
80+
//
81+
2782
// EvaluateHook evaluates a packet using the rules of the given hook for the
2883
// given address family, returning a netfilter verdict and modifying the packet
2984
// in place.
3085
// Returns an error if address family or hook is invalid or they don't match.
3186
// TODO(b/345684870): Consider removing error case if we never return an error.
32-
func (nf *NFTables) EvaluateHook(family AddressFamily, hook Hook, pkt *stack.PacketBuffer) (Verdict, error) {
87+
func (nf *NFTables) EvaluateHook(family stack.AddressFamily, hook stack.NFHook, pkt *stack.PacketBuffer) (stack.NFVerdict, error) {
3388
// Note: none of the other evaluate functions are public because they require
3489
// jumping to different chains in the same table, so all chains, rules, and
3590
// operations must be tied to a table. Thus, calling evaluate for standalone
3691
// chains, rules, or operations can be misleading and dangerous.
3792

3893
// Ensures address family is valid.
3994
if err := validateAddressFamily(family); err != nil {
40-
return Verdict{}, err
95+
return stack.NFVerdict{}, err
4196
}
4297

4398
// Ensures hook is valid.
4499
if err := validateHook(hook, family); err != nil {
45-
return Verdict{}, err
100+
return stack.NFVerdict{}, err
46101
}
47102

48103
// Immediately accept if there are no base chains for the specified hook.
49104
if nf.filters[family] == nil || nf.filters[family].hfStacks[hook] == nil ||
50105
len(nf.filters[family].hfStacks[hook].baseChains) == 0 {
51-
return Verdict{Code: VC(linux.NF_ACCEPT)}, nil
106+
return stack.NFVerdict{Code: VC(linux.NF_ACCEPT)}, nil
52107
}
53108

54109
regs := newRegisterSet()
@@ -63,7 +118,7 @@ func (nf *NFTables) EvaluateHook(family AddressFamily, hook Hook, pkt *stack.Pac
63118

64119
err := bc.evaluate(&regs, pkt)
65120
if err != nil {
66-
return Verdict{}, err
121+
return stack.NFVerdict{}, err
67122
}
68123

69124
// Terminates immediately on netfilter terminal verdicts.
@@ -78,9 +133,9 @@ func (nf *NFTables) EvaluateHook(family AddressFamily, hook Hook, pkt *stack.Pac
78133
switch regs.Verdict().Code {
79134
case VC(linux.NFT_CONTINUE), VC(linux.NFT_RETURN):
80135
if bc.GetBaseChainInfo().PolicyDrop {
81-
return Verdict{Code: VC(linux.NF_DROP)}, nil
136+
return stack.NFVerdict{Code: VC(linux.NF_DROP)}, nil
82137
}
83-
return Verdict{Code: VC(linux.NF_ACCEPT)}, nil
138+
return stack.NFVerdict{Code: VC(linux.NF_ACCEPT)}, nil
84139
}
85140

86141
panic(fmt.Sprintf("unexpected verdict from hook evaluation: %s", VerdictCodeToString(regs.Verdict().Code)))
@@ -184,14 +239,14 @@ func NewNFTables(clock tcpip.Clock, rng rand.RNG) *NFTables {
184239

185240
// Flush clears entire ruleset and all data for all address families.
186241
func (nf *NFTables) Flush() {
187-
for family := range NumAFs {
242+
for family := range stack.NumAFs {
188243
nf.filters[family] = nil
189244
}
190245
}
191246

192247
// FlushAddressFamily clears ruleset and all data for the given address family,
193248
// returning an error if the address family is invalid.
194-
func (nf *NFTables) FlushAddressFamily(family AddressFamily) error {
249+
func (nf *NFTables) FlushAddressFamily(family stack.AddressFamily) error {
195250
// Ensures address family is valid.
196251
if err := validateAddressFamily(family); err != nil {
197252
return err
@@ -202,7 +257,7 @@ func (nf *NFTables) FlushAddressFamily(family AddressFamily) error {
202257
}
203258

204259
// GetTable validates the inputs and gets a table if it exists, error otherwise.
205-
func (nf *NFTables) GetTable(family AddressFamily, tableName string) (*Table, error) {
260+
func (nf *NFTables) GetTable(family stack.AddressFamily, tableName string) (*Table, error) {
206261
// Ensures address family is valid.
207262
if err := validateAddressFamily(family); err != nil {
208263
return nil, err
@@ -232,7 +287,7 @@ func (nf *NFTables) GetTable(family AddressFamily, tableName string) (*Table, er
232287
// Note: if the table already exists, the existing table is returned without any
233288
// modifications.
234289
// Note: Table initialized as not dormant.
235-
func (nf *NFTables) AddTable(family AddressFamily, name string, comment string,
290+
func (nf *NFTables) AddTable(family stack.AddressFamily, name string, comment string,
236291
errorOnDuplicate bool) (*Table, error) {
237292
// Ensures address family is valid.
238293
if err := validateAddressFamily(family); err != nil {
@@ -245,7 +300,7 @@ func (nf *NFTables) AddTable(family AddressFamily, name string, comment string,
245300
family: family,
246301
nftState: nf,
247302
tables: make(map[string]*Table),
248-
hfStacks: make(map[Hook]*hookFunctionStack),
303+
hfStacks: make(map[stack.NFHook]*hookFunctionStack),
249304
}
250305
}
251306

@@ -278,14 +333,14 @@ func (nf *NFTables) AddTable(family AddressFamily, name string, comment string,
278333
// but also returns an error if a table by the same name already exists.
279334
// Note: this interface mirrors the difference between the create and add
280335
// commands within the nft binary.
281-
func (nf *NFTables) CreateTable(family AddressFamily, name string, comment string) (*Table, error) {
336+
func (nf *NFTables) CreateTable(family stack.AddressFamily, name string, comment string) (*Table, error) {
282337
return nf.AddTable(family, name, comment, true)
283338
}
284339

285340
// DeleteTable deletes the specified table from the NFTables object returning
286341
// true if the table was deleted and false if the table doesn't exist. Returns
287342
// an error if the address family is invalid.
288-
func (nf *NFTables) DeleteTable(family AddressFamily, tableName string) (bool, error) {
343+
func (nf *NFTables) DeleteTable(family stack.AddressFamily, tableName string) (bool, error) {
289344
// Ensures address family is valid.
290345
if err := validateAddressFamily(family); err != nil {
291346
return false, err
@@ -308,7 +363,7 @@ func (nf *NFTables) DeleteTable(family AddressFamily, tableName string) (bool, e
308363
}
309364

310365
// GetChain validates the inputs and gets a chain if it exists, error otherwise.
311-
func (nf *NFTables) GetChain(family AddressFamily, tableName string, chainName string) (*Chain, error) {
366+
func (nf *NFTables) GetChain(family stack.AddressFamily, tableName string, chainName string) (*Chain, error) {
312367
// Gets and checks the table.
313368
t, err := nf.GetTable(family, tableName)
314369
if err != nil {
@@ -326,7 +381,7 @@ func (nf *NFTables) GetChain(family AddressFamily, tableName string, chainName s
326381
// Note: if the chain already exists, the existing chain is returned without any
327382
// modifications.
328383
// Note: if the chain is not a base chain, info should be nil.
329-
func (nf *NFTables) AddChain(family AddressFamily, tableName string, chainName string, info *BaseChainInfo, comment string, errorOnDuplicate bool) (*Chain, error) {
384+
func (nf *NFTables) AddChain(family stack.AddressFamily, tableName string, chainName string, info *BaseChainInfo, comment string, errorOnDuplicate bool) (*Chain, error) {
330385
// Gets and checks the table.
331386
t, err := nf.GetTable(family, tableName)
332387
if err != nil {
@@ -341,14 +396,14 @@ func (nf *NFTables) AddChain(family AddressFamily, tableName string, chainName s
341396
// chain by the same name already exists.
342397
// Note: this interface mirrors the difference between the create and add
343398
// commands within the nft binary.
344-
func (nf *NFTables) CreateChain(family AddressFamily, tableName string, chainName string, info *BaseChainInfo, comment string) (*Chain, error) {
399+
func (nf *NFTables) CreateChain(family stack.AddressFamily, tableName string, chainName string, info *BaseChainInfo, comment string) (*Chain, error) {
345400
return nf.AddChain(family, tableName, chainName, info, comment, true)
346401
}
347402

348403
// DeleteChain deletes the specified chain from the NFTables object returning
349404
// true if the chain was deleted and false if the chain doesn't exist. Returns
350405
// an error if the address family is invalid or the table doesn't exist.
351-
func (nf *NFTables) DeleteChain(family AddressFamily, tableName string, chainName string) (bool, error) {
406+
func (nf *NFTables) DeleteChain(family stack.AddressFamily, tableName string, chainName string) (bool, error) {
352407
// Gets and checks the table.
353408
t, err := nf.GetTable(family, tableName)
354409
if err != nil {
@@ -373,7 +428,7 @@ func (t *Table) GetName() string {
373428
}
374429

375430
// GetAddressFamily returns the address family of the table.
376-
func (t *Table) GetAddressFamily() AddressFamily {
431+
func (t *Table) GetAddressFamily() stack.AddressFamily {
377432
return t.afFilter.family
378433
}
379434

@@ -486,7 +541,7 @@ func (c *Chain) GetName() string {
486541
}
487542

488543
// GetAddressFamily returns the address family of the chain.
489-
func (c *Chain) GetAddressFamily() AddressFamily {
544+
func (c *Chain) GetAddressFamily() stack.AddressFamily {
490545
return c.table.GetAddressFamily()
491546
}
492547

0 commit comments

Comments
 (0)