This commit is contained in:
Alex Stockinger 2022-10-20 12:29:41 +02:00 committed by GitHub
commit ae7ba8247f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 367 additions and 126 deletions

2
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/campoy/embedmd v1.0.0 github.com/campoy/embedmd v1.0.0
github.com/containernetworking/cni v1.0.1 github.com/containernetworking/cni v1.0.1
github.com/containernetworking/plugins v1.1.1 github.com/containernetworking/plugins v1.1.1
github.com/coreos/go-iptables v0.6.0 github.com/coreos/go-iptables v0.6.1-0.20220901214115-d2b8608923d1
github.com/go-kit/kit v0.9.0 github.com/go-kit/kit v0.9.0
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
github.com/metalmatze/signal v0.0.0-20210307161603-1c9aa721a97a github.com/metalmatze/signal v0.0.0-20210307161603-1c9aa721a97a

4
go.sum
View File

@ -106,8 +106,8 @@ github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNG
github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.1-0.20220901214115-d2b8608923d1 h1:zSiUKnogKeEwIIeUQP/WPH7m0BJ/IvW0VyL4muaauUY=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-iptables v0.6.1-0.20220901214115-d2b8608923d1/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=

View File

@ -96,8 +96,8 @@ func (f *cilium) Init(_ int) error {
} }
// Rules is a no-op. // Rules is a no-op.
func (f *cilium) Rules(_ []*net.IPNet) []iptables.Rule { func (f *cilium) Rules(_ []*net.IPNet) iptables.RuleSet {
return nil return iptables.RuleSet{}
} }
// Set is a no-op. // Set is a no-op.

View File

@ -49,7 +49,7 @@ type Encapsulator interface {
Gw(net.IP, net.IP, *net.IPNet) net.IP Gw(net.IP, net.IP, *net.IPNet) net.IP
Index() int Index() int
Init(int) error Init(int) error
Rules([]*net.IPNet) []iptables.Rule Rules([]*net.IPNet) iptables.RuleSet
Set(*net.IPNet) error Set(*net.IPNet) error
Strategy() Strategy Strategy() Strategy
} }

View File

@ -95,8 +95,8 @@ func (f *flannel) Init(_ int) error {
} }
// Rules is a no-op. // Rules is a no-op.
func (f *flannel) Rules(_ []*net.IPNet) []iptables.Rule { func (f *flannel) Rules(_ []*net.IPNet) iptables.RuleSet {
return nil return iptables.RuleSet{}
} }
// Set is a no-op. // Set is a no-op.

View File

@ -65,20 +65,20 @@ func (i *ipip) Init(base int) error {
// Rules returns a set of iptables rules that are necessary // Rules returns a set of iptables rules that are necessary
// when traffic between nodes must be encapsulated. // when traffic between nodes must be encapsulated.
func (i *ipip) Rules(nodes []*net.IPNet) []iptables.Rule { func (i *ipip) Rules(nodes []*net.IPNet) iptables.RuleSet {
var rules []iptables.Rule rules := iptables.RuleSet{}
proto := ipipProtocolName() proto := ipipProtocolName()
rules = append(rules, iptables.NewIPv4Chain("filter", "KILO-IPIP")) rules.AddToAppend(iptables.NewIPv4Chain("filter", "KILO-IPIP"))
rules = append(rules, iptables.NewIPv6Chain("filter", "KILO-IPIP")) rules.AddToAppend(iptables.NewIPv6Chain("filter", "KILO-IPIP"))
rules = append(rules, iptables.NewIPv4Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: jump to IPIP chain", "-j", "KILO-IPIP")) rules.AddToAppend(iptables.NewIPv4Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: jump to IPIP chain", "-j", "KILO-IPIP"))
rules = append(rules, iptables.NewIPv6Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: jump to IPIP chain", "-j", "KILO-IPIP")) rules.AddToAppend(iptables.NewIPv6Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: jump to IPIP chain", "-j", "KILO-IPIP"))
for _, n := range nodes { for _, n := range nodes {
// Accept encapsulated traffic from peers. // Accept encapsulated traffic from peers.
rules = append(rules, iptables.NewRule(iptables.GetProtocol(n.IP), "filter", "KILO-IPIP", "-s", n.String(), "-m", "comment", "--comment", "Kilo: allow IPIP traffic", "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(n.IP), "filter", "KILO-IPIP", "-s", n.String(), "-m", "comment", "--comment", "Kilo: allow IPIP traffic", "-j", "ACCEPT"))
} }
// Drop all other IPIP traffic. // Drop all other IPIP traffic.
rules = append(rules, iptables.NewIPv4Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: reject other IPIP traffic", "-j", "DROP")) rules.AddToAppend(iptables.NewIPv4Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: reject other IPIP traffic", "-j", "DROP"))
rules = append(rules, iptables.NewIPv6Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: reject other IPIP traffic", "-j", "DROP")) rules.AddToAppend(iptables.NewIPv6Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: reject other IPIP traffic", "-j", "DROP"))
return rules return rules
} }

View File

@ -44,8 +44,8 @@ func (n Noop) Init(_ int) error {
} }
// Rules will also do nothing. // Rules will also do nothing.
func (n Noop) Rules(_ []*net.IPNet) []iptables.Rule { func (n Noop) Rules(_ []*net.IPNet) iptables.RuleSet {
return nil return iptables.RuleSet{}
} }
// Set will also do nothing. // Set will also do nothing.

View File

