Pass context to nftables functions

Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
Rob Murray
2025-07-02 17:59:11 +01:00
parent 1c5d6d1ee3
commit a55fede2d4
5 changed files with 118 additions and 96 deletions

View File

@@ -81,7 +81,7 @@ func (nft *nftabler) getTable(ipv firewaller.IPVersion) nftables.TableRef {
func (nft *nftabler) FilterForwardDrop(ctx context.Context, ipv firewaller.IPVersion) error {
table := nft.getTable(ipv)
if err := table.Chain(forwardChain).SetPolicy("drop"); err != nil {
if err := table.Chain(ctx, forwardChain).SetPolicy("drop"); err != nil {
return err
}
return nftApply(ctx, table)
@@ -104,7 +104,7 @@ func (nft *nftabler) init(ctx context.Context, family nftables.Family) (nftables
// So, packets that aren't related to docker don't need to traverse any per-network filter forward
// rules - and packets that are entering or leaving docker networks only need to traverse rules
// related to those networks.
fwdChain, err := table.BaseChain(forwardChain,
fwdChain, err := table.BaseChain(ctx, forwardChain,
nftables.BaseChainTypeFilter,
nftables.BaseChainHookForward,
nftables.BaseChainPriorityFilter)
@@ -112,51 +112,51 @@ func (nft *nftabler) init(ctx context.Context, family nftables.Family) (nftables
return nftables.TableRef{}, fmt.Errorf("initialising nftables: %w", err)
}
// Instantiate the verdict maps and add the jumps.
_ = table.InterfaceVMap(filtFwdInVMap)
if err := fwdChain.AppendRule(initialRuleGroup, "oifname vmap @"+filtFwdInVMap); err != nil {
_ = table.InterfaceVMap(ctx, filtFwdInVMap)
if err := fwdChain.AppendRule(ctx, initialRuleGroup, "oifname vmap @"+filtFwdInVMap); err != nil {
return nftables.TableRef{}, fmt.Errorf("initialising nftables: %w", err)
}
_ = table.InterfaceVMap(filtFwdOutVMap)
if err := fwdChain.AppendRule(initialRuleGroup, "iifname vmap @"+filtFwdOutVMap); err != nil {
_ = table.InterfaceVMap(ctx, filtFwdOutVMap)
if err := fwdChain.AppendRule(ctx, initialRuleGroup, "iifname vmap @"+filtFwdOutVMap); err != nil {
return nftables.TableRef{}, fmt.Errorf("initialising nftables: %w", err)
}
// Set up the NAT postrouting base chain.
//
// Like the filter-forward chain, its only rules are jumps to network-specific ingress and egress chains.
natPostRtChain, err := table.BaseChain(postroutingChain,
natPostRtChain, err := table.BaseChain(ctx, postroutingChain,
nftables.BaseChainTypeNAT,
nftables.BaseChainHookPostrouting,
nftables.BaseChainPrioritySrcNAT)
if err != nil {
return nftables.TableRef{}, err
}
_ = table.InterfaceVMap(natPostroutingOutVMap)
if err := natPostRtChain.AppendRule(initialRuleGroup, "iifname vmap @"+natPostroutingOutVMap); err != nil {
_ = table.InterfaceVMap(ctx, natPostroutingOutVMap)
if err := natPostRtChain.AppendRule(ctx, initialRuleGroup, "iifname vmap @"+natPostroutingOutVMap); err != nil {
return nftables.TableRef{}, fmt.Errorf("initialising nftables: %w", err)
}
_ = table.InterfaceVMap(natPostroutingInVMap)
if err := natPostRtChain.AppendRule(initialRuleGroup, "oifname vmap @"+natPostroutingInVMap); err != nil {
_ = table.InterfaceVMap(ctx, natPostroutingInVMap)
if err := natPostRtChain.AppendRule(ctx, initialRuleGroup, "oifname vmap @"+natPostroutingInVMap); err != nil {
return nftables.TableRef{}, fmt.Errorf("initialising nftables: %w", err)
}
// Instantiate natChain, for the NAT prerouting and output base chains to jump to.
_ = table.Chain(natChain)
_ = table.Chain(ctx, natChain)
// Set up the NAT prerouting base chain.
natPreRtChain, err := table.BaseChain(preroutingChain,
natPreRtChain, err := table.BaseChain(ctx, preroutingChain,
nftables.BaseChainTypeNAT,
nftables.BaseChainHookPrerouting,
nftables.BaseChainPriorityDstNAT)
if err != nil {
return nftables.TableRef{}, err
}
if err := natPreRtChain.AppendRule(initialRuleGroup, "fib daddr type local counter jump "+natChain); err != nil {
if err := natPreRtChain.AppendRule(ctx, initialRuleGroup, "fib daddr type local counter jump "+natChain); err != nil {
return nftables.TableRef{}, fmt.Errorf("initialising nftables: %w", err)
}
// Set up the NAT output base chain
natOutputChain, err := table.BaseChain(outputChain,
natOutputChain, err := table.BaseChain(ctx, outputChain,
nftables.BaseChainTypeNAT,
nftables.BaseChainHookOutput,
nftables.BaseChainPriorityDstNAT)
@@ -172,12 +172,12 @@ func (nft *nftabler) init(ctx context.Context, family nftables.Family) (nftables
skipLoopback = "ip6 daddr != ::1 "
}
}
if err := natOutputChain.AppendRule(initialRuleGroup, skipLoopback+"fib daddr type local counter jump "+natChain); err != nil {
if err := natOutputChain.AppendRule(ctx, initialRuleGroup, skipLoopback+"fib daddr type local counter jump "+natChain); err != nil {
return nftables.TableRef{}, fmt.Errorf("initialising nftables: %w", err)
}
// Set up the raw prerouting base chain
if _, err := table.BaseChain(rawPreroutingChain,
if _, err := table.BaseChain(ctx, rawPreroutingChain,
nftables.BaseChainTypeFilter,
nftables.BaseChainHookPrerouting,
nftables.BaseChainPriorityRaw); err != nil {

View File

@@ -8,7 +8,7 @@ import (
"github.com/docker/docker/libnetwork/internal/nftables"
)
// mirroredWSL2Workaround adds IPv4 NAT rule if docker's host Linux appears to
// mirroredWSL2Workaround adds IPv4 NAT rule if docker's host Linux appears to
// be a guest running under WSL2 in with mirrored mode networking.
// https://learn.microsoft.com/en-us/windows/wsl/networking#mirrored-mode-networking
//
@@ -44,5 +44,6 @@ func mirroredWSL2Workaround(ctx context.Context, table nftables.TableRef) error
if table.Family() != nftables.IPv4 {
return nil
}
return table.Chain(natChain).AppendRule(initialRuleGroup, `iifname "loopback0" ip daddr 127.0.0.0/8 counter return`)
return table.Chain(ctx, natChain).AppendRule(ctx,
initialRuleGroup, `iifname "loopback0" ip daddr 127.0.0.0/8 counter return`)
}

View File

@@ -408,7 +408,7 @@ type ChainRef struct {
// It is an error to create a base chain that already exists.
// If the underlying chain already exists, it will be flushed by the
// next [TableRef.Apply] before new rules are added.
func (t TableRef) BaseChain(name string, chainType BaseChainType, hook BaseChainHook, priority int) (ChainRef, error) {
func (t TableRef) BaseChain(ctx context.Context, name string, chainType BaseChainType, hook BaseChainHook, priority int) (ChainRef, error) {
if _, ok := t.t.Chains[name]; ok {
return ChainRef{}, fmt.Errorf("chain %q already exists", name)
}
@@ -423,7 +423,7 @@ func (t TableRef) BaseChain(name string, chainType BaseChainType, hook BaseChain
ruleGroups: map[RuleGroup][]string{},
}
t.t.Chains[name] = c
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": t.t.Family,
"table": t.t.Name,
"chain": name,
@@ -442,7 +442,7 @@ func (t TableRef) BaseChain(name string, chainType BaseChainType, hook BaseChain
//
// If a new [ChainRef] is created and the underlying chain already exists, it
// will be flushed by the next [TableRef.Apply] before new rules are added.
func (t TableRef) Chain(name string) ChainRef {
func (t TableRef) Chain(ctx context.Context, name string) ChainRef {
c, ok := t.t.Chains[name]
if !ok {
c = &chain{
@@ -453,7 +453,7 @@ func (t TableRef) Chain(name string) ChainRef {
}
t.t.Chains[name] = c
}
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": t.t.Family,
"table": t.t.Name,
"chain": name,
@@ -462,14 +462,14 @@ func (t TableRef) Chain(name string) ChainRef {
}
// ChainUpdateFunc is a function that can add rules to a chain, or remove rules from it.
type ChainUpdateFunc func(RuleGroup, string, ...interface{}) error
type ChainUpdateFunc func(context.Context, RuleGroup, string, ...interface{}) error
// ChainUpdateFunc returns a [ChainUpdateFunc] to add rules to the named chain if
// enable is true, or to remove rules from the chain if enable is false.
// (Written as a convenience function to ease migration of iptables functions
// originally written with an enable flag.)
func (t TableRef) ChainUpdateFunc(name string, enable bool) ChainUpdateFunc {
c := t.Chain(name)
func (t TableRef) ChainUpdateFunc(ctx context.Context, name string, enable bool) ChainUpdateFunc {
c := t.Chain(ctx, name)
if enable {
return c.AppendRule
}
@@ -477,14 +477,14 @@ func (t TableRef) ChainUpdateFunc(name string, enable bool) ChainUpdateFunc {
}
// DeleteChain deletes a chain. It is an error to delete a chain that does not exist.
func (t TableRef) DeleteChain(name string) error {
func (t TableRef) DeleteChain(ctx context.Context, name string) error {
if _, ok := t.t.Chains[name]; !ok {
return fmt.Errorf("chain %q does not exist", name)
}
delete(t.t.Chains, name)
t.t.DeleteChainCommands = append(t.t.DeleteChainCommands,
fmt.Sprintf("delete chain %s %s %s", t.t.Family, t.t.Name, name))
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": t.t.Family,
"table": t.t.Name,
"chain": name,
@@ -504,7 +504,7 @@ func (c ChainRef) SetPolicy(policy string) error {
}
// AppendRule appends a rule to a [RuleGroup] in a [ChainRef].
func (c ChainRef) AppendRule(group RuleGroup, rule string, args ...interface{}) error {
func (c ChainRef) AppendRule(ctx context.Context, group RuleGroup, rule string, args ...interface{}) error {
if len(args) > 0 {
rule = fmt.Sprintf(rule, args...)
}
@@ -513,7 +513,7 @@ func (c ChainRef) AppendRule(group RuleGroup, rule string, args ...interface{})
}
c.c.ruleGroups[group] = append(c.c.ruleGroups[group], rule)
c.c.Dirty = true
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": c.c.table.Family,
"table": c.c.table.Name,
"chain": c.c.Name,
@@ -523,10 +523,18 @@ func (c ChainRef) AppendRule(group RuleGroup, rule string, args ...interface{})
return nil
}
// AppendRuleCf calls AppendRule and returns a cleanup function or an error.
func (c ChainRef) AppendRuleCf(ctx context.Context, group RuleGroup, rule string, args ...interface{}) (func(context.Context) error, error) {
if err := c.AppendRule(ctx, group, rule, args...); err != nil {
return nil, err
}
return func(ctx context.Context) error { return c.DeleteRule(ctx, group, rule, args...) }, nil
}
// DeleteRule deletes a rule from a [RuleGroup] in a [ChainRef]. It is an error
// to delete from a group that does not exist, or to delete a rule that does not
// exist.
func (c ChainRef) DeleteRule(group RuleGroup, rule string, args ...interface{}) error {
func (c ChainRef) DeleteRule(ctx context.Context, group RuleGroup, rule string, args ...interface{}) error {
if len(args) > 0 {
rule = fmt.Sprintf(rule, args...)
}
@@ -540,7 +548,7 @@ func (c ChainRef) DeleteRule(group RuleGroup, rule string, args ...interface{})
return fmt.Errorf("rule %q does not exist", rule)
}
c.c.Dirty = true
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": c.c.table.Family,
"table": c.c.table.Name,
"chain": c.c.Name,
@@ -578,7 +586,7 @@ type VMapRef struct {
//
// If a [VMapRef] is created and the underlying map already exists, it will be flushed
// by the next [TableRef.Apply] before new elements are added.
func (t TableRef) InterfaceVMap(name string) VMapRef {
func (t TableRef) InterfaceVMap(ctx context.Context, name string) VMapRef {
if vmap, ok := t.t.VMaps[name]; ok {
return VMapRef{vmap}
}
@@ -592,7 +600,7 @@ func (t TableRef) InterfaceVMap(name string) VMapRef {
Dirty: true,
}
t.t.VMaps[name] = vmap
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": t.t.Family,
"table": t.t.Name,
"vmap": name,
@@ -602,13 +610,13 @@ func (t TableRef) InterfaceVMap(name string) VMapRef {
// AddElement adds an element to a verdict map. The caller must ensure the key has
// the correct type. It is an error to add a key that already exists.
func (v VMapRef) AddElement(key string, verdict string) error {
func (v VMapRef) AddElement(ctx context.Context, key string, verdict string) error {
if _, ok := v.v.Elements[key]; ok {
return fmt.Errorf("verdict map already contains element %q", key)
}
v.v.Elements[key] = verdict
v.v.AddedElements[key] = verdict
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": v.v.table.Family,
"table": v.v.table.Name,
"vmap": v.v.Name,
@@ -618,15 +626,23 @@ func (v VMapRef) AddElement(key string, verdict string) error {
return nil
}
// AddElementCf calls AddElement and returns a cleanup function or an error.
func (v VMapRef) AddElementCf(ctx context.Context, key string, verdict string) (func(context.Context) error, error) {
if err := v.AddElement(ctx, key, verdict); err != nil {
return nil, err
}
return func(ctx context.Context) error { return v.DeleteElement(ctx, key) }, nil
}
// DeleteElement deletes an element from a verdict map. It is an error to delete
// an element that does not exist.
func (v VMapRef) DeleteElement(key string) error {
func (v VMapRef) DeleteElement(ctx context.Context, key string) error {
if _, ok := v.v.Elements[key]; !ok {
return fmt.Errorf("verdict map does not contain element %q", key)
}
delete(v.v.Elements, key)
v.v.DeletedElements[key] = struct{}{}
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": v.v.table.Family,
"table": v.v.table.Name,
"vmap": v.v.Name,
@@ -666,7 +682,7 @@ type SetRef struct {
// change if we need an "inet" table.)
//
// See https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets
func (t TableRef) PrefixSet(name string) SetRef {
func (t TableRef) PrefixSet(ctx context.Context, name string) SetRef {
if s, ok := t.t.Sets[name]; ok {
return SetRef{s}
}
@@ -684,7 +700,7 @@ func (t TableRef) PrefixSet(name string) SetRef {
s.ElementType = nftTypeIPv6Addr
}
t.t.Sets[name] = s
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": t.t.Family,
"table": t.t.Name,
"set": name,
@@ -695,13 +711,13 @@ func (t TableRef) PrefixSet(name string) SetRef {
// AddElement adds an element to a set. It is the caller's responsibility to make sure
// the element has the correct type. It is an error to add an element that is already
// in the set.
func (s SetRef) AddElement(element string) error {
func (s SetRef) AddElement(ctx context.Context, element string) error {
if _, ok := s.s.Elements[element]; ok {
return fmt.Errorf("set already contains element %q", element)
}
s.s.Elements[element] = struct{}{}
s.s.AddedElements[element] = struct{}{}
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": s.s.table.Family,
"table": s.s.table.Name,
"set": s.s.Name,
@@ -712,13 +728,13 @@ func (s SetRef) AddElement(element string) error {
// DeleteElement deletes an element from the set. It is an error to delete an
// element that is not in the set.
func (s SetRef) DeleteElement(element string) error {
func (s SetRef) DeleteElement(ctx context.Context, element string) error {
if _, ok := s.s.Elements[element]; !ok {
return fmt.Errorf("set does not contain element %q", element)
}
delete(s.s.Elements, element)
s.s.DeletedElements[element] = struct{}{}
log.G(context.TODO()).WithFields(log.Fields{
log.G(ctx).WithFields(log.Fields{
"family": s.s.table.Family,
"table": s.s.table.Name,
"set": s.s.Name,

View File

@@ -58,6 +58,7 @@ func TestTable(t *testing.T) {
func TestChain(t *testing.T) {
defer testSetup(t)()
ctx := context.Background()
// Create a table.
tbl, err := NewTable(IPv4, "this_is_a_table")
@@ -65,68 +66,68 @@ func TestChain(t *testing.T) {
// Create a base chain.
const bcName = "this_is_a_base_chain"
bc1, err := tbl.BaseChain(bcName, BaseChainTypeFilter, BaseChainHookForward, BaseChainPriorityFilter+10)
bc1, err := tbl.BaseChain(ctx, bcName, BaseChainTypeFilter, BaseChainHookForward, BaseChainPriorityFilter+10)
assert.NilError(t, err)
// Check that it's an error to add a new base chain with the same name.
_, err = tbl.BaseChain(bcName, BaseChainTypeNAT, BaseChainHookPrerouting, BaseChainPriorityDstNAT)
_, err = tbl.BaseChain(ctx, bcName, BaseChainTypeNAT, BaseChainHookPrerouting, BaseChainPriorityDstNAT)
assert.Check(t, is.ErrorContains(err, "already exists"))
// Add a rule.
err = bc1.AppendRule(0, "counter")
err = bc1.AppendRule(ctx, 0, "counter")
assert.NilError(t, err)
// Add a regular chain.
const regularChainName = "this_is_a_regular_chain"
_ = tbl.Chain(regularChainName)
_ = tbl.Chain(ctx, regularChainName)
// Add a rule to the regular chain, use string formatting and a func retrieved
// from the table.
f := tbl.ChainUpdateFunc(regularChainName, true)
err = f(0, "counter %s", "accept")
f := tbl.ChainUpdateFunc(ctx, regularChainName, true)
err = f(ctx, 0, "counter %s", "accept")
assert.Check(t, err)
// Fetch the base chain by name.
bc1 = tbl.Chain(bcName)
bc1 = tbl.Chain(ctx, bcName)
// Add another rule to the base chain, using the newly-retrieved handle.
err = bc1.AppendRule(0, "jump %s", regularChainName)
err = bc1.AppendRule(ctx, 0, "jump %s", regularChainName)
assert.Check(t, err)
// Update nftables and check what happened.
applyAndCheck(t, tbl, t.Name()+"_created.golden")
// Delete a rule from the base chain.
f = tbl.ChainUpdateFunc(bcName, false)
err = f(0, "counter")
f = tbl.ChainUpdateFunc(ctx, bcName, false)
err = f(ctx, 0, "counter")
assert.Check(t, err)
// Check it's an error to delete that rule again. This time, call the delete
// function directly on a newly retrieved handle.
err = tbl.Chain(bcName).DeleteRule(0, "counter")
err = tbl.Chain(ctx, bcName).DeleteRule(ctx, 0, "counter")
assert.Check(t, is.ErrorContains(err, "does not exist"))
// Update the base chain's policy.
err = tbl.Chain(bcName).SetPolicy("drop")
err = tbl.Chain(ctx, bcName).SetPolicy("drop")
assert.Check(t, err)
// Check it's an error to set a policy on a regular chain.
err = tbl.Chain(regularChainName).SetPolicy("drop")
err = tbl.Chain(ctx, regularChainName).SetPolicy("drop")
assert.Check(t, is.ErrorContains(err, "not a base chain"))
// Update nftables and check what happened.
applyAndCheck(t, tbl, t.Name()+"_modified.golden")
// Delete the base chain.
err = tbl.DeleteChain(bcName)
err = tbl.DeleteChain(ctx, bcName)
assert.Check(t, err)
// Delete the regular chain.
err = tbl.DeleteChain(regularChainName)
err = tbl.DeleteChain(ctx, regularChainName)
assert.Check(t, err)
// Check that it's an error to delete it again.
err = tbl.DeleteChain(regularChainName)
err = tbl.DeleteChain(ctx, regularChainName)
assert.Check(t, is.ErrorContains(err, "does not exist"))
// Update nftables and check what happened.
@@ -135,19 +136,20 @@ func TestChain(t *testing.T) {
func TestChainRuleGroups(t *testing.T) {
defer testSetup(t)()
ctx := context.Background()
tbl, err := NewTable(IPv4, "testtable")
assert.NilError(t, err)
c := tbl.Chain("testchain")
err = c.AppendRule(100, "hello100")
c := tbl.Chain(ctx, "testchain")
err = c.AppendRule(ctx, 100, "hello100")
assert.Check(t, err)
err = c.AppendRule(200, "hello200")
err = c.AppendRule(ctx, 200, "hello200")
assert.Check(t, err)
err = c.AppendRule(100, "hello101")
err = c.AppendRule(ctx, 100, "hello101")
assert.Check(t, err)
err = c.AppendRule(200, "hello201")
err = c.AppendRule(ctx, 200, "hello201")
assert.Check(t, err)
err = c.AppendRule(100, "hello102")
err = c.AppendRule(ctx, 100, "hello102")
assert.Check(t, err)
assert.Check(t, is.DeepEqual(c.c.Rules(), []string{
@@ -158,6 +160,7 @@ func TestChainRuleGroups(t *testing.T) {
func TestVMap(t *testing.T) {
defer testSetup(t)()
ctx := context.Background()
// Create a table.
tbl, err := NewTable(IPv6, "this_is_a_table")
@@ -165,32 +168,32 @@ func TestVMap(t *testing.T) {
// Create a verdict map.
const mapName = "this_is_a_vmap"
m := tbl.InterfaceVMap(mapName)
m := tbl.InterfaceVMap(ctx, mapName)
// Add an element.
err = m.AddElement("eth0", "return")
err = m.AddElement(ctx, "eth0", "return")
assert.Check(t, err)
// Check that it's an error to add the element again.
err = m.AddElement("eth0", "return")
err = m.AddElement(ctx, "eth0", "return")
assert.Check(t, is.ErrorContains(err, "already contains element"))
// Fetch the existing vmap.
m = tbl.InterfaceVMap(mapName)
m = tbl.InterfaceVMap(ctx, mapName)
// Add another element.
err = m.AddElement("eth1", "drop")
err = m.AddElement(ctx, "eth1", "drop")
assert.Check(t, err)
// Update nftables and check what happened.
applyAndCheck(t, tbl, t.Name()+"_created.golden")
// Delete an element.
err = m.DeleteElement("eth1")
err = m.DeleteElement(ctx, "eth1")
assert.Check(t, err)
// Check it's an error to delete it again.
err = m.DeleteElement("eth1")
err = m.DeleteElement(ctx, "eth1")
assert.Check(t, is.ErrorContains(err, "does not contain element"))
// Update nftables and check what happened.
@@ -199,6 +202,7 @@ func TestVMap(t *testing.T) {
func TestSet(t *testing.T) {
defer testSetup(t)()
ctx := context.Background()
// Create v4 and v6 tables.
tbl4, err := NewTable(IPv4, "table4")
@@ -207,19 +211,19 @@ func TestSet(t *testing.T) {
assert.NilError(t, err)
// Create a set in each table.
s4 := tbl4.PrefixSet("set4")
s6 := tbl6.PrefixSet("set6")
s4 := tbl4.PrefixSet(ctx, "set4")
s6 := tbl6.PrefixSet(ctx, "set6")
// Add elements to each set.
err = s4.AddElement("192.0.2.1/24")
err = s4.AddElement(ctx, "192.0.2.1/24")
assert.Check(t, err)
err = s6.AddElement("2001:db8::1/64")
err = s6.AddElement(ctx, "2001:db8::1/64")
assert.Check(t, err)
// Check it's an error to add those elements again.
err = s4.AddElement("192.0.2.1/24")
err = s4.AddElement(ctx, "192.0.2.1/24")
assert.Check(t, is.ErrorContains(err, "already contains element"))
err = s6.AddElement("2001:db8::1/64")
err = s6.AddElement(ctx, "2001:db8::1/64")
assert.Check(t, is.ErrorContains(err, "already contains element"))
// Update nftables and check what happened.
@@ -227,15 +231,15 @@ func TestSet(t *testing.T) {
applyAndCheck(t, tbl6, t.Name()+"_created46.golden")
// Delete elements.
err = s4.DeleteElement("192.0.2.1/24")
err = s4.DeleteElement(ctx, "192.0.2.1/24")
assert.Check(t, err)
err = s6.DeleteElement("2001:db8::1/64")
err = s6.DeleteElement(ctx, "2001:db8::1/64")
assert.Check(t, err)
// Check it's an error to delete those elements again.
err = s4.DeleteElement("192.0.2.1/24")
err = s4.DeleteElement(ctx, "192.0.2.1/24")
assert.Check(t, is.ErrorContains(err, "does not contain element"))
err = s6.DeleteElement("2001:db8::1/64")
err = s6.DeleteElement(ctx, "2001:db8::1/64")
assert.Check(t, is.ErrorContains(err, "does not contain element"))
// Update nftables and check what happened.
@@ -245,21 +249,22 @@ func TestSet(t *testing.T) {
func TestReload(t *testing.T) {
defer testSetup(t)()
ctx := context.Background()
// Create a table with some stuff in it.
const tableName = "this_is_a_table"
tbl, err := NewTable(IPv4, tableName)
assert.NilError(t, err)
bc, err := tbl.BaseChain("a_base_chain", BaseChainTypeFilter, BaseChainHookForward, BaseChainPriorityFilter)
bc, err := tbl.BaseChain(ctx, "a_base_chain", BaseChainTypeFilter, BaseChainHookForward, BaseChainPriorityFilter)
assert.NilError(t, err)
err = bc.AppendRule(0, "counter")
err = bc.AppendRule(ctx, 0, "counter")
assert.NilError(t, err)
m := tbl.InterfaceVMap("this_is_a_vmap")
err = m.AddElement("eth0", "return")
m := tbl.InterfaceVMap(ctx, "this_is_a_vmap")
err = m.AddElement(ctx, "eth0", "return")
assert.Check(t, err)
err = m.AddElement("eth1", "return")
err = m.AddElement(ctx, "eth1", "return")
assert.Check(t, err)
err = tbl.PrefixSet("set4").AddElement("192.0.2.0/24")
err = tbl.PrefixSet(ctx, "set4").AddElement(ctx, "192.0.2.0/24")
assert.Check(t, err)
applyAndCheck(t, tbl, t.Name()+"_created.golden")
@@ -284,7 +289,7 @@ func TestReload(t *testing.T) {
// Check implicit/recovery reload - only deleting something that's gone missing
// from a vmap/set will trigger this.
err = m.DeleteElement("eth1")
err = m.DeleteElement(ctx, "eth1")
assert.Check(t, err)
applyAndCheck(t, tbl, t.Name()+"_recovered.golden")
}

View File

@@ -98,25 +98,25 @@ func (r *Resolver) setupNftablesNAT(ctx context.Context, laddr, ltcpaddr, resolv
return err
}
dnatChain, err := table.BaseChain("dns-dnat", nftables.BaseChainTypeNAT, nftables.BaseChainHookOutput, nftables.BaseChainPriorityDstNAT)
dnatChain, err := table.BaseChain(ctx, "dns-dnat", nftables.BaseChainTypeNAT, nftables.BaseChainHookOutput, nftables.BaseChainPriorityDstNAT)
if err != nil {
return err
}
if err := dnatChain.AppendRule(0, "ip daddr %s udp dport %s counter dnat to %s", resolverIP, dnsPort, laddr); err != nil {
if err := dnatChain.AppendRule(ctx, 0, "ip daddr %s udp dport %s counter dnat to %s", resolverIP, dnsPort, laddr); err != nil {
return err
}
if err := dnatChain.AppendRule(0, "ip daddr %s tcp dport %s counter dnat to %s", resolverIP, dnsPort, ltcpaddr); err != nil {
if err := dnatChain.AppendRule(ctx, 0, "ip daddr %s tcp dport %s counter dnat to %s", resolverIP, dnsPort, ltcpaddr); err != nil {
return err
}
snatChain, err := table.BaseChain("dns-snat", nftables.BaseChainTypeNAT, nftables.BaseChainHookPostrouting, nftables.BaseChainPrioritySrcNAT)
snatChain, err := table.BaseChain(ctx, "dns-snat", nftables.BaseChainTypeNAT, nftables.BaseChainHookPostrouting, nftables.BaseChainPrioritySrcNAT)
if err != nil {
return err
}
if err := snatChain.AppendRule(0, "ip saddr %s udp sport %s counter snat to :%s", resolverIP, ipPort, dnsPort); err != nil {
if err := snatChain.AppendRule(ctx, 0, "ip saddr %s udp sport %s counter snat to :%s", resolverIP, ipPort, dnsPort); err != nil {
return err
}
if err := snatChain.AppendRule(0, "ip saddr %s tcp sport %s counter snat to :%s", resolverIP, tcpPort, dnsPort); err != nil {
if err := snatChain.AppendRule(ctx, 0, "ip saddr %s tcp sport %s counter snat to :%s", resolverIP, tcpPort, dnsPort); err != nil {
return err
}