diff --git a/iptables/iptables.go b/iptables/iptables.go index c4f5686..a92e712 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -185,6 +185,20 @@ func (ipt *IPTables) Insert(table, chain string, pos int, rulespec ...string) er 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 func (ipt *IPTables) Append(table, chain string, rulespec ...string) error { cmd := append([]string{"-t", table, "-A", chain}, rulespec...) diff --git a/iptables/iptables_test.go b/iptables/iptables_test.go index c5a0465..2ad0528 100644 --- a/iptables/iptables_test.go +++ b/iptables/iptables_test.go @@ -293,6 +293,11 @@ func runRulesTests(t *testing.T, ipt *IPTables) { t.Fatalf("Insert failed: %v", err) } + err = ipt.InsertUnique("filter", chain, 2, "-s", subnet2, "-d", address2, "-j", "ACCEPT") + if err != nil { + t.Fatalf("Insert failed: %v", err) + } + err = ipt.Insert("filter", chain, 1, "-s", subnet1, "-d", address2, "-j", "ACCEPT") if err != nil { t.Fatalf("Insert failed: %v", err)