github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/pkg/iptables/iptables_test.go (about) 1 package iptables 2 3 import ( 4 "net" 5 "os/exec" 6 "strconv" 7 "strings" 8 "sync" 9 "testing" 10 ) 11 12 const chainName = "DOCKERTEST" 13 14 var natChain *Chain 15 var filterChain *Chain 16 17 func TestNewChain(t *testing.T) { 18 var err error 19 20 natChain, err = NewChain(chainName, "lo", Nat, false) 21 if err != nil { 22 t.Fatal(err) 23 } 24 25 filterChain, err = NewChain(chainName, "lo", Filter, false) 26 if err != nil { 27 t.Fatal(err) 28 } 29 } 30 31 func TestForward(t *testing.T) { 32 ip := net.ParseIP("192.168.1.1") 33 port := 1234 34 dstAddr := "172.17.0.1" 35 dstPort := 4321 36 proto := "tcp" 37 38 err := natChain.Forward(Insert, ip, port, proto, dstAddr, dstPort) 39 if err != nil { 40 t.Fatal(err) 41 } 42 43 dnatRule := []string{ 44 "-d", ip.String(), 45 "-p", proto, 46 "--dport", strconv.Itoa(port), 47 "-j", "DNAT", 48 "--to-destination", dstAddr + ":" + strconv.Itoa(dstPort), 49 } 50 51 if !Exists(natChain.Table, natChain.Name, dnatRule...) { 52 t.Fatalf("DNAT rule does not exist") 53 } 54 55 filterRule := []string{ 56 "!", "-i", filterChain.Bridge, 57 "-o", filterChain.Bridge, 58 "-d", dstAddr, 59 "-p", proto, 60 "--dport", strconv.Itoa(dstPort), 61 "-j", "ACCEPT", 62 } 63 64 if !Exists(filterChain.Table, filterChain.Name, filterRule...) { 65 t.Fatalf("filter rule does not exist") 66 } 67 68 masqRule := []string{ 69 "-d", dstAddr, 70 "-s", dstAddr, 71 "-p", proto, 72 "--dport", strconv.Itoa(dstPort), 73 "-j", "MASQUERADE", 74 } 75 76 if !Exists(natChain.Table, "POSTROUTING", masqRule...) { 77 t.Fatalf("MASQUERADE rule does not exist") 78 } 79 } 80 81 func TestLink(t *testing.T) { 82 var err error 83 84 ip1 := net.ParseIP("192.168.1.1") 85 ip2 := net.ParseIP("192.168.1.2") 86 port := 1234 87 proto := "tcp" 88 89 err = filterChain.Link(Append, ip1, ip2, port, proto) 90 if err != nil { 91 t.Fatal(err) 92 } 93 94 rule1 := []string{ 95 "-i", filterChain.Bridge, 96 "-o", filterChain.Bridge, 97 "-p", proto, 98 "-s", ip1.String(), 99 "-d", ip2.String(), 100 "--dport", strconv.Itoa(port), 101 "-j", "ACCEPT"} 102 103 if !Exists(filterChain.Table, filterChain.Name, rule1...) { 104 t.Fatalf("rule1 does not exist") 105 } 106 107 rule2 := []string{ 108 "-i", filterChain.Bridge, 109 "-o", filterChain.Bridge, 110 "-p", proto, 111 "-s", ip2.String(), 112 "-d", ip1.String(), 113 "--sport", strconv.Itoa(port), 114 "-j", "ACCEPT"} 115 116 if !Exists(filterChain.Table, filterChain.Name, rule2...) { 117 t.Fatalf("rule2 does not exist") 118 } 119 } 120 121 func TestPrerouting(t *testing.T) { 122 args := []string{ 123 "-i", "lo", 124 "-d", "192.168.1.1"} 125 126 err := natChain.Prerouting(Insert, args...) 127 if err != nil { 128 t.Fatal(err) 129 } 130 131 rule := []string{ 132 "-j", natChain.Name} 133 134 rule = append(rule, args...) 135 136 if !Exists(natChain.Table, "PREROUTING", rule...) { 137 t.Fatalf("rule does not exist") 138 } 139 140 delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, rule...) 141 if _, err = Raw(delRule...); err != nil { 142 t.Fatal(err) 143 } 144 } 145 146 func TestOutput(t *testing.T) { 147 args := []string{ 148 "-o", "lo", 149 "-d", "192.168.1.1"} 150 151 err := natChain.Output(Insert, args...) 152 if err != nil { 153 t.Fatal(err) 154 } 155 156 rule := []string{ 157 "-j", natChain.Name} 158 159 rule = append(rule, args...) 160 161 if !Exists(natChain.Table, "OUTPUT", rule...) { 162 t.Fatalf("rule does not exist") 163 } 164 165 delRule := append([]string{"-D", "OUTPUT", "-t", 166 string(natChain.Table)}, rule...) 167 if _, err = Raw(delRule...); err != nil { 168 t.Fatal(err) 169 } 170 } 171 172 func TestConcurrencyWithWait(t *testing.T) { 173 RunConcurrencyTest(t, true) 174 } 175 176 func TestConcurrencyNoWait(t *testing.T) { 177 RunConcurrencyTest(t, false) 178 } 179 180 // Runs 10 concurrent rule additions. This will fail if iptables 181 // is actually invoked simultaneously without --wait. 182 // Note that if iptables does not support the xtable lock on this 183 // system, then allowXlock has no effect -- it will always be off. 184 func RunConcurrencyTest(t *testing.T, allowXlock bool) { 185 var wg sync.WaitGroup 186 187 if !allowXlock && supportsXlock { 188 supportsXlock = false 189 defer func() { supportsXlock = true }() 190 } 191 192 ip := net.ParseIP("192.168.1.1") 193 port := 1234 194 dstAddr := "172.17.0.1" 195 dstPort := 4321 196 proto := "tcp" 197 198 for i := 0; i < 10; i++ { 199 wg.Add(1) 200 go func() { 201 defer wg.Done() 202 err := natChain.Forward(Append, ip, port, proto, dstAddr, dstPort) 203 if err != nil { 204 t.Fatal(err) 205 } 206 }() 207 } 208 wg.Wait() 209 } 210 211 func TestCleanup(t *testing.T) { 212 var err error 213 var rules []byte 214 215 // Cleanup filter/FORWARD first otherwise output of iptables-save is dirty 216 link := []string{"-t", string(filterChain.Table), 217 string(Delete), "FORWARD", 218 "-o", filterChain.Bridge, 219 "-j", filterChain.Name} 220 if _, err = Raw(link...); err != nil { 221 t.Fatal(err) 222 } 223 filterChain.Remove() 224 225 err = RemoveExistingChain(chainName, Nat) 226 if err != nil { 227 t.Fatal(err) 228 } 229 230 rules, err = exec.Command("iptables-save").Output() 231 if err != nil { 232 t.Fatal(err) 233 } 234 if strings.Contains(string(rules), chainName) { 235 t.Fatalf("Removing chain failed. %s found in iptables-save", chainName) 236 } 237 }