|
@@ -0,0 +1,204 @@
|
|
|
+package iptables
|
|
|
+
|
|
|
+import (
|
|
|
+ "net"
|
|
|
+ "os/exec"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "testing"
|
|
|
+)
|
|
|
+
|
|
|
+const chainName = "DOCKERTEST"
|
|
|
+
|
|
|
+var natChain *Chain
|
|
|
+var filterChain *Chain
|
|
|
+
|
|
|
+func TestNewChain(t *testing.T) {
|
|
|
+ var err error
|
|
|
+
|
|
|
+ natChain, err = NewChain(chainName, "lo", Nat)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ filterChain, err = NewChain(chainName, "lo", Filter)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestForward(t *testing.T) {
|
|
|
+ ip := net.ParseIP("192.168.1.1")
|
|
|
+ port := 1234
|
|
|
+ dstAddr := "172.17.0.1"
|
|
|
+ dstPort := 4321
|
|
|
+ proto := "tcp"
|
|
|
+
|
|
|
+ err := natChain.Forward(Insert, ip, port, proto, dstAddr, dstPort)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ dnatRule := []string{natChain.Name,
|
|
|
+ "-t", string(natChain.Table),
|
|
|
+ "!", "-i", filterChain.Bridge,
|
|
|
+ "-d", ip.String(),
|
|
|
+ "-p", proto,
|
|
|
+ "--dport", strconv.Itoa(port),
|
|
|
+ "-j", "DNAT",
|
|
|
+ "--to-destination", dstAddr + ":" + strconv.Itoa(dstPort),
|
|
|
+ }
|
|
|
+
|
|
|
+ if !Exists(dnatRule...) {
|
|
|
+ t.Fatalf("DNAT rule does not exist")
|
|
|
+ }
|
|
|
+
|
|
|
+ filterRule := []string{filterChain.Name,
|
|
|
+ "-t", string(filterChain.Table),
|
|
|
+ "!", "-i", filterChain.Bridge,
|
|
|
+ "-o", filterChain.Bridge,
|
|
|
+ "-d", dstAddr,
|
|
|
+ "-p", proto,
|
|
|
+ "--dport", strconv.Itoa(dstPort),
|
|
|
+ "-j", "ACCEPT",
|
|
|
+ }
|
|
|
+
|
|
|
+ if !Exists(filterRule...) {
|
|
|
+ t.Fatalf("filter rule does not exist")
|
|
|
+ }
|
|
|
+
|
|
|
+ masqRule := []string{"POSTROUTING",
|
|
|
+ "-t", string(natChain.Table),
|
|
|
+ "-d", dstAddr,
|
|
|
+ "-s", dstAddr,
|
|
|
+ "-p", proto,
|
|
|
+ "--dport", strconv.Itoa(dstPort),
|
|
|
+ "-j", "MASQUERADE",
|
|
|
+ }
|
|
|
+
|
|
|
+ if !Exists(masqRule...) {
|
|
|
+ t.Fatalf("MASQUERADE rule does not exist")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestLink(t *testing.T) {
|
|
|
+ var err error
|
|
|
+
|
|
|
+ ip1 := net.ParseIP("192.168.1.1")
|
|
|
+ ip2 := net.ParseIP("192.168.1.2")
|
|
|
+ port := 1234
|
|
|
+ proto := "tcp"
|
|
|
+
|
|
|
+ err = filterChain.Link(Append, ip1, ip2, port, proto)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ rule1 := []string{filterChain.Name,
|
|
|
+ "-t", string(filterChain.Table),
|
|
|
+ "-i", filterChain.Bridge,
|
|
|
+ "-o", filterChain.Bridge,
|
|
|
+ "-p", proto,
|
|
|
+ "-s", ip1.String(),
|
|
|
+ "-d", ip2.String(),
|
|
|
+ "--dport", strconv.Itoa(port),
|
|
|
+ "-j", "ACCEPT"}
|
|
|
+
|
|
|
+ if !Exists(rule1...) {
|
|
|
+ t.Fatalf("rule1 does not exist")
|
|
|
+ }
|
|
|
+
|
|
|
+ rule2 := []string{filterChain.Name,
|
|
|
+ "-t", string(filterChain.Table),
|
|
|
+ "-i", filterChain.Bridge,
|
|
|
+ "-o", filterChain.Bridge,
|
|
|
+ "-p", proto,
|
|
|
+ "-s", ip2.String(),
|
|
|
+ "-d", ip1.String(),
|
|
|
+ "--sport", strconv.Itoa(port),
|
|
|
+ "-j", "ACCEPT"}
|
|
|
+
|
|
|
+ if !Exists(rule2...) {
|
|
|
+ t.Fatalf("rule2 does not exist")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestPrerouting(t *testing.T) {
|
|
|
+ args := []string{
|
|
|
+ "-i", "lo",
|
|
|
+ "-d", "192.168.1.1"}
|
|
|
+
|
|
|
+ err := natChain.Prerouting(Insert, args...)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ rule := []string{"PREROUTING",
|
|
|
+ "-t", string(Nat),
|
|
|
+ "-j", natChain.Name}
|
|
|
+
|
|
|
+ rule = append(rule, args...)
|
|
|
+
|
|
|
+ if !Exists(rule...) {
|
|
|
+ t.Fatalf("rule does not exist")
|
|
|
+ }
|
|
|
+
|
|
|
+ delRule := append([]string{"-D"}, rule...)
|
|
|
+ if _, err = Raw(delRule...); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestOutput(t *testing.T) {
|
|
|
+ args := []string{
|
|
|
+ "-o", "lo",
|
|
|
+ "-d", "192.168.1.1"}
|
|
|
+
|
|
|
+ err := natChain.Output(Insert, args...)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ rule := []string{"OUTPUT",
|
|
|
+ "-t", string(natChain.Table),
|
|
|
+ "-j", natChain.Name}
|
|
|
+
|
|
|
+ rule = append(rule, args...)
|
|
|
+
|
|
|
+ if !Exists(rule...) {
|
|
|
+ t.Fatalf("rule does not exist")
|
|
|
+ }
|
|
|
+
|
|
|
+ delRule := append([]string{"-D"}, rule...)
|
|
|
+ if _, err = Raw(delRule...); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestCleanup(t *testing.T) {
|
|
|
+ var err error
|
|
|
+ var rules []byte
|
|
|
+
|
|
|
+ // Cleanup filter/FORWARD first otherwise output of iptables-save is dirty
|
|
|
+ link := []string{"-t", string(filterChain.Table),
|
|
|
+ string(Delete), "FORWARD",
|
|
|
+ "-o", filterChain.Bridge,
|
|
|
+ "-j", filterChain.Name}
|
|
|
+ if _, err = Raw(link...); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ filterChain.Remove()
|
|
|
+
|
|
|
+ err = RemoveExistingChain(chainName, Nat)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ rules, err = exec.Command("iptables-save").Output()
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if strings.Contains(string(rules), chainName) {
|
|
|
+ t.Fatalf("Removing chain failed. %s found in iptables-save", chainName)
|
|
|
+ }
|
|
|
+}
|