@ -46,6 +46,24 @@ type fakeClient struct {
var _ Client = &fakeClient{} var _ Client = &fakeClient{}
func (f *fakeClient) InsertUnique(table, chain string, pos int, spec ...string) error {
atomic.AddUint64(&f.calls, 1)
exists, err := f.Exists(table, chain, spec...)
if err != nil {
return err
}
if exists {
return nil
}
index := pos - 1 // iptables are 1-based
rule := &rule{table: table, chain: chain, spec: spec}
prefix := append([]Rule{}, f.storage[:index]...)
suffix := append([]Rule{}, f.storage[index:]...)
prefix = append(prefix, rule)
f.storage = append(prefix, suffix...)
return nil
}
func (f *fakeClient) AppendUnique(table, chain string, spec ...string) error { func (f *fakeClient) AppendUnique(table, chain string, spec ...string) error {
atomic.AddUint64(&f.calls, 1) atomic.AddUint64(&f.calls, 1)
exists, err := f.Exists(table, chain, spec...) exists, err := f.Exists(table, chain, spec...)

View File

@ -46,6 +46,11 @@ func ipv6Disabled() (bool, error) {
// Protocol represents an IP protocol. // Protocol represents an IP protocol.
type Protocol byte type Protocol byte
type RuleSet struct {
appendRules []Rule // Rules to append to the chain - order matters.
prependRules []Rule // Rules to prepend to the chain - order does not matter.
}
const ( const (
// ProtocolIPv4 represents the IPv4 protocol. // ProtocolIPv4 represents the IPv4 protocol.
ProtocolIPv4 Protocol = iota ProtocolIPv4 Protocol = iota
@ -53,6 +58,21 @@ const (
ProtocolIPv6 ProtocolIPv6
) )
func (rs *RuleSet) AddToAppend(rule Rule) {
rs.appendRules = append(rs.appendRules, rule)
}
func (rs *RuleSet) AddToPrepend(rule Rule) {
rs.prependRules = append(rs.prependRules, rule)
}
func (rs *RuleSet) AppendRuleSet(other RuleSet) RuleSet {
return RuleSet{
appendRules: append(rs.appendRules, other.appendRules...),
prependRules: append(rs.prependRules, other.prependRules...),
}
}
// GetProtocol will return a protocol from the length of an IP address. // GetProtocol will return a protocol from the length of an IP address.
func GetProtocol(ip net.IP) Protocol { func GetProtocol(ip net.IP) Protocol {
if len(ip) == net.IPv4len || ip.To4() != nil { if len(ip) == net.IPv4len || ip.To4() != nil {
@ -64,6 +84,7 @@ func GetProtocol(ip net.IP) Protocol {
// Client represents any type that can administer iptables rules. // Client represents any type that can administer iptables rules.
type Client interface { type Client interface {
AppendUnique(table string, chain string, rule ...string) error AppendUnique(table string, chain string, rule ...string) error
InsertUnique(table, chain string, pos int, rule ...string) error
Delete(table string, chain string, rule ...string) error Delete(table string, chain string, rule ...string) error
Exists(table string, chain string, rule ...string) (bool, error) Exists(table string, chain string, rule ...string) (bool, error)
List(table string, chain string) ([]string, error) List(table string, chain string) ([]string, error)
@ -75,7 +96,8 @@ type Client interface {
// Rule is an interface for interacting with iptables objects. // Rule is an interface for interacting with iptables objects.
type Rule interface { type Rule interface {
Add(Client) error Append(Client) error
Prepend(Client) error
Delete(Client) error Delete(Client) error
Exists(Client) (bool, error) Exists(Client) (bool, error)
String() string String() string
@ -106,7 +128,14 @@ func NewIPv6Rule(table, chain string, spec ...string) Rule {
return &rule{table, chain, spec, ProtocolIPv6} return &rule{table, chain, spec, ProtocolIPv6}
} }
func (r *rule) Add(client Client) error { func (r *rule) Prepend(client Client) error {
if err := client.InsertUnique(r.table, r.chain, 1, r.spec...); err != nil {
return fmt.Errorf("failed to add iptables rule: %v", err)
}
return nil
}
func (r *rule) Append(client Client) error {
if err := client.AppendUnique(r.table, r.chain, r.spec...); err != nil { if err := client.AppendUnique(r.table, r.chain, r.spec...); err != nil {
return fmt.Errorf("failed to add iptables rule: %v", err) return fmt.Errorf("failed to add iptables rule: %v", err)
} }
@ -162,7 +191,11 @@ func NewIPv6Chain(table, name string) Rule {
return &chain{table, name, ProtocolIPv6} return &chain{table, name, ProtocolIPv6}
} }
func (c *chain) Add(client Client) error { func (c *chain) Prepend(client Client) error {
return c.Append(client)
}
func (c *chain) Append(client Client) error {
// Note: `ClearChain` creates a chain if it does not exist. // Note: `ClearChain` creates a chain if it does not exist.
if err := client.ClearChain(c.table, c.chain); err != nil { if err := client.ClearChain(c.table, c.chain); err != nil {
return fmt.Errorf("failed to add iptables chain: %v", err) return fmt.Errorf("failed to add iptables chain: %v", err)
@ -224,8 +257,9 @@ type Controller struct {
registerer prometheus.Registerer registerer prometheus.Registerer
sync.Mutex sync.Mutex
rules []Rule appendRules []Rule
subscribed bool prependRules []Rule
subscribed bool
} }
// ControllerOption modifies the controller's configuration. // ControllerOption modifies the controller's configuration.
@ -333,14 +367,21 @@ func (c *Controller) reconcile() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
var rc ruleCache var rc ruleCache
for i, r := range c.rules { if err := c.reconcileAppendRules(rc); err != nil {
return err
}
return c.reconcilePrependRules(rc)
}
func (c *Controller) reconcileAppendRules(rc ruleCache) error {
for i, r := range c.appendRules {
ok, err := rc.exists(c.client(r.Proto()), r) ok, err := rc.exists(c.client(r.Proto()), r)
if err != nil { if err != nil {
return fmt.Errorf("failed to check if rule exists: %v", err) return fmt.Errorf("failed to check if rule exists: %v", err)
} }
if !ok { if !ok {
level.Info(c.logger).Log("msg", fmt.Sprintf("applying %d iptables rules", len(c.rules)-i)) level.Info(c.logger).Log("msg", fmt.Sprintf("applying %d iptables rules", len(c.appendRules)-i))
if err := c.resetFromIndex(i, c.rules); err != nil { if err := c.resetFromIndex(i, c.appendRules); err != nil {
return fmt.Errorf("failed to add rule: %v", err) return fmt.Errorf("failed to add rule: %v", err)
} }
break break
@ -349,6 +390,22 @@ func (c *Controller) reconcile() error {
return nil return nil
} }
func (c *Controller) reconcilePrependRules(rc ruleCache) error {
for _, r := range c.prependRules {
ok, err := rc.exists(c.client(r.Proto()), r)
if err != nil {
return fmt.Errorf("failed to check if rule exists: %v", err)
}
if !ok {
level.Info(c.logger).Log("msg", "prepending iptables rule")
if err := r.Prepend(c.client(r.Proto())); err != nil {
return fmt.Errorf("failed to prepend rule: %v", err)
}
}
}
return nil
}
// resetFromIndex re-adds all rules starting from the given index. // resetFromIndex re-adds all rules starting from the given index.
func (c *Controller) resetFromIndex(i int, rules []Rule) error { func (c *Controller) resetFromIndex(i int, rules []Rule) error {
if i >= len(rules) { if i >= len(rules) {
@ -358,7 +415,7 @@ func (c *Controller) resetFromIndex(i int, rules []Rule) error {
if err := rules[j].Delete(c.client(rules[j].Proto())); err != nil { if err := rules[j].Delete(c.client(rules[j].Proto())); err != nil {
return fmt.Errorf("failed to delete rule: %v", err) return fmt.Errorf("failed to delete rule: %v", err)
} }
if err := rules[j].Add(c.client(rules[j].Proto())); err != nil { if err := rules[j].Append(c.client(rules[j].Proto())); err != nil {
return fmt.Errorf("failed to add rule: %v", err) return fmt.Errorf("failed to add rule: %v", err)
} }
} }
@ -383,34 +440,87 @@ func (c *Controller) deleteFromIndex(i int, rules *[]Rule) error {
// Set idempotently overwrites any iptables rules previously defined // Set idempotently overwrites any iptables rules previously defined
// for the controller with the given set of rules. // for the controller with the given set of rules.
func (c *Controller) Set(rules []Rule) error { func (c *Controller) Set(rules RuleSet) error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
if err := c.setAppendRules(rules.appendRules); err != nil {
return err
}
return c.setPrependRules(rules.prependRules)
}
func (c *Controller) setAppendRules(appendRules []Rule) error {
var i int var i int
for ; i < len(rules); i++ { for ; i < len(appendRules); i++ {
if i < len(c.rules) { if i < len(c.appendRules) {
if rules[i].String() != c.rules[i].String() { if appendRules[i].String() != c.appendRules[i].String() {
if err := c.deleteFromIndex(i, &c.rules); err != nil { if err := c.deleteFromIndex(i, &c.appendRules); err != nil {
return err return err
} }
} }
} }
if i >= len(c.rules) { if i >= len(c.appendRules) {
if err := rules[i].Add(c.client(rules[i].Proto())); err != nil { if err := appendRules[i].Append(c.client(appendRules[i].Proto())); err != nil {
return fmt.Errorf("failed to add rule: %v", err) return fmt.Errorf("failed to add rule: %v", err)
} }
c.rules = append(c.rules, rules[i]) c.appendRules = append(c.appendRules, appendRules[i])
} }
} }
return c.deleteFromIndex(i, &c.rules) err := c.deleteFromIndex(i, &c.appendRules)
if err != nil {
return fmt.Errorf("failed to delete rule: %v", err)
}
return nil
}
func (c *Controller) setPrependRules(prependRules []Rule) error {
for _, prependRule := range prependRules {
if !containsRule(c.prependRules, prependRule) {
if err := prependRule.Prepend(c.client(prependRule.Proto())); err != nil {
return fmt.Errorf("failed to add rule: %v", err)
}
c.prependRules = append(c.prependRules, prependRule)
}
}
for _, existingRule := range c.prependRules {
if !containsRule(prependRules, existingRule) {
if err := existingRule.Delete(c.client(existingRule.Proto())); err != nil {
return fmt.Errorf("failed to delete rule: %v", err)
}
c.prependRules = removeRule(c.prependRules, existingRule)
}
}
return nil
}
func removeRule(rules []Rule, toRemove Rule) []Rule {
ret := make([]Rule, 0, len(rules))
for _, rule := range rules {
if rule.String() != toRemove.String() {
ret = append(ret, rule)
}
}
return ret
}
func containsRule(haystack []Rule, needle Rule) bool {
for _, element := range haystack {
if element.String() == needle.String() {
return true
}
}
return false
} }
// CleanUp will clean up any rules created by the controller. // CleanUp will clean up any rules created by the controller.
func (c *Controller) CleanUp() error { func (c *Controller) CleanUp() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
return c.deleteFromIndex(0, &c.rules) err := c.deleteFromIndex(0, &c.prependRules)
if err != nil {
return err
}
return c.deleteFromIndex(0, &c.appendRules)
} }
func (c *Controller) client(p Protocol) Client { func (c *Controller) client(p Protocol) Client {

View File

@ -18,70 +18,94 @@ import (
"testing" "testing"
) )
var rules = []Rule{ var appendRules = []Rule{
NewIPv4Rule("filter", "FORWARD", "-s", "10.4.0.0/16", "-j", "ACCEPT"), NewIPv4Rule("filter", "FORWARD", "-s", "10.4.0.0/16", "-j", "ACCEPT"),
NewIPv4Rule("filter", "FORWARD", "-d", "10.4.0.0/16", "-j", "ACCEPT"), NewIPv4Rule("filter", "FORWARD", "-d", "10.4.0.0/16", "-j", "ACCEPT"),
} }
var prependRules = []Rule{
NewIPv4Rule("filter", "FORWARD", "-s", "10.5.0.0/16", "-j", "DROP"),
NewIPv4Rule("filter", "FORWARD", "-s", "10.6.0.0/16", "-j", "DROP"),
}
func TestSet(t *testing.T) { func TestSet(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
name string name string
sets [][]Rule sets []RuleSet
out []Rule appendOut []Rule
actions []func(Client) error prependOut []Rule
storageOut []Rule
actions []func(Client) error
}{ }{
{ {
name: "empty", name: "empty",
}, },
{ {
name: "single", name: "single",
sets: [][]Rule{ sets: []RuleSet{
{rules[0]}, {appendRules: []Rule{appendRules[0]}},
}, },
out: []Rule{rules[0]}, appendOut: []Rule{appendRules[0]},
storageOut: []Rule{appendRules[0]},
}, },
{ {
name: "two rules", name: "two rules",
sets: [][]Rule{ sets: []RuleSet{
{rules[0], rules[1]}, {appendRules: []Rule{appendRules[0], appendRules[1]}},
}, },
out: []Rule{rules[0], rules[1]}, appendOut: []Rule{appendRules[0], appendRules[1]},
storageOut: []Rule{appendRules[0], appendRules[1]},
}, },
{ {
name: "multiple", name: "multiple",
sets: [][]Rule{ sets: []RuleSet{
{rules[0], rules[1]}, {appendRules: []Rule{appendRules[0], appendRules[1]}},
{rules[1]}, {appendRules: []Rule{appendRules[1]}},
}, },
out: []Rule{rules[1]}, appendOut: []Rule{appendRules[1]},
storageOut: []Rule{appendRules[1]},
}, },
{ {
name: "re-add", name: "re-add",
sets: [][]Rule{ sets: []RuleSet{
{rules[0], rules[1]}, {appendRules: []Rule{appendRules[0], appendRules[1]}},
}, },
out: []Rule{rules[0], rules[1]}, appendOut: []Rule{appendRules[0], appendRules[1]},
storageOut: []Rule{appendRules[0], appendRules[1]},
actions: []func(c Client) error{ actions: []func(c Client) error{
func(c Client) error { func(c Client) error {
return rules[0].Delete(c) return appendRules[0].Delete(c)
}, },
func(c Client) error { func(c Client) error {
return rules[1].Delete(c) return appendRules[1].Delete(c)
}, },
}, },
}, },
{ {
name: "order", name: "order",
sets: [][]Rule{ sets: []RuleSet{
{rules[0], rules[1]}, {appendRules: []Rule{appendRules[0], appendRules[1]}},
}, },
out: []Rule{rules[0], rules[1]}, appendOut: []Rule{appendRules[0], appendRules[1]},
storageOut: []Rule{appendRules[0], appendRules[1]},
actions: []func(c Client) error{ actions: []func(c Client) error{
func(c Client) error { func(c Client) error {
return rules[0].Delete(c) return appendRules[0].Delete(c)
}, },
}, },
}, },
{
name: "append and prepend",
sets: []RuleSet{
{
prependRules: []Rule{prependRules[0], prependRules[1]},
appendRules: []Rule{appendRules[0], appendRules[1]},
},
},
appendOut: []Rule{appendRules[0], appendRules[1]},
prependOut: []Rule{prependRules[0], prependRules[1]},
storageOut: []Rule{prependRules[1], prependRules[0], appendRules[0], appendRules[1]},
},
} { } {
client := &fakeClient{} client := &fakeClient{}
controller, err := New(WithClients(client, client)) controller, err := New(WithClients(client, client))
@ -90,7 +114,7 @@ func TestSet(t *testing.T) {
} }
for i := range tc.sets { for i := range tc.sets {
if err := controller.Set(tc.sets[i]); err != nil { if err := controller.Set(tc.sets[i]); err != nil {
t.Fatalf("test case %q: got unexpected error seting rule set %d: %v", tc.name, i, err) t.Fatalf("test case %q: got unexpected error setting rule set %d: %v", tc.name, i, err)
} }
} }
for i, f := range tc.actions { for i, f := range tc.actions {
@ -101,21 +125,30 @@ func TestSet(t *testing.T) {
if err := controller.reconcile(); err != nil { if err := controller.reconcile(); err != nil {
t.Fatalf("test case %q: got unexpected error %v", tc.name, err) t.Fatalf("test case %q: got unexpected error %v", tc.name, err)
} }
if len(tc.out) != len(client.storage) { if len(tc.storageOut) != len(client.storage) {
t.Errorf("test case %q: expected %d rules in storage, got %d", tc.name, len(tc.out), len(client.storage)) t.Errorf("test case %q: expected %d rules in storage, got %d", tc.name, len(tc.storageOut), len(client.storage))
} else { } else {
for i := range tc.out { for i := range tc.storageOut {
if tc.out[i].String() != client.storage[i].String() { if tc.storageOut[i].String() != client.storage[i].String() {
t.Errorf("test case %q: expected rule %d in storage to be equal: expected %v, got %v", tc.name, i, tc.out[i], client.storage[i]) t.Errorf("test case %q: expected rule %d in storage to be equal: expected %v, got %v", tc.name, i, tc.storageOut[i], client.storage[i])
} }
} }
} }
if len(tc.out) != len(controller.rules) { if len(tc.appendOut) != len(controller.appendRules) {
t.Errorf("test case %q: expected %d rules in controller, got %d", tc.name, len(tc.out), len(controller.rules)) t.Errorf("test case %q: expected %d appendRules in controller, got %d", tc.name, len(tc.appendOut), len(controller.appendRules))
} else { } else {
for i := range tc.out { for i := range tc.appendOut {
if tc.out[i].String() != controller.rules[i].String() { if tc.appendOut[i].String() != controller.appendRules[i].String() {
t.Errorf("test case %q: expected rule %d in controller to be equal: expected %v, got %v", tc.name, i, tc.out[i], controller.rules[i]) t.Errorf("test case %q: expected appendRule %d in controller to be equal: expected %v, got %v", tc.name, i, tc.appendOut[i], controller.appendRules[i])
}
}
}
if len(tc.prependOut) != len(controller.prependRules) {
t.Errorf("test case %q: expected %d prependRules in controller, got %d", tc.name, len(tc.prependOut), len(controller.prependRules))
} else {
for i := range tc.prependOut {
if tc.prependOut[i].String() != controller.prependRules[i].String() {
t.Errorf("test case %q: expected prependRule %d in controller to be equal: expected %v, got %v", tc.name, i, tc.prependOut[i], controller.prependRules[i])
} }
} }
} }
@ -124,20 +157,26 @@ func TestSet(t *testing.T) {
func TestCleanUp(t *testing.T) { func TestCleanUp(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
name string name string
rules []Rule appendRules []Rule
prependRules []Rule
}{ }{
{ {
name: "empty", name: "empty",
rules: nil, appendRules: nil,
}, },
{ {
name: "single", name: "single append",
rules: []Rule{rules[0]}, appendRules: []Rule{appendRules[0]},
}, },
{ {
name: "multiple", name: "multiple append",
rules: []Rule{rules[0], rules[1]}, appendRules: []Rule{appendRules[0], appendRules[1]},
},
{
name: "multiple append and prepend",
appendRules: []Rule{appendRules[0], appendRules[1]},
prependRules: []Rule{prependRules[0], prependRules[1]},
}, },
} { } {
client := &fakeClient{} client := &fakeClient{}
@ -145,11 +184,12 @@ func TestCleanUp(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("test case %q: got unexpected error instantiating controller: %v", tc.name, err) t.Fatalf("test case %q: got unexpected error instantiating controller: %v", tc.name, err)
} }
if err := controller.Set(tc.rules); err != nil { ruleSet := RuleSet{appendRules: tc.appendRules, prependRules: tc.prependRules}
if err := controller.Set(ruleSet); err != nil {
t.Fatalf("test case %q: Set should not fail: %v", tc.name, err) t.Fatalf("test case %q: Set should not fail: %v", tc.name, err)
} }
if len(client.storage) != len(tc.rules) { if len(client.storage) != len(tc.appendRules)+len(tc.prependRules) {
t.Errorf("test case %q: expected %d rules in storage, got %d rules", tc.name, len(tc.rules), len(client.storage)) t.Errorf("test case %q: expected %d rules in storage, got %d rules", tc.name, len(ruleSet.appendRules)+len(ruleSet.prependRules), len(client.storage))
} }
if err := controller.CleanUp(); err != nil { if err := controller.CleanUp(); err != nil {
t.Errorf("test case %q: got unexpected error: %v", tc.name, err) t.Errorf("test case %q: got unexpected error: %v", tc.name, err)
@ -159,3 +199,42 @@ func TestCleanUp(t *testing.T) {
} }
} }
} }
func TestReconcile(t *testing.T) {
for _, tc := range []struct {
name string
appendRules []Rule
prependRules []Rule
storageOut []Rule
}{
{
name: "append and prepend rules",
appendRules: []Rule{appendRules[0], appendRules[1]},
prependRules: []Rule{prependRules[0], prependRules[1]},
storageOut: []Rule{prependRules[1], prependRules[0], appendRules[0], appendRules[1]},
},
} {
client := &fakeClient{}
controller, err := New(WithClients(client, client))
if err != nil {
t.Fatalf("test case %q: got unexpected error instantiating controller: %v", tc.name, err)
}
controller.appendRules = tc.appendRules
controller.prependRules = tc.prependRules
err = controller.reconcile()
if err != nil {
t.Fatalf("test case %q: unexpected error during reconcile: %v", tc.name, err)
}
if len(tc.storageOut) != len(client.storage) {
t.Errorf("test case %q: expected %d rules in storage, got %d", tc.name, len(tc.storageOut), len(client.storage))
} else {
for i := range tc.storageOut {
if tc.storageOut[i].String() != client.storage[i].String() {
t.Errorf("test case %q: expected rule %d in storage to be equal: expected %v, got %v", tc.name, i, tc.storageOut[i], client.storage[i])
}
}
}
}
}

View File

@ -51,6 +51,15 @@ func (m *metricsClientWrapper) AppendUnique(table string, chain string, rule ...
return m.client.AppendUnique(table, chain, rule...) return m.client.AppendUnique(table, chain, rule...)
} }
func (m *metricsClientWrapper) InsertUnique(table, chain string, pos int, rule ...string) error {
m.operationCounter.With(prometheus.Labels{
"operation": "InsertUnique",
"table": table,
"chain": chain,
}).Inc()
return m.client.InsertUnique(table, chain, pos, rule...)
}
func (m *metricsClientWrapper) Delete(table string, chain string, rule ...string) error { func (m *metricsClientWrapper) Delete(table string, chain string, rule ...string) error {
m.operationCounter.With(prometheus.Labels{ m.operationCounter.With(prometheus.Labels{
"operation": "Delete", "operation": "Delete",

View File

@ -29,21 +29,21 @@ func TestRuleCache(t *testing.T) {
{ {
name: "empty", name: "empty",
rules: nil, rules: nil,
check: []Rule{rules[0]}, check: []Rule{appendRules[0]},
out: []bool{false}, out: []bool{false},
calls: 1, calls: 1,
}, },
{ {
name: "single negative", name: "single negative",
rules: []Rule{rules[1]}, rules: []Rule{appendRules[1]},
check: []Rule{rules[0]}, check: []Rule{appendRules[0]},
out: []bool{false}, out: []bool{false},
calls: 1, calls: 1,
}, },
{ {
name: "single positive", name: "single positive",
rules: []Rule{rules[1]}, rules: []Rule{appendRules[1]},
check: []Rule{rules[1]}, check: []Rule{appendRules[1]},
out: []bool{true}, out: []bool{true},
calls: 1, calls: 1,
}, },
@ -56,29 +56,29 @@ func TestRuleCache(t *testing.T) {
}, },
{ {
name: "rule on chain means chain exists", name: "rule on chain means chain exists",
rules: []Rule{rules[0]}, rules: []Rule{appendRules[0]},
check: []Rule{rules[0], &chain{"filter", "FORWARD", ProtocolIPv4}}, check: []Rule{appendRules[0], &chain{"filter", "FORWARD", ProtocolIPv4}},
out: []bool{true, true}, out: []bool{true, true},
calls: 1, calls: 1,
}, },
{ {
name: "rule on chain does not mean table is fully populated", name: "rule on chain does not mean table is fully populated",
rules: []Rule{rules[0], &chain{"filter", "INPUT", ProtocolIPv4}}, rules: []Rule{appendRules[0], &chain{"filter", "INPUT", ProtocolIPv4}},
check: []Rule{rules[0], &chain{"filter", "OUTPUT", ProtocolIPv4}, &chain{"filter", "INPUT", ProtocolIPv4}}, check: []Rule{appendRules[0], &chain{"filter", "OUTPUT", ProtocolIPv4}, &chain{"filter", "INPUT", ProtocolIPv4}},
out: []bool{true, false, true}, out: []bool{true, false, true},
calls: 2, calls: 2,
}, },
{ {
name: "multiple rules on chain", name: "multiple rules on chain",
rules: []Rule{rules[0], rules[1]}, rules: []Rule{appendRules[0], appendRules[1]},
check: []Rule{rules[0], rules[1], &chain{"filter", "FORWARD", ProtocolIPv4}}, check: []Rule{appendRules[0], appendRules[1], &chain{"filter", "FORWARD", ProtocolIPv4}},
out: []bool{true, true, true}, out: []bool{true, true, true},
calls: 1, calls: 1,
}, },
{ {
name: "checking rule on chain does not mean chain exists", name: "checking rule on chain does not mean chain exists",
rules: nil, rules: nil,
check: []Rule{rules[0], &chain{"filter", "FORWARD", ProtocolIPv4}}, check: []Rule{appendRules[0], &chain{"filter", "FORWARD", ProtocolIPv4}},
out: []bool{false, false}, out: []bool{false, false},
calls: 2, calls: 2,
}, },
@ -101,7 +101,8 @@ func TestRuleCache(t *testing.T) {
client := &fakeClient{} client := &fakeClient{}
controller.v4 = client controller.v4 = client
controller.v6 = client controller.v6 = client
if err := controller.Set(tc.rules); err != nil { ruleSet := RuleSet{appendRules: tc.rules}
if err := controller.Set(ruleSet); err != nil {
t.Fatalf("test case %q: Set should not fail: %v", tc.name, err) t.Fatalf("test case %q: Set should not fail: %v", tc.name, err)
} }
// Reset the client's calls so we can examine how many times // Reset the client's calls so we can examine how many times

View File

@ -525,7 +525,8 @@ func (m *Mesh) applyTopology() {
} }
} }
ipRules = append(m.enc.Rules(cidrs), ipRules...) encIpRules := m.enc.Rules(cidrs)
ipRules = encIpRules.AppendRuleSet(ipRules)
// If we are handling local routes, ensure the local // If we are handling local routes, ensure the local
// tunnel has an IP address. // tunnel has an IP address.

View File

@ -311,12 +311,12 @@ func encapsulateRoute(route *netlink.Route, encapsulate encapsulation.Strategy,
} }
// Rules returns the iptables rules required by the local node. // Rules returns the iptables rules required by the local node.
func (t *Topology) Rules(cni, iptablesForwardRule bool) []iptables.Rule { func (t *Topology) Rules(cni, iptablesForwardRule bool) iptables.RuleSet {
var rules []iptables.Rule rules := iptables.RuleSet{}
rules = append(rules, iptables.NewIPv4Chain("nat", "KILO-NAT")) rules.AddToAppend(iptables.NewIPv4Chain("nat", "KILO-NAT"))
rules = append(rules, iptables.NewIPv6Chain("nat", "KILO-NAT")) rules.AddToAppend(iptables.NewIPv6Chain("nat", "KILO-NAT"))
if cni { if cni {
rules = append(rules, iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "nat", "POSTROUTING", "-s", t.subnet.String(), "-m", "comment", "--comment", "Kilo: jump to KILO-NAT chain", "-j", "KILO-NAT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "nat", "POSTROUTING", "-s", t.subnet.String(), "-m", "comment", "--comment", "Kilo: jump to KILO-NAT chain", "-j", "KILO-NAT"))
// Some linux distros or docker will set forward DROP in the filter table. // Some linux distros or docker will set forward DROP in the filter table.
// To still be able to have pod to pod communication we need to ALLOW packets from and to pod CIDRs within a location. // To still be able to have pod to pod communication we need to ALLOW packets from and to pod CIDRs within a location.
// Leader nodes will forward packets from all nodes within a location because they act as a gateway for them. // Leader nodes will forward packets from all nodes within a location because they act as a gateway for them.
@ -326,52 +326,48 @@ func (t *Topology) Rules(cni, iptablesForwardRule bool) []iptables.Rule {
if s.location == t.location { if s.location == t.location {
// Make sure packets to and from pod cidrs are not dropped in the forward chain. // Make sure packets to and from pod cidrs are not dropped in the forward chain.
for _, c := range s.cidrs { for _, c := range s.cidrs {
rules = append(rules, iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from the pod subnet", "-s", c.String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from the pod subnet", "-s", c.String(), "-j", "ACCEPT"))
rules = append(rules, iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to the pod subnet", "-d", c.String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to the pod subnet", "-d", c.String(), "-j", "ACCEPT"))
} }
// Make sure packets to and from allowed location IPs are not dropped in the forward chain. // Make sure packets to and from allowed location IPs are not dropped in the forward chain.
for _, c := range s.allowedLocationIPs { for _, c := range s.allowedLocationIPs {
rules = append(rules, iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from allowed location IPs", "-s", c.String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from allowed location IPs", "-s", c.String(), "-j", "ACCEPT"))
rules = append(rules, iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to allowed location IPs", "-d", c.String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(c.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to allowed location IPs", "-d", c.String(), "-j", "ACCEPT"))
} }
// Make sure packets to and from private IPs are not dropped in the forward chain. // Make sure packets to and from private IPs are not dropped in the forward chain.
for _, c := range s.privateIPs { for _, c := range s.privateIPs {
rules = append(rules, iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from private IPs", "-s", oneAddressCIDR(c).String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from private IPs", "-s", oneAddressCIDR(c).String(), "-j", "ACCEPT"))
rules = append(rules, iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to private IPs", "-d", oneAddressCIDR(c).String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to private IPs", "-d", oneAddressCIDR(c).String(), "-j", "ACCEPT"))
} }
} }
} }
} else if iptablesForwardRule { } else if iptablesForwardRule {
rules = append(rules, iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from the node's pod subnet", "-s", t.subnet.String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from the node's pod subnet", "-s", t.subnet.String(), "-j", "ACCEPT"))
rules = append(rules, iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to the node's pod subnet", "-d", t.subnet.String(), "-j", "ACCEPT")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to the node's pod subnet", "-d", t.subnet.String(), "-j", "ACCEPT"))
} }
} }
for _, s := range t.segments { for _, s := range t.segments {
rules = append(rules, iptables.NewRule(iptables.GetProtocol(s.wireGuardIP), "nat", "KILO-NAT", "-d", oneAddressCIDR(s.wireGuardIP).String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for WireGuared IPs", "-j", "RETURN")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(s.wireGuardIP), "nat", "KILO-NAT", "-d", oneAddressCIDR(s.wireGuardIP).String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for WireGuared IPs", "-j", "RETURN"))
for _, aip := range s.allowedIPs { for _, aip := range s.allowedIPs {
rules = append(rules, iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "KILO-NAT", "-d", aip.String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for known IPs", "-j", "RETURN")) rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "KILO-NAT", "-d", aip.String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for known IPs", "-j", "RETURN"))
} }
// Make sure packets to allowed location IPs go through the KILO-NAT chain, so they can be MASQUERADEd, // Make sure packets to allowed location IPs go through the KILO-NAT chain, so they can be MASQUERADEd,
// Otherwise packets to these destinations will reach the destination, but never find their way back. // Otherwise packets to these destinations will reach the destination, but never find their way back.
// We only want to NAT in locations of the corresponding allowed location IPs. // We only want to NAT in locations of the corresponding allowed location IPs.
if t.location == s.location { if t.location == s.location {
for _, alip := range s.allowedLocationIPs { for _, alip := range s.allowedLocationIPs {
rules = append(rules, rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(alip.IP), "nat", "POSTROUTING", "-d", alip.String(), "-m", "comment", "--comment", "Kilo: jump to NAT chain", "-j", "KILO-NAT"))
iptables.NewRule(iptables.GetProtocol(alip.IP), "nat", "POSTROUTING", "-d", alip.String(), "-m", "comment", "--comment", "Kilo: jump to NAT chain", "-j", "KILO-NAT"),
)
} }
} }
} }
for _, p := range t.peers { for _, p := range t.peers {
for _, aip := range p.AllowedIPs { for _, aip := range p.AllowedIPs {
rules = append(rules, rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "POSTROUTING", "-s", aip.String(), "-m", "comment", "--comment", "Kilo: jump to NAT chain", "-j", "KILO-NAT"))
iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "POSTROUTING", "-s", aip.String(), "-m", "comment", "--comment", "Kilo: jump to NAT chain", "-j", "KILO-NAT"), rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "KILO-NAT", "-d", aip.String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for peers", "-j", "RETURN"))
iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "KILO-NAT", "-d", aip.String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for peers", "-j", "RETURN"),
)
} }
} }
rules = append(rules, iptables.NewIPv4Rule("nat", "KILO-NAT", "-m", "comment", "--comment", "Kilo: NAT remaining packets", "-j", "MASQUERADE")) rules.AddToAppend(iptables.NewIPv4Rule("nat", "KILO-NAT", "-m", "comment", "--comment", "Kilo: NAT remaining packets", "-j", "MASQUERADE"))
rules = append(rules, iptables.NewIPv6Rule("nat", "KILO-NAT", "-m", "comment", "--comment", "Kilo: NAT remaining packets", "-j", "MASQUERADE")) rules.AddToAppend(iptables.NewIPv6Rule("nat", "KILO-NAT", "-m", "comment", "--comment", "Kilo: NAT remaining packets", "-j", "MASQUERADE"))
return rules return rules
} }

View File

@ -109,6 +109,7 @@ func Timeout(timeout int) option {
// For backwards compatibility, by default always uses IPv4 and timeout 0. // For backwards compatibility, by default always uses IPv4 and timeout 0.
// i.e. you can create an IPv6 IPTables using a timeout of 5 seconds passing // i.e. you can create an IPv6 IPTables using a timeout of 5 seconds passing
// the IPFamily and Timeout options as follow: // the IPFamily and Timeout options as follow:
//
// ip6t := New(IPFamily(ProtocolIPv6), Timeout(5)) // ip6t := New(IPFamily(ProtocolIPv6), Timeout(5))
func New(opts ...option) (*IPTables, error) { func New(opts ...option) (*IPTables, error) {
@ -185,6 +186,20 @@ func (ipt *IPTables) Insert(table, chain string, pos int, rulespec ...string) er
return ipt.run(cmd...) return ipt.run(cmd...)
} }
// InsertUnique acts like Insert except that it won't insert a duplicate (no matter the position in the chain)
func (ipt *IPTables) InsertUnique(table, chain string, pos int, rulespec ...string) error {
exists, err := ipt.Exists(table, chain, rulespec...)
if err != nil {
return err
}
if !exists {
return ipt.Insert(table, chain, pos, rulespec...)
}
return nil
}
// Append appends rulespec to specified table/chain // Append appends rulespec to specified table/chain
func (ipt *IPTables) Append(table, chain string, rulespec ...string) error { func (ipt *IPTables) Append(table, chain string, rulespec ...string) error {
cmd := append([]string{"-t", table, "-A", chain}, rulespec...) cmd := append([]string{"-t", table, "-A", chain}, rulespec...)
@ -219,6 +234,16 @@ func (ipt *IPTables) DeleteIfExists(table, chain string, rulespec ...string) err
return err return err
} }
// List rules in specified table/chain
func (ipt *IPTables) ListById(table, chain string, id int) (string, error) {
args := []string{"-t", table, "-S", chain, strconv.Itoa(id)}
rule, err := ipt.executeList(args)
if err != nil {
return "", err
}
return rule[0], nil
}
// List rules in specified table/chain // List rules in specified table/chain
func (ipt *IPTables) List(table, chain string) ([]string, error) { func (ipt *IPTables) List(table, chain string) ([]string, error) {
args := []string{"-t", table, "-S", chain} args := []string{"-t", table, "-S", chain}
@ -510,7 +535,9 @@ func (ipt *IPTables) runWithOutput(args []string, stdout io.Writer) error {
syscall.Close(fmu.fd) syscall.Close(fmu.fd)
return err return err
} }
defer ul.Unlock() defer func() {
_ = ul.Unlock()
}()
} }
var stderr bytes.Buffer var stderr bytes.Buffer
@ -619,7 +646,7 @@ func iptablesHasWaitCommand(v1 int, v2 int, v3 int) bool {
return false return false
} }
//Checks if an iptablse version is after 1.6.0, when --wait support second // Checks if an iptablse version is after 1.6.0, when --wait support second
func iptablesWaitSupportSecond(v1 int, v2 int, v3 int) bool { func iptablesWaitSupportSecond(v1 int, v2 int, v3 int) bool {
if v1 > 1 { if v1 > 1 {
return true return true

2
vendor/modules.txt vendored
View File

@ -39,7 +39,7 @@ github.com/containernetworking/plugins/pkg/ns
github.com/containernetworking/plugins/pkg/utils/sysctl github.com/containernetworking/plugins/pkg/utils/sysctl
github.com/containernetworking/plugins/plugins/ipam/host-local/backend github.com/containernetworking/plugins/plugins/ipam/host-local/backend
github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator
# github.com/coreos/go-iptables v0.6.0 # github.com/coreos/go-iptables v0.6.1-0.20220901214115-d2b8608923d1
## explicit; go 1.16 ## explicit; go 1.16
github.com/coreos/go-iptables/iptables github.com/coreos/go-iptables/iptables
# github.com/davecgh/go-spew v1.1.1 # github.com/davecgh/go-spew v1.1.1