1
2
3
4
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
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 }
599
View as plain text