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