github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/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 _ "github.com/docker/libnetwork/testutils" 12 ) 13 14 const chainName = "DOCKEREST" 15 16 var natChain *ChainInfo 17 var filterChain *ChainInfo 18 var bridgeName string 19 20 func TestNewChain(t *testing.T) { 21 var err error 22 23 bridgeName = "lo" 24 natChain, err = NewChain(chainName, Nat, false) 25 err = ProgramChain(natChain, bridgeName, false, true) 26 if err != nil { 27 t.Fatal(err) 28 } 29 30 filterChain, err = NewChain(chainName, Filter, false) 31 err = ProgramChain(filterChain, bridgeName, false, true) 32 if err != nil { 33 t.Fatal(err) 34 } 35 } 36 37 func TestForward(t *testing.T) { 38 ip := net.ParseIP("192.168.1.1") 39 port := 1234 40 dstAddr := "172.17.0.1" 41 dstPort := 4321 42 proto := "tcp" 43 44 bridgeName := "lo" 45 err := natChain.Forward(Insert, ip, port, proto, dstAddr, dstPort, bridgeName) 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 dnatRule := []string{ 51 "-d", ip.String(), 52 "-p", proto, 53 "--dport", strconv.Itoa(port), 54 "-j", "DNAT", 55 "--to-destination", dstAddr + ":" + strconv.Itoa(dstPort), 56 "!", "-i", bridgeName, 57 } 58 59 if !Exists(natChain.Table, natChain.Name, dnatRule...) { 60 t.Fatalf("DNAT rule does not exist") 61 } 62 63 filterRule := []string{ 64 "!", "-i", bridgeName, 65 "-o", bridgeName, 66 "-d", dstAddr, 67 "-p", proto, 68 "--dport", strconv.Itoa(dstPort), 69 "-j", "ACCEPT", 70 } 71 72 if !Exists(filterChain.Table, filterChain.Name, filterRule...) { 73 t.Fatalf("filter rule does not exist") 74 } 75 76 masqRule := []string{ 77 "-d", dstAddr, 78 "-s", dstAddr, 79 "-p", proto, 80 "--dport", strconv.Itoa(dstPort), 81 "-j", "MASQUERADE", 82 } 83 84 if !Exists(natChain.Table, "POSTROUTING", masqRule...) { 85 t.Fatalf("MASQUERADE rule does not exist") 86 } 87 } 88 89 func TestLink(t *testing.T) { 90 var err error 91 92 bridgeName := "lo" 93 ip1 := net.ParseIP("192.168.1.1") 94 ip2 := net.ParseIP("192.168.1.2") 95 port := 1234 96 proto := "tcp" 97 98 err = filterChain.Link(Append, ip1, ip2, port, proto, bridgeName) 99 if err != nil { 100 t.Fatal(err) 101 } 102 103 rule1 := []string{ 104 "-i", bridgeName, 105 "-o", bridgeName, 106 "-p", proto, 107 "-s", ip1.String(), 108 "-d", ip2.String(), 109 "--dport", strconv.Itoa(port), 110 "-j", "ACCEPT"} 111 112 if !Exists(filterChain.Table, filterChain.Name, rule1...) { 113 t.Fatalf("rule1 does not exist") 114 } 115 116 rule2 := []string{ 117 "-i", bridgeName, 118 "-o", bridgeName, 119 "-p", proto, 120 "-s", ip2.String(), 121 "-d", ip1.String(), 122 "--sport", strconv.Itoa(port), 123 "-j", "ACCEPT"} 124 125 if !Exists(filterChain.Table, filterChain.Name, rule2...) { 126 t.Fatalf("rule2 does not exist") 127 } 128 } 129 130 func TestPrerouting(t *testing.T) { 131 args := []string{ 132 "-i", "lo", 133 "-d", "192.168.1.1"} 134 135 err := natChain.Prerouting(Insert, args...) 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 if !Exists(natChain.Table, "PREROUTING", args...) { 141 t.Fatalf("rule does not exist") 142 } 143 144 delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, args...) 145 if _, err = Raw(delRule...); err != nil { 146 t.Fatal(err) 147 } 148 } 149 150 func TestOutput(t *testing.T) { 151 args := []string{ 152 "-o", "lo", 153 "-d", "192.168.1.1"} 154 155 err := natChain.Output(Insert, args...) 156 if err != nil { 157 t.Fatal(err) 158 } 159 160 if !Exists(natChain.Table, "OUTPUT", args...) { 161 t.Fatalf("rule does not exist") 162 } 163 164 delRule := append([]string{"-D", "OUTPUT", "-t", 165 string(natChain.Table)}, args...) 166 if _, err = Raw(delRule...); err != nil { 167 t.Fatal(err) 168 } 169 } 170 171 func TestConcurrencyWithWait(t *testing.T) { 172 RunConcurrencyTest(t, true) 173 } 174 175 func TestConcurrencyNoWait(t *testing.T) { 176 RunConcurrencyTest(t, false) 177 } 178 179 // Runs 10 concurrent rule additions. This will fail if iptables 180 // is actually invoked simultaneously without --wait. 181 // Note that if iptables does not support the xtable lock on this 182 // system, then allowXlock has no effect -- it will always be off. 183 func RunConcurrencyTest(t *testing.T, allowXlock bool) { 184 var wg sync.WaitGroup 185 186 if !allowXlock && supportsXlock { 187 supportsXlock = false 188 defer func() { supportsXlock = true }() 189 } 190 191 ip := net.ParseIP("192.168.1.1") 192 port := 1234 193 dstAddr := "172.17.0.1" 194 dstPort := 4321 195 proto := "tcp" 196 197 for i := 0; i < 10; i++ { 198 wg.Add(1) 199 go func() { 200 defer wg.Done() 201 err := natChain.Forward(Append, ip, port, proto, dstAddr, dstPort, "lo") 202 if err != nil { 203 t.Fatal(err) 204 } 205 }() 206 } 207 wg.Wait() 208 } 209 210 func TestCleanup(t *testing.T) { 211 var err error 212 var rules []byte 213 214 // Cleanup filter/FORWARD first otherwise output of iptables-save is dirty 215 link := []string{"-t", string(filterChain.Table), 216 string(Delete), "FORWARD", 217 "-o", bridgeName, 218 "-j", filterChain.Name} 219 if _, err = Raw(link...); err != nil { 220 t.Fatal(err) 221 } 222 filterChain.Remove() 223 224 err = RemoveExistingChain(chainName, Nat) 225 if err != nil { 226 t.Fatal(err) 227 } 228 229 rules, err = exec.Command("iptables-save").Output() 230 if err != nil { 231 t.Fatal(err) 232 } 233 if strings.Contains(string(rules), chainName) { 234 t.Fatalf("Removing chain failed. %s found in iptables-save", chainName) 235 } 236 } 237 238 func TestExistsRaw(t *testing.T) { 239 testChain1 := "ABCD" 240 testChain2 := "EFGH" 241 242 _, err := NewChain(testChain1, Filter, false) 243 if err != nil { 244 t.Fatal(err) 245 } 246 defer func() { 247 RemoveExistingChain(testChain1, Filter) 248 }() 249 250 _, err = NewChain(testChain2, Filter, false) 251 if err != nil { 252 t.Fatal(err) 253 } 254 defer func() { 255 RemoveExistingChain(testChain2, Filter) 256 }() 257 258 // Test detection over full and truncated rule string 259 input := []struct{ rule []string }{ 260 {[]string{"-s", "172.8.9.9/32", "-j", "ACCEPT"}}, 261 {[]string{"-d", "172.8.9.0/24", "-j", "DROP"}}, 262 {[]string{"-s", "172.0.3.0/24", "-d", "172.17.0.0/24", "-p", "tcp", "-m", "tcp", "--dport", "80", "-j", testChain2}}, 263 {[]string{"-j", "RETURN"}}, 264 } 265 266 for i, r := range input { 267 ruleAdd := append([]string{"-t", string(Filter), "-A", testChain1}, r.rule...) 268 err = RawCombinedOutput(ruleAdd...) 269 if err != nil { 270 t.Fatalf("i=%d, err: %v", i, err) 271 } 272 if !existsRaw(Filter, testChain1, r.rule...) { 273 t.Fatalf("Failed to detect rule. i=%d", i) 274 } 275 // Truncate the rule 276 trg := r.rule[len(r.rule)-1] 277 trg = trg[:len(trg)-2] 278 r.rule[len(r.rule)-1] = trg 279 if existsRaw(Filter, testChain1, r.rule...) { 280 t.Fatalf("Invalid detection. i=%d", i) 281 } 282 } 283 } 284 285 func TestGetVersion(t *testing.T) { 286 mj, mn, mc := parseVersionNumbers("iptables v1.4.19.1-alpha") 287 if mj != 1 || mn != 4 || mc != 19 { 288 t.Fatalf("Failed to parse version numbers") 289 } 290 } 291 292 func TestSupportsCOption(t *testing.T) { 293 input := []struct { 294 mj int 295 mn int 296 mc int 297 ok bool 298 }{ 299 {1, 4, 11, true}, 300 {1, 4, 12, true}, 301 {1, 5, 0, true}, 302 {0, 4, 11, false}, 303 {0, 5, 12, false}, 304 {1, 3, 12, false}, 305 {1, 4, 10, false}, 306 } 307 for ind, inp := range input { 308 if inp.ok != supportsCOption(inp.mj, inp.mn, inp.mc) { 309 t.Fatalf("Incorrect check: %d", ind) 310 } 311 } 312 }