pkg/iptableswrapper/fake_iptables.go (143 lines of code) (raw):
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
package iptableswrapper
import (
"bytes"
"fmt"
"time"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/iptables"
iptest "k8s.io/kubernetes/pkg/util/iptables/testing"
)
// FakeIPTables is no-op implementation of iptables Interface.
// We create a wrapper for iptest.FakeIPTables because the original package does not contain enough builtinTargets we need.
type FakeIPTables struct {
fake *iptest.FakeIPTables
builtinTargets sets.Set[string]
}
// NewFake returns a no-op iptables.Interface
func NewFake() *FakeIPTables {
return &FakeIPTables{
fake: iptest.NewFake(),
builtinTargets: sets.New[string]("ACCEPT", "DROP", "RETURN", "REJECT", "DNAT", "SNAT", "MASQUERADE", "MARK", "CONNMARK"),
}
}
// NewIPv6Fake returns a no-op iptables.Interface with IsIPv6() == true
func NewIPv6Fake() *FakeIPTables {
return &FakeIPTables{
fake: iptest.NewIPv6Fake(),
builtinTargets: sets.New[string]("ACCEPT", "DROP", "RETURN", "REJECT", "DNAT", "SNAT", "MASQUERADE", "MARK", "CONNMARK"),
}
}
func (f *FakeIPTables) AddBuiltinTargets(targets ...string) {
for _, target := range targets {
f.builtinTargets = f.builtinTargets.Insert(target)
}
}
// SetHasRandomFully sets f's return value for HasRandomFully()
func (f *FakeIPTables) SetHasRandomFully(can bool) *FakeIPTables {
f.fake.SetHasRandomFully(can)
return f
}
// EnsureChain is part of iptables.Interface
func (f *FakeIPTables) EnsureChain(table iptables.Table, chain iptables.Chain) (bool, error) {
return f.fake.EnsureChain(table, chain)
}
// FlushChain is part of iptables.Interface
func (f *FakeIPTables) FlushChain(table iptables.Table, chain iptables.Chain) error {
return f.fake.FlushChain(table, chain)
}
// DeleteChain is part of iptables.Interface
func (f *FakeIPTables) DeleteChain(table iptables.Table, chain iptables.Chain) error {
return f.fake.DeleteChain(table, chain)
}
// ChainExists is part of iptables.Interface
func (f *FakeIPTables) ChainExists(table iptables.Table, chain iptables.Chain) (bool, error) {
return f.fake.ChainExists(table, chain)
}
// EnsureRule is part of iptables.Interface
func (f *FakeIPTables) EnsureRule(position iptables.RulePosition, table iptables.Table, chain iptables.Chain, args ...string) (bool, error) {
return f.fake.EnsureRule(position, table, chain, args...)
}
// DeleteRule is part of iptables.Interface
func (f *FakeIPTables) DeleteRule(table iptables.Table, chain iptables.Chain, args ...string) error {
return f.fake.DeleteRule(table, chain, args...)
}
// IsIPv6 is part of iptables.Interface
func (f *FakeIPTables) IsIPv6() bool {
return f.fake.IsIPv6()
}
// Protocol is part of iptables.Interface
func (f *FakeIPTables) Protocol() iptables.Protocol {
return f.fake.Protocol()
}
// SaveInto is part of iptables.Interface
func (f *FakeIPTables) SaveInto(table iptables.Table, buffer *bytes.Buffer) error {
return f.fake.SaveInto(table, buffer)
}
// copied from k8s.io/kubernetes/pkg/util/iptables/testing/fake.go with builtinTargets updated
func (f *FakeIPTables) restoreTable(newDump *iptest.IPTablesDump, newTable *iptest.Table, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error {
oldTable, err := f.fake.Dump.GetTable(newTable.Name)
if err != nil {
return err
}
backupChains := make([]iptest.Chain, len(oldTable.Chains))
copy(backupChains, oldTable.Chains)
// Update internal state
if flush == iptables.FlushTables {
oldTable.Chains = make([]iptest.Chain, 0, len(newTable.Chains))
}
for _, newChain := range newTable.Chains {
oldChain, _ := f.fake.Dump.GetChain(newTable.Name, newChain.Name)
switch {
case oldChain == nil && newChain.Deleted:
// no-op
case oldChain == nil && !newChain.Deleted:
oldTable.Chains = append(oldTable.Chains, newChain)
case oldChain != nil && newChain.Deleted:
_ = f.DeleteChain(newTable.Name, newChain.Name)
case oldChain != nil && !newChain.Deleted:
// replace old data with new
oldChain.Rules = newChain.Rules
if counters == iptables.RestoreCounters {
oldChain.Packets = newChain.Packets
oldChain.Bytes = newChain.Bytes
}
}
}
// Now check that all old/new jumps are valid
for _, chain := range oldTable.Chains {
for _, rule := range chain.Rules {
if rule.Jump == nil {
continue
}
if f.builtinTargets.Has(rule.Jump.Value) {
continue
}
jumpedChain, _ := f.fake.Dump.GetChain(oldTable.Name, iptables.Chain(rule.Jump.Value))
if jumpedChain == nil {
newChain, _ := newDump.GetChain(oldTable.Name, iptables.Chain(rule.Jump.Value))
if newChain != nil {
// rule is an old rule that jumped to a chain which
// was deleted by newDump.
oldTable.Chains = backupChains
return fmt.Errorf("deleted chain %q is referenced by existing rules", newChain.Name)
} else {
// rule is a new rule that jumped to a chain that was
// neither created nor pre-existing
oldTable.Chains = backupChains
return fmt.Errorf("rule %q jumps to a non-existent chain", rule.Raw)
}
}
}
}
return nil
}
// Restore is part of iptables.Interface
// copied from k8s.io/kubernetes/pkg/util/iptables/testing/fake.go
func (f *FakeIPTables) Restore(table iptables.Table, data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error {
dump, err := iptest.ParseIPTablesDump(string(data))
if err != nil {
return err
}
newTable, err := dump.GetTable(table)
if err != nil {
return err
}
return f.restoreTable(dump, newTable, flush, counters)
}
// RestoreAll is part of iptables.Interface
// copied from k8s.io/kubernetes/pkg/util/iptables/testing/fake.go
func (f *FakeIPTables) RestoreAll(data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error {
dump, err := iptest.ParseIPTablesDump(string(data))
if err != nil {
return err
}
for i := range dump.Tables {
err = f.restoreTable(dump, &dump.Tables[i], flush, counters)
if err != nil {
return err
}
}
return nil
}
// Monitor is part of iptables.Interface
func (f *FakeIPTables) Monitor(canary iptables.Chain, tables []iptables.Table, reloadFunc func(), interval time.Duration, stopCh <-chan struct{}) {
}
// HasRandomFully is part of iptables.Interface
func (f *FakeIPTables) HasRandomFully() bool {
return f.fake.HasRandomFully()
}
func (f *FakeIPTables) Present() bool {
return true
}
var _ = iptables.Interface(&FakeIPTables{})