k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/util/iptables/testing/parse_test.go (about) 1 //go:build linux 2 // +build linux 3 4 /* 5 Copyright 2022 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package testing 21 22 import ( 23 "fmt" 24 "reflect" 25 "strings" 26 "testing" 27 28 "github.com/lithammer/dedent" 29 30 "k8s.io/kubernetes/pkg/util/iptables" 31 utilpointer "k8s.io/utils/pointer" 32 ) 33 34 func TestParseRule(t *testing.T) { 35 testCases := []struct { 36 name string 37 rule string 38 parsed *Rule 39 nonStrict bool 40 err string 41 }{ 42 { 43 name: "basic rule", 44 rule: `-A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT`, 45 parsed: &Rule{ 46 Raw: `-A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT`, 47 Chain: iptables.Chain("KUBE-NODEPORTS"), 48 Comment: &IPTablesValue{Value: "ns2/svc2:p80 health check node port"}, 49 Protocol: &IPTablesValue{Value: "tcp"}, 50 DestinationPort: &IPTablesValue{Value: "30000"}, 51 Jump: &IPTablesValue{Value: "ACCEPT"}, 52 }, 53 }, 54 { 55 name: "addRuleToChainRegex requires an actual rule, not just a chain name", 56 rule: `-A KUBE-NODEPORTS`, 57 err: `(no match rules)`, 58 }, 59 { 60 name: "ParseRule only parses adds", 61 rule: `-D KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT`, 62 err: `(does not start with "-A CHAIN")`, 63 }, 64 { 65 name: "unquoted comment", 66 rule: `-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ`, 67 parsed: &Rule{ 68 Raw: `-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ`, 69 Chain: iptables.Chain("KUBE-SVC-XPGD46QRK7WJZT7O"), 70 Comment: &IPTablesValue{Value: "ns1/svc1:p80"}, 71 Jump: &IPTablesValue{Value: "KUBE-SEP-SXIVWICOYRO3J4NJ"}, 72 }, 73 }, 74 { 75 name: "local source", 76 rule: `-A KUBE-XLB-GNZBNJ2PO5MGZ6GT -m comment --comment "masquerade LOCAL traffic for ns2/svc2:p80 LB IP" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ`, 77 parsed: &Rule{ 78 Raw: `-A KUBE-XLB-GNZBNJ2PO5MGZ6GT -m comment --comment "masquerade LOCAL traffic for ns2/svc2:p80 LB IP" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ`, 79 Chain: iptables.Chain("KUBE-XLB-GNZBNJ2PO5MGZ6GT"), 80 Comment: &IPTablesValue{Value: "masquerade LOCAL traffic for ns2/svc2:p80 LB IP"}, 81 SourceType: &IPTablesValue{Value: "LOCAL"}, 82 Jump: &IPTablesValue{Value: "KUBE-MARK-MASQ"}, 83 }, 84 }, 85 { 86 name: "not local destination", 87 rule: `-A RULE-TYPE-NOT-CURRENTLY-USED-BY-KUBE-PROXY -m addrtype ! --dst-type LOCAL -j KUBE-MARK-MASQ`, 88 parsed: &Rule{ 89 Raw: `-A RULE-TYPE-NOT-CURRENTLY-USED-BY-KUBE-PROXY -m addrtype ! --dst-type LOCAL -j KUBE-MARK-MASQ`, 90 Chain: iptables.Chain("RULE-TYPE-NOT-CURRENTLY-USED-BY-KUBE-PROXY"), 91 DestinationType: &IPTablesValue{Negated: true, Value: "LOCAL"}, 92 Jump: &IPTablesValue{Value: "KUBE-MARK-MASQ"}, 93 }, 94 }, 95 { 96 name: "destination IP/port", 97 rule: `-A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O`, 98 parsed: &Rule{ 99 Raw: `-A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O`, 100 Chain: iptables.Chain("KUBE-SERVICES"), 101 Comment: &IPTablesValue{Value: "ns1/svc1:p80 cluster IP"}, 102 Protocol: &IPTablesValue{Value: "tcp"}, 103 DestinationAddress: &IPTablesValue{Value: "172.30.0.41"}, 104 DestinationPort: &IPTablesValue{Value: "80"}, 105 Jump: &IPTablesValue{Value: "KUBE-SVC-XPGD46QRK7WJZT7O"}, 106 }, 107 }, 108 { 109 name: "source IP", 110 rule: `-A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ`, 111 parsed: &Rule{ 112 Raw: `-A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ`, 113 Chain: iptables.Chain("KUBE-SEP-SXIVWICOYRO3J4NJ"), 114 Comment: &IPTablesValue{Value: "ns1/svc1:p80"}, 115 SourceAddress: &IPTablesValue{Value: "10.180.0.1"}, 116 Jump: &IPTablesValue{Value: "KUBE-MARK-MASQ"}, 117 }, 118 }, 119 { 120 name: "not source IP", 121 rule: `-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 ! -s 10.0.0.0/8 -j KUBE-MARK-MASQ`, 122 parsed: &Rule{ 123 Raw: `-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 ! -s 10.0.0.0/8 -j KUBE-MARK-MASQ`, 124 Chain: iptables.Chain("KUBE-SVC-XPGD46QRK7WJZT7O"), 125 Comment: &IPTablesValue{Value: "ns1/svc1:p80 cluster IP"}, 126 Protocol: &IPTablesValue{Value: "tcp"}, 127 DestinationAddress: &IPTablesValue{Value: "172.30.0.41"}, 128 DestinationPort: &IPTablesValue{Value: "80"}, 129 SourceAddress: &IPTablesValue{Negated: true, Value: "10.0.0.0/8"}, 130 Jump: &IPTablesValue{Value: "KUBE-MARK-MASQ"}, 131 }, 132 }, 133 { 134 name: "affinity", 135 rule: `-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -m recent --name KUBE-SEP-SXIVWICOYRO3J4NJ --rcheck --seconds 10800 --reap -j KUBE-SEP-SXIVWICOYRO3J4NJ`, 136 parsed: &Rule{ 137 Raw: `-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -m recent --name KUBE-SEP-SXIVWICOYRO3J4NJ --rcheck --seconds 10800 --reap -j KUBE-SEP-SXIVWICOYRO3J4NJ`, 138 Chain: iptables.Chain("KUBE-SVC-XPGD46QRK7WJZT7O"), 139 Comment: &IPTablesValue{Value: "ns1/svc1:p80"}, 140 AffinityName: &IPTablesValue{Value: "KUBE-SEP-SXIVWICOYRO3J4NJ"}, 141 AffinitySeconds: &IPTablesValue{Value: "10800"}, 142 AffinityCheck: utilpointer.Bool(true), 143 AffinityReap: utilpointer.Bool(true), 144 Jump: &IPTablesValue{Value: "KUBE-SEP-SXIVWICOYRO3J4NJ"}, 145 }, 146 }, 147 { 148 name: "jump to DNAT", 149 rule: `-A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80`, 150 parsed: &Rule{ 151 Raw: `-A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80`, 152 Chain: iptables.Chain("KUBE-SEP-SXIVWICOYRO3J4NJ"), 153 Comment: &IPTablesValue{Value: "ns1/svc1:p80"}, 154 Protocol: &IPTablesValue{Value: "tcp"}, 155 Jump: &IPTablesValue{Value: "DNAT"}, 156 DNATDestination: &IPTablesValue{Value: "10.180.0.1:80"}, 157 }, 158 }, 159 { 160 name: "jump to endpoint", 161 rule: `-A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -m statistic --mode random --probability 0.5000000000 -j KUBE-SEP-UKSFD7AGPMPPLUHC`, 162 parsed: &Rule{ 163 Raw: `-A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -m statistic --mode random --probability 0.5000000000 -j KUBE-SEP-UKSFD7AGPMPPLUHC`, 164 Chain: iptables.Chain("KUBE-SVC-4SW47YFZTEDKD3PK"), 165 Comment: &IPTablesValue{Value: "ns4/svc4:p80"}, 166 Probability: &IPTablesValue{Value: "0.5000000000"}, 167 StatisticMode: &IPTablesValue{Value: "random"}, 168 Jump: &IPTablesValue{Value: "KUBE-SEP-UKSFD7AGPMPPLUHC"}, 169 }, 170 }, 171 { 172 name: "unrecognized arguments", 173 rule: `-A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -i eth0 -j KUBE-SEP-UKSFD7AGPMPPLUHC`, 174 err: `unrecognized parameter "-i"`, 175 }, 176 { 177 name: "unrecognized arguments with strict=false", 178 rule: `-A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -i eth0 -j KUBE-SEP-UKSFD7AGPMPPLUHC`, 179 nonStrict: true, 180 parsed: &Rule{ 181 Raw: `-A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -i eth0 -j KUBE-SEP-UKSFD7AGPMPPLUHC`, 182 Chain: iptables.Chain("KUBE-SVC-4SW47YFZTEDKD3PK"), 183 Comment: &IPTablesValue{Value: "ns4/svc4:p80"}, 184 Jump: &IPTablesValue{Value: "KUBE-SEP-UKSFD7AGPMPPLUHC"}, 185 }, 186 }, 187 { 188 name: "bad use of !", 189 rule: `-A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 ! -j KUBE-SEP-UKSFD7AGPMPPLUHC`, 190 err: `cannot negate parameter "-j"`, 191 }, 192 { 193 name: "missing argument", 194 rule: `-A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -j`, 195 err: `parameter "-j" requires an argument`, 196 }, 197 { 198 name: "negated bool arg", 199 rule: `-A TEST -m recent ! --rcheck -j KUBE-SEP-SXIVWICOYRO3J4NJ`, 200 parsed: &Rule{ 201 Raw: `-A TEST -m recent ! --rcheck -j KUBE-SEP-SXIVWICOYRO3J4NJ`, 202 Chain: iptables.Chain("TEST"), 203 AffinityCheck: utilpointer.Bool(false), 204 Jump: &IPTablesValue{Value: "KUBE-SEP-SXIVWICOYRO3J4NJ"}, 205 }, 206 }, 207 } 208 209 for _, testCase := range testCases { 210 t.Run(testCase.name, func(t *testing.T) { 211 rule, err := ParseRule(testCase.rule, !testCase.nonStrict) 212 if err != nil { 213 if testCase.err == "" { 214 t.Errorf("expected %+v, got error %q", testCase.parsed, err) 215 } else if !strings.Contains(err.Error(), testCase.err) { 216 t.Errorf("wrong error, expected %q got %q", testCase.err, err) 217 } 218 } else { 219 if testCase.err != "" { 220 t.Errorf("expected error %q, got %+v", testCase.err, rule) 221 } else if !reflect.DeepEqual(rule, testCase.parsed) { 222 t.Errorf("bad match: expected\n%+v\ngot\n%+v", testCase.parsed, rule) 223 } 224 } 225 }) 226 } 227 } 228 229 // Helper for TestParseIPTablesDump. Obviously it should not be used in TestParseRule... 230 func mustParseRule(rule string) *Rule { 231 parsed, err := ParseRule(rule, false) 232 if err != nil { 233 panic(fmt.Sprintf("failed to parse test case rule %q: %v", rule, err)) 234 } 235 return parsed 236 } 237 238 func TestParseIPTablesDump(t *testing.T) { 239 for _, tc := range []struct { 240 name string 241 input string 242 output *IPTablesDump 243 error string 244 }{ 245 { 246 name: "basic test", 247 input: dedent.Dedent(` 248 *filter 249 :KUBE-SERVICES - [0:0] 250 :KUBE-EXTERNAL-SERVICES - [0:0] 251 :KUBE-FORWARD - [0:0] 252 :KUBE-NODEPORTS - [0:0] 253 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 254 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 255 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 256 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 257 COMMIT 258 *nat 259 :KUBE-SERVICES - [0:0] 260 :KUBE-NODEPORTS - [0:0] 261 :KUBE-POSTROUTING - [0:0] 262 :KUBE-MARK-MASQ - [0:0] 263 :KUBE-SVC-XPGD46QRK7WJZT7O - [0:0] 264 :KUBE-SEP-SXIVWICOYRO3J4NJ - [0:0] 265 -A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN 266 -A KUBE-POSTROUTING -j MARK --xor-mark 0x4000 267 -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE 268 -A KUBE-MARK-MASQ -j MARK --or-mark 0x4000 269 -A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O 270 -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 ! -s 10.0.0.0/24 -j KUBE-MARK-MASQ 271 -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ 272 -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ 273 -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80 274 -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS 275 COMMIT 276 `), 277 output: &IPTablesDump{ 278 Tables: []Table{{ 279 Name: iptables.TableFilter, 280 Chains: []Chain{{ 281 Name: iptables.Chain("KUBE-SERVICES"), 282 }, { 283 Name: iptables.Chain("KUBE-EXTERNAL-SERVICES"), 284 }, { 285 Name: iptables.Chain("KUBE-FORWARD"), 286 Rules: []*Rule{ 287 mustParseRule(`-A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP`), 288 mustParseRule(`-A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT`), 289 mustParseRule(`-A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT`), 290 }, 291 }, { 292 Name: iptables.Chain("KUBE-NODEPORTS"), 293 Rules: []*Rule{ 294 mustParseRule(`-A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT`), 295 }, 296 }}, 297 }, { 298 Name: iptables.TableNAT, 299 Chains: []Chain{{ 300 Name: iptables.Chain("KUBE-SERVICES"), 301 Rules: []*Rule{ 302 mustParseRule(`-A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O`), 303 mustParseRule(`-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS`), 304 }, 305 }, { 306 Name: iptables.Chain("KUBE-NODEPORTS"), 307 }, { 308 Name: iptables.Chain("KUBE-POSTROUTING"), 309 Rules: []*Rule{ 310 mustParseRule(`-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN`), 311 mustParseRule(`-A KUBE-POSTROUTING -j MARK --xor-mark 0x4000`), 312 mustParseRule(`-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE`), 313 }, 314 }, { 315 Name: iptables.Chain("KUBE-MARK-MASQ"), 316 Rules: []*Rule{ 317 mustParseRule(`-A KUBE-MARK-MASQ -j MARK --or-mark 0x4000`), 318 }, 319 }, { 320 Name: iptables.Chain("KUBE-SVC-XPGD46QRK7WJZT7O"), 321 Rules: []*Rule{ 322 mustParseRule(`-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 ! -s 10.0.0.0/24 -j KUBE-MARK-MASQ`), 323 mustParseRule(`-A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ`), 324 }, 325 }, { 326 Name: iptables.Chain("KUBE-SEP-SXIVWICOYRO3J4NJ"), 327 Rules: []*Rule{ 328 mustParseRule(`-A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ`), 329 mustParseRule(`-A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80`), 330 }, 331 }}, 332 }}, 333 }, 334 }, 335 { 336 name: "deletion", 337 input: dedent.Dedent(` 338 *nat 339 :KUBE-SERVICES - [0:0] 340 :KUBE-SVC-XPGD46QRK7WJZT7O - [0:0] 341 :KUBE-SEP-SXIVWICOYRO3J4NJ - [0:0] 342 -X KUBE-SVC-XPGD46QRK7WJZT7O 343 -X KUBE-SEP-SXIVWICOYRO3J4NJ 344 -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS 345 COMMIT 346 `), 347 output: &IPTablesDump{ 348 Tables: []Table{{ 349 Name: iptables.TableNAT, 350 Chains: []Chain{{ 351 Name: iptables.Chain("KUBE-SERVICES"), 352 Rules: []*Rule{ 353 mustParseRule(`-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS`), 354 }, 355 }, { 356 Name: iptables.Chain("KUBE-SVC-XPGD46QRK7WJZT7O"), 357 Deleted: true, 358 }, { 359 Name: iptables.Chain("KUBE-SEP-SXIVWICOYRO3J4NJ"), 360 Deleted: true, 361 }}, 362 }}, 363 }, 364 }, 365 { 366 name: "whitespace and comments", 367 input: dedent.Dedent(` 368 # Generated by iptables-save v1.8.7 on Mon May 9 11:22:21 2022 369 # (not really...) 370 *filter 371 :KUBE-SERVICES - [0:0] 372 :KUBE-EXTERNAL-SERVICES - [0:0] 373 374 :KUBE-FORWARD - [0:0] 375 :KUBE-NODEPORTS - [0:0] 376 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 377 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 378 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 379 # This rule does a thing 380 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 381 COMMIT 382 # Completed on Mon May 9 11:22:21 2022 383 `), 384 output: &IPTablesDump{ 385 Tables: []Table{{ 386 Name: iptables.TableFilter, 387 Chains: []Chain{{ 388 Name: iptables.Chain("KUBE-SERVICES"), 389 }, { 390 Name: iptables.Chain("KUBE-EXTERNAL-SERVICES"), 391 }, { 392 Name: iptables.Chain("KUBE-FORWARD"), 393 Rules: []*Rule{ 394 mustParseRule(`-A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP`), 395 mustParseRule(`-A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT`), 396 mustParseRule(`-A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT`), 397 }, 398 }, { 399 Name: iptables.Chain("KUBE-NODEPORTS"), 400 Rules: []*Rule{ 401 mustParseRule(`-A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT`), 402 }, 403 }}, 404 }}, 405 }, 406 }, 407 { 408 name: "no COMMIT line", 409 input: dedent.Dedent(` 410 *filter 411 :KUBE-SERVICES - [0:0] 412 :KUBE-EXTERNAL-SERVICES - [0:0] 413 :KUBE-FORWARD - [0:0] 414 :KUBE-NODEPORTS - [0:0] 415 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 416 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 417 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 418 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 419 `), 420 error: "no COMMIT line?", 421 }, 422 { 423 name: "two tables, no second COMMIT line", 424 input: dedent.Dedent(` 425 *filter 426 :KUBE-SERVICES - [0:0] 427 :KUBE-EXTERNAL-SERVICES - [0:0] 428 :KUBE-FORWARD - [0:0] 429 :KUBE-NODEPORTS - [0:0] 430 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 431 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 432 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 433 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 434 COMMIT 435 *nat 436 :KUBE-SERVICES - [0:0] 437 :KUBE-NODEPORTS - [0:0] 438 :KUBE-POSTROUTING - [0:0] 439 :KUBE-MARK-MASQ - [0:0] 440 :KUBE-SVC-XPGD46QRK7WJZT7O - [0:0] 441 :KUBE-SEP-SXIVWICOYRO3J4NJ - [0:0] 442 -A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN 443 -A KUBE-POSTROUTING -j MARK --xor-mark 0x4000 444 -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE 445 -A KUBE-MARK-MASQ -j MARK --or-mark 0x4000 446 -A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O 447 -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 ! -s 10.0.0.0/24 -j KUBE-MARK-MASQ 448 -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ 449 -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ 450 -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80 451 -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS 452 `), 453 error: "no COMMIT line?", 454 }, 455 { 456 name: "two tables, no second header line", 457 input: dedent.Dedent(` 458 *filter 459 :KUBE-SERVICES - [0:0] 460 :KUBE-EXTERNAL-SERVICES - [0:0] 461 :KUBE-FORWARD - [0:0] 462 :KUBE-NODEPORTS - [0:0] 463 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 464 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 465 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 466 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 467 COMMIT 468 :KUBE-SERVICES - [0:0] 469 :KUBE-NODEPORTS - [0:0] 470 :KUBE-POSTROUTING - [0:0] 471 :KUBE-MARK-MASQ - [0:0] 472 :KUBE-SVC-XPGD46QRK7WJZT7O - [0:0] 473 :KUBE-SEP-SXIVWICOYRO3J4NJ - [0:0] 474 -A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN 475 -A KUBE-POSTROUTING -j MARK --xor-mark 0x4000 476 -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE 477 -A KUBE-MARK-MASQ -j MARK --or-mark 0x4000 478 -A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O 479 -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 ! -s 10.0.0.0/24 -j KUBE-MARK-MASQ 480 -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ 481 -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ 482 -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80 483 -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS 484 COMMIT 485 `), 486 error: "not a table name", 487 }, 488 { 489 name: "trailing junk", 490 input: dedent.Dedent(` 491 *filter 492 :KUBE-SERVICES - [0:0] 493 :KUBE-EXTERNAL-SERVICES - [0:0] 494 :KUBE-FORWARD - [0:0] 495 :KUBE-NODEPORTS - [0:0] 496 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 497 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 498 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 499 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 500 COMMIT 501 *nat 502 :KUBE-SERVICES - [0:0] 503 :KUBE-EXTERNAL-SERVICES - [0:0] 504 :KUBE-FORWARD - [0:0] 505 :KUBE-NODEPORTS - [0:0] 506 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 507 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 508 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 509 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 510 COMMIT 511 junk 512 `), 513 error: `table 3 starts with "junk"`, 514 }, 515 { 516 name: "add to missing chain", 517 input: dedent.Dedent(` 518 *filter 519 :KUBE-SERVICES - [0:0] 520 :KUBE-EXTERNAL-SERVICES - [0:0] 521 :KUBE-NODEPORTS - [0:0] 522 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 523 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 524 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 525 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 526 COMMIT 527 `), 528 error: `no such chain "KUBE-FORWARD"`, 529 }, 530 { 531 name: "add to deleted chain", 532 input: dedent.Dedent(` 533 *filter 534 :KUBE-SERVICES - [0:0] 535 :KUBE-EXTERNAL-SERVICES - [0:0] 536 :KUBE-FORWARD - [0:0] 537 :KUBE-NODEPORTS - [0:0] 538 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 539 -X KUBE-FORWARD 540 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 541 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 542 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 543 COMMIT 544 `), 545 error: `cannot add rules to deleted chain`, 546 }, 547 { 548 name: "deleted non-empty chain", 549 input: dedent.Dedent(` 550 *filter 551 :KUBE-SERVICES - [0:0] 552 :KUBE-EXTERNAL-SERVICES - [0:0] 553 :KUBE-FORWARD - [0:0] 554 :KUBE-NODEPORTS - [0:0] 555 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 556 -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 557 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 558 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 559 -X KUBE-FORWARD 560 COMMIT 561 `), 562 error: `cannot delete chain "KUBE-FORWARD" after adding rules`, 563 }, 564 { 565 name: "junk rule", 566 input: dedent.Dedent(` 567 *filter 568 :KUBE-SERVICES - [0:0] 569 :KUBE-EXTERNAL-SERVICES - [0:0] 570 :KUBE-FORWARD - [0:0] 571 :KUBE-NODEPORTS - [0:0] 572 -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT 573 -Q KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP 574 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT 575 -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 576 COMMIT 577 `), 578 error: `"-Q KUBE-FORWARD`, 579 }, 580 } { 581 t.Run(tc.name, func(t *testing.T) { 582 dump, err := ParseIPTablesDump(tc.input) 583 if err == nil { 584 if tc.error != "" { 585 t.Errorf("unexpectedly did not get error") 586 } else if !reflect.DeepEqual(tc.output, dump) { 587 t.Errorf("bad output: expected %#v got %#v", tc.output, dump) 588 } 589 } else { 590 if tc.error == "" { 591 t.Errorf("got unexpected error: %v", err) 592 } else if !strings.Contains(err.Error(), tc.error) { 593 t.Errorf("got wrong error: %v (expected %q)", err, tc.error) 594 } 595 } 596 }) 597 } 598 }