diff options
Diffstat (limited to 'internal/pkg/network/iptables.go')
-rw-r--r-- | internal/pkg/network/iptables.go | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/internal/pkg/network/iptables.go b/internal/pkg/network/iptables.go new file mode 100644 index 0000000..6e71b3f --- /dev/null +++ b/internal/pkg/network/iptables.go @@ -0,0 +1,124 @@ +package network + +import ( + "fmt" + "strings" + + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + + "github.com/coreos/go-iptables/iptables" +) + +var log = logf.Log.WithName("iptables") + +type IPTables interface { + AppendUnique(table string, chain string, rulespec ...string) error + Delete(table string, chain string, rulespec ...string) error + Exists(table string, chain string, rulespec ...string) (bool, error) +} + +type IPTablesRule struct { + table string + chain string + rulespec []string +} + +func MasqRules(ifname string) []IPTablesRule { + return []IPTablesRule{ + // This rule makes sure ifname is SNAT + {"nat", "POSTROUTING", []string{"-o", ifname, "-j", "MASQUERADE"}}, + } +} + +func ForwardRules(ovnNetwork string) []IPTablesRule { + return []IPTablesRule{ + // These rules allow traffic to be forwarded if it is to or from the ovn network range. + {"filter", "FORWARD", []string{"-s", ovnNetwork, "-j", "ACCEPT"}}, + {"filter", "FORWARD", []string{"-d", ovnNetwork, "-j", "ACCEPT"}}, + } +} + +func ipTablesRulesExist(ipt IPTables, rules []IPTablesRule) (bool, error) { + for _, rule := range rules { + exists, err := ipt.Exists(rule.table, rule.chain, rule.rulespec...) + if err != nil { + // this shouldn't ever happen + return false, fmt.Errorf("failed to check rule existence: %v", err) + } + if !exists { + return false, nil + } + } + + return true, nil +} + +func SetupAndEnsureIPTables(rules []IPTablesRule) error { + ipt, err := iptables.New() + if err != nil { + // if we can't find iptables, give up and return + log.Error(err, "Failed to setup IPTables. iptables binary was not found") + return err + } + + // Ensure that all the iptables rules exist every 5 seconds + if err := ensureIPTables(ipt, rules); err != nil { + log.Error(err, "Failed to ensure iptables rules") + return err + } + + return nil + +} + +// DeleteIPTables delete specified iptables rules +func DeleteIPTables(rules []IPTablesRule) error { + ipt, err := iptables.New() + if err != nil { + // if we can't find iptables, give up and return + log.Error(err, "Failed to setup IPTables. iptables binary was not found") + return err + } + teardownIPTables(ipt, rules) + return nil +} + +func ensureIPTables(ipt IPTables, rules []IPTablesRule) error { + exists, err := ipTablesRulesExist(ipt, rules) + if err != nil { + return fmt.Errorf("Error checking rule existence: %v", err) + } + if exists { + // if all the rules already exist, no need to do anything + return nil + } + // Otherwise, teardown all the rules and set them up again + // We do this because the order of the rules is important + log.Info("Some iptables rules are missing; deleting and recreating rules") + teardownIPTables(ipt, rules) + if err = setupIPTables(ipt, rules); err != nil { + return fmt.Errorf("Error setting up rules: %v", err) + } + return nil +} + +func setupIPTables(ipt IPTables, rules []IPTablesRule) error { + for _, rule := range rules { + log.Info("Adding iptables rule: ", "rule", strings.Join(rule.rulespec, " ")) + err := ipt.AppendUnique(rule.table, rule.chain, rule.rulespec...) + if err != nil { + return fmt.Errorf("failed to insert IPTables rule: %v", err) + } + } + + return nil +} + +func teardownIPTables(ipt IPTables, rules []IPTablesRule) { + for _, rule := range rules { + log.Info("Deleting iptables rule: ", "rule", strings.Join(rule.rulespec, " ")) + // We ignore errors here because if there's an error it's almost certainly because the rule + // doesn't exist, which is fine (we don't need to delete rules that don't exist) + ipt.Delete(rule.table, rule.chain, rule.rulespec...) + } +} |