1
2
3
4 package netlink
5
6 import (
7 "net"
8 "testing"
9
10 "golang.org/x/sys/unix"
11 )
12
13 func TestRuleAddDel(t *testing.T) {
14 skipUnlessRoot(t)
15 defer setUpNetlinkTest(t)()
16
17 srcNet := &net.IPNet{IP: net.IPv4(172, 16, 0, 1), Mask: net.CIDRMask(16, 32)}
18 dstNet := &net.IPNet{IP: net.IPv4(172, 16, 1, 1), Mask: net.CIDRMask(24, 32)}
19
20 rulesBegin, err := RuleList(FAMILY_V4)
21 if err != nil {
22 t.Fatal(err)
23 }
24
25 rule := NewRule()
26 rule.Family = FAMILY_V4
27 rule.Table = unix.RT_TABLE_MAIN
28 rule.Src = srcNet
29 rule.Dst = dstNet
30 rule.Priority = 5
31 rule.OifName = "lo"
32 rule.IifName = "lo"
33 rule.Invert = true
34 rule.Tos = 0x10
35 rule.Dport = NewRulePortRange(80, 80)
36 rule.Sport = NewRulePortRange(1000, 1024)
37 rule.IPProto = unix.IPPROTO_UDP
38 rule.UIDRange = NewRuleUIDRange(100, 100)
39 rule.Protocol = unix.RTPROT_KERNEL
40 if err := RuleAdd(rule); err != nil {
41 t.Fatal(err)
42 }
43
44 rules, err := RuleList(FAMILY_V4)
45 if err != nil {
46 t.Fatal(err)
47 }
48
49 if len(rules) != len(rulesBegin)+1 {
50 t.Fatal("Rule not added properly")
51 }
52
53
54 found := ruleExists(rules, *rule)
55 if !found {
56 t.Fatal("Rule has diffrent options than one added")
57 }
58
59 if err := RuleDel(rule); err != nil {
60 t.Fatal(err)
61 }
62
63 rulesEnd, err := RuleList(FAMILY_V4)
64 if err != nil {
65 t.Fatal(err)
66 }
67
68 if len(rulesEnd) != len(rulesBegin) {
69 t.Fatal("Rule not removed properly")
70 }
71 }
72
73 func TestRuleListFiltered(t *testing.T) {
74 skipUnlessRoot(t)
75 defer setUpNetlinkTest(t)()
76
77 t.Run("IPv4", testRuleListFilteredIPv4)
78 t.Run("IPv6", testRuleListFilteredIPv6)
79 }
80
81 func testRuleListFilteredIPv4(t *testing.T) {
82 srcNet := &net.IPNet{IP: net.IPv4(172, 16, 0, 1), Mask: net.CIDRMask(16, 32)}
83 dstNet := &net.IPNet{IP: net.IPv4(172, 16, 1, 1), Mask: net.CIDRMask(24, 32)}
84 runRuleListFiltered(t, FAMILY_V4, srcNet, dstNet)
85 }
86
87 func testRuleListFilteredIPv6(t *testing.T) {
88 ip1 := net.ParseIP("fd56:6b58:db28:2913::")
89 ip2 := net.ParseIP("fde9:379f:3b35:6635::")
90
91 srcNet := &net.IPNet{IP: ip1, Mask: net.CIDRMask(64, 128)}
92 dstNet := &net.IPNet{IP: ip2, Mask: net.CIDRMask(96, 128)}
93 runRuleListFiltered(t, FAMILY_V6, srcNet, dstNet)
94 }
95
96 func runRuleListFiltered(t *testing.T, family int, srcNet, dstNet *net.IPNet) {
97 defaultRules, _ := RuleList(family)
98
99 tests := []struct {
100 name string
101 ruleFilter *Rule
102 filterMask uint64
103 preRun func() *Rule
104 postRun func(*Rule)
105 setupWant func(*Rule) ([]Rule, bool)
106 }{
107 {
108 name: "returns all rules",
109 ruleFilter: nil,
110 filterMask: 0,
111 preRun: func() *Rule { return nil },
112 postRun: func(r *Rule) {},
113 setupWant: func(_ *Rule) ([]Rule, bool) {
114 return defaultRules, false
115 },
116 },
117 {
118 name: "returns one rule filtered by Src",
119 ruleFilter: &Rule{Src: srcNet},
120 filterMask: RT_FILTER_SRC,
121 preRun: func() *Rule {
122 r := NewRule()
123 r.Src = srcNet
124 r.Priority = 1
125 r.Family = family
126 r.Table = 1
127 RuleAdd(r)
128 return r
129 },
130 postRun: func(r *Rule) { RuleDel(r) },
131 setupWant: func(r *Rule) ([]Rule, bool) {
132 return []Rule{*r}, false
133 },
134 },
135 {
136 name: "returns one rule filtered by Dst",
137 ruleFilter: &Rule{Dst: dstNet},
138 filterMask: RT_FILTER_DST,
139 preRun: func() *Rule {
140 r := NewRule()
141 r.Dst = dstNet
142 r.Priority = 1
143 r.Family = family
144 r.Table = 1
145 RuleAdd(r)
146 return r
147 },
148 postRun: func(r *Rule) { RuleDel(r) },
149 setupWant: func(r *Rule) ([]Rule, bool) {
150 return []Rule{*r}, false
151 },
152 },
153 {
154 name: "returns two rules filtered by Dst",
155 ruleFilter: &Rule{Dst: dstNet},
156 filterMask: RT_FILTER_DST,
157 preRun: func() *Rule {
158 r := NewRule()
159 r.Dst = dstNet
160 r.Priority = 1
161 r.Family = family
162 r.Table = 1
163 RuleAdd(r)
164
165 rc := *r
166 rc.Src = srcNet
167 RuleAdd(&rc)
168
169 return r
170 },
171 postRun: func(r *Rule) {
172 RuleDel(r)
173
174 rc := *r
175 rc.Src = srcNet
176 RuleDel(&rc)
177 },
178 setupWant: func(r *Rule) ([]Rule, bool) {
179 rs := []Rule{}
180 rs = append(rs, *r)
181
182 rc := *r
183 rc.Src = srcNet
184 rs = append(rs, rc)
185
186 return rs, false
187 },
188 },
189 {
190 name: "returns one rule filtered by Src when two rules exist",
191 ruleFilter: &Rule{Src: srcNet},
192 filterMask: RT_FILTER_SRC,
193 preRun: func() *Rule {
194 r := NewRule()
195 r.Dst = dstNet
196 r.Priority = 1
197 r.Family = family
198 r.Table = 1
199 RuleAdd(r)
200
201 rc := *r
202 rc.Src = srcNet
203 RuleAdd(&rc)
204
205 return r
206 },
207 postRun: func(r *Rule) {
208 RuleDel(r)
209
210 rc := *r
211 rc.Src = srcNet
212 RuleDel(&rc)
213 },
214 setupWant: func(r *Rule) ([]Rule, bool) {
215 rs := []Rule{}
216
217
218 rc := *r
219 rc.Src = srcNet
220 rs = append(rs, rc)
221
222 return rs, false
223 },
224 },
225 {
226 name: "returns one rule filtered by Priority(0) and Table",
227 ruleFilter: &Rule{Priority: 0, Table: 1},
228 filterMask: RT_FILTER_PRIORITY | RT_FILTER_TABLE,
229 preRun: func() *Rule {
230 r := NewRule()
231 r.Src = srcNet
232 r.Priority = 0
233 r.Family = family
234 r.Table = 1
235 RuleAdd(r)
236 return r
237 },
238 postRun: func(r *Rule) {
239 RuleDel(r)
240 },
241 setupWant: func(r *Rule) ([]Rule, bool) {
242 return []Rule{*r}, false
243 },
244 },
245 {
246 name: "returns one rule filtered by Priority preceding main-table rule",
247 ruleFilter: &Rule{Priority: 32765},
248 filterMask: RT_FILTER_PRIORITY,
249 preRun: func() *Rule {
250 r := NewRule()
251 r.Src = srcNet
252 r.Family = family
253 r.Table = 1
254 RuleAdd(r)
255
256 r.Priority = 32765
257 return r
258 },
259 postRun: func(r *Rule) {
260 RuleDel(r)
261 },
262 setupWant: func(r *Rule) ([]Rule, bool) {
263 return []Rule{*r}, false
264 },
265 },
266 {
267 name: "returns rules with specific priority",
268 ruleFilter: &Rule{Priority: 5},
269 filterMask: RT_FILTER_PRIORITY,
270 preRun: func() *Rule {
271 r := NewRule()
272 r.Src = srcNet
273 r.Priority = 5
274 r.Family = family
275 r.Table = 1
276 RuleAdd(r)
277
278 for i := 2; i < 5; i++ {
279 rc := *r
280 rc.Table = i
281 RuleAdd(&rc)
282 }
283
284 return r
285 },
286 postRun: func(r *Rule) {
287 RuleDel(r)
288
289 for i := 2; i < 5; i++ {
290 rc := *r
291 rc.Table = -1
292 RuleDel(&rc)
293 }
294 },
295 setupWant: func(r *Rule) ([]Rule, bool) {
296 rs := []Rule{}
297 rs = append(rs, *r)
298
299 for i := 2; i < 5; i++ {
300 rc := *r
301 rc.Table = i
302 rs = append(rs, rc)
303 }
304
305 return rs, false
306 },
307 },
308 {
309 name: "returns rules filtered by Table",
310 ruleFilter: &Rule{Table: 199},
311 filterMask: RT_FILTER_TABLE,
312 preRun: func() *Rule {
313 r := NewRule()
314 r.Src = srcNet
315 r.Priority = 1
316 r.Family = family
317 r.Table = 199
318 RuleAdd(r)
319 return r
320 },
321 postRun: func(r *Rule) { RuleDel(r) },
322 setupWant: func(r *Rule) ([]Rule, bool) {
323 return []Rule{*r}, false
324 },
325 },
326 {
327 name: "returns rules filtered by Mask",
328 ruleFilter: &Rule{Mask: &[]uint32{0x5}[0]},
329 filterMask: RT_FILTER_MASK,
330 preRun: func() *Rule {
331 r := NewRule()
332 r.Src = srcNet
333 r.Priority = 1
334 r.Family = family
335 r.Table = 1
336 r.Mask = &[]uint32{0x5}[0]
337 RuleAdd(r)
338 return r
339 },
340 postRun: func(r *Rule) { RuleDel(r) },
341 setupWant: func(r *Rule) ([]Rule, bool) {
342 return []Rule{*r}, false
343 },
344 },
345 {
346 name: "returns rules filtered by Mark",
347 ruleFilter: &Rule{Mark: 0xbb},
348 filterMask: RT_FILTER_MARK,
349 preRun: func() *Rule {
350 r := NewRule()
351 r.Src = srcNet
352 r.Priority = 1
353 r.Family = family
354 r.Table = 1
355 r.Mask = &[]uint32{0xff}[0]
356 r.Mark = 0xbb
357 RuleAdd(r)
358 return r
359 },
360 postRun: func(r *Rule) { RuleDel(r) },
361 setupWant: func(r *Rule) ([]Rule, bool) {
362 return []Rule{*r}, false
363 },
364 },
365 {
366 name: "returns rules filtered by fwmark 0",
367 ruleFilter: &Rule{Mark: 0, Mask: nil, Table: 100},
368 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
369 preRun: func() *Rule {
370 r := NewRule()
371 r.Src = srcNet
372 r.Priority = 1
373 r.Family = family
374 r.Table = 100
375 r.Mark = 0
376 r.Mask = nil
377 if err := RuleAdd(r); err != nil {
378 t.Fatal(err)
379 }
380 return r
381 },
382 postRun: func(r *Rule) { RuleDel(r) },
383 setupWant: func(r *Rule) ([]Rule, bool) {
384 return []Rule{*r}, false
385 },
386 },
387 {
388 name: "returns rules filtered by fwmark 0/0xFFFFFFFF",
389 ruleFilter: &Rule{Mark: 0, Mask: &[]uint32{0xFFFFFFFF}[0], Table: 100},
390 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
391 preRun: func() *Rule {
392 r := NewRule()
393 r.Src = srcNet
394 r.Priority = 1
395 r.Family = family
396 r.Table = 100
397 r.Mark = 0
398 r.Mask = &[]uint32{0xFFFFFFFF}[0]
399 if err := RuleAdd(r); err != nil {
400 t.Fatal(err)
401 }
402 return r
403 },
404 postRun: func(r *Rule) { RuleDel(r) },
405 setupWant: func(r *Rule) ([]Rule, bool) {
406 return []Rule{*r}, false
407 },
408 },
409 {
410 name: "returns rules filtered by fwmark 0x1234/0",
411 ruleFilter: &Rule{Mark: 0x1234, Mask: &[]uint32{0}[0], Table: 100},
412 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
413 preRun: func() *Rule {
414 r := NewRule()
415 r.Src = srcNet
416 r.Priority = 1
417 r.Family = family
418 r.Table = 100
419 r.Mark = 0x1234
420 r.Mask = &[]uint32{0}[0]
421 if err := RuleAdd(r); err != nil {
422 t.Fatal(err)
423 }
424 return r
425 },
426 postRun: func(r *Rule) { RuleDel(r) },
427 setupWant: func(r *Rule) ([]Rule, bool) {
428 return []Rule{*r}, false
429 },
430 },
431 {
432 name: "returns rules filtered by fwmark 0/0xFFFFFFFF",
433 ruleFilter: &Rule{Mark: 0, Mask: &[]uint32{0xFFFFFFFF}[0], Table: 100},
434 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
435 preRun: func() *Rule {
436 r := NewRule()
437 r.Src = srcNet
438 r.Priority = 1
439 r.Family = family
440 r.Table = 100
441 r.Mark = 0
442 r.Mask = &[]uint32{0xFFFFFFFF}[0]
443 if err := RuleAdd(r); err != nil {
444 t.Fatal(err)
445 }
446 return r
447 },
448 postRun: func(r *Rule) { RuleDel(r) },
449 setupWant: func(r *Rule) ([]Rule, bool) {
450 return []Rule{*r}, false
451 },
452 },
453 {
454 name: "returns rules filtered by fwmark 0xFFFFFFFF",
455 ruleFilter: &Rule{Mark: 0xFFFFFFFF, Mask: &[]uint32{0xFFFFFFFF}[0], Table: 100},
456 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
457 preRun: func() *Rule {
458 r := NewRule()
459 r.Src = srcNet
460 r.Priority = 1
461 r.Family = family
462 r.Table = 100
463 r.Mark = 0xFFFFFFFF
464 r.Mask = nil
465 if err := RuleAdd(r); err != nil {
466 t.Fatal(err)
467 }
468 return r
469 },
470 postRun: func(r *Rule) { RuleDel(r) },
471 setupWant: func(r *Rule) ([]Rule, bool) {
472 return []Rule{*r}, false
473 },
474 },
475 {
476 name: "returns rules filtered by fwmark 0x1234",
477 ruleFilter: &Rule{Mark: 0x1234, Mask: &[]uint32{0xFFFFFFFF}[0], Table: 100},
478 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
479 preRun: func() *Rule {
480 r := NewRule()
481 r.Src = srcNet
482 r.Priority = 1
483 r.Family = family
484 r.Table = 100
485 r.Mark = 0x1234
486 r.Mask = nil
487 if err := RuleAdd(r); err != nil {
488 t.Fatal(err)
489 }
490 return r
491 },
492 postRun: func(r *Rule) { RuleDel(r) },
493 setupWant: func(r *Rule) ([]Rule, bool) {
494 return []Rule{*r}, false
495 },
496 },
497 {
498 name: "returns rules filtered by fwmark 0x12345678",
499 ruleFilter: &Rule{Mark: 0x12345678, Mask: &[]uint32{0xFFFFFFFF}[0], Table: 100},
500 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
501 preRun: func() *Rule {
502 r := NewRule()
503 r.Src = srcNet
504 r.Priority = 1
505 r.Family = family
506 r.Table = 100
507 r.Mark = 0x12345678
508 r.Mask = nil
509 if err := RuleAdd(r); err != nil {
510 t.Fatal(err)
511 }
512 return r
513 },
514 postRun: func(r *Rule) { RuleDel(r) },
515 setupWant: func(r *Rule) ([]Rule, bool) {
516 return []Rule{*r}, false
517 },
518 },
519 {
520 name: "returns rules filtered by fwmark 0xFFFFFFFF/0",
521 ruleFilter: &Rule{Mark: 0xFFFFFFFF, Mask: &[]uint32{0}[0], Table: 100},
522 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
523 preRun: func() *Rule {
524 r := NewRule()
525 r.Src = srcNet
526 r.Priority = 1
527 r.Family = family
528 r.Table = 100
529 r.Mark = 0xFFFFFFFF
530 r.Mask = &[]uint32{0}[0]
531 if err := RuleAdd(r); err != nil {
532 t.Fatal(err)
533 }
534 return r
535 },
536 postRun: func(r *Rule) { RuleDel(r) },
537 setupWant: func(r *Rule) ([]Rule, bool) {
538 return []Rule{*r}, false
539 },
540 },
541 {
542 name: "returns rules filtered by fwmark 0xFFFFFFFF/0xFFFFFFFF",
543 ruleFilter: &Rule{Mark: 0xFFFFFFFF, Mask: &[]uint32{0xFFFFFFFF}[0], Table: 100},
544 filterMask: RT_FILTER_MARK | RT_FILTER_MASK | RT_FILTER_TABLE,
545 preRun: func() *Rule {
546 r := NewRule()
547 r.Src = srcNet
548 r.Priority = 1
549 r.Family = family
550 r.Table = 100
551 r.Mark = 0xFFFFFFFF
552 r.Mask = &[]uint32{0xFFFFFFFF}[0]
553 if err := RuleAdd(r); err != nil {
554 t.Fatal(err)
555 }
556 return r
557 },
558 postRun: func(r *Rule) { RuleDel(r) },
559 setupWant: func(r *Rule) ([]Rule, bool) {
560 return []Rule{*r}, false
561 },
562 },
563 {
564 name: "returns rules filtered by Tos",
565 ruleFilter: &Rule{Tos: 12},
566 filterMask: RT_FILTER_TOS,
567 preRun: func() *Rule {
568 r := NewRule()
569 r.Src = srcNet
570 r.Priority = 1
571 r.Family = family
572 r.Table = 12
573 r.Tos = 12
574 RuleAdd(r)
575 return r
576 },
577 postRun: func(r *Rule) { RuleDel(r) },
578 setupWant: func(r *Rule) ([]Rule, bool) {
579 return []Rule{*r}, false
580 },
581 },
582 }
583 for _, tt := range tests {
584 t.Run(tt.name, func(t *testing.T) {
585 rule := tt.preRun()
586 rules, err := RuleListFiltered(family, tt.ruleFilter, tt.filterMask)
587 tt.postRun(rule)
588
589 wantRules, wantErr := tt.setupWant(rule)
590
591 if len(wantRules) != len(rules) {
592 t.Errorf("Expected len: %d, got: %d", len(wantRules), len(rules))
593 } else {
594 for i := range wantRules {
595 if !ruleEquals(wantRules[i], rules[i]) {
596 t.Errorf("Rules mismatch, want %v, got %v", wantRules[i], rules[i])
597 }
598 }
599 }
600
601 if (err != nil) != wantErr {
602 t.Errorf("Error expectation not met, want %v, got %v", (err != nil), wantErr)
603 }
604 })
605 }
606 }
607
608 func TestRuleString(t *testing.T) {
609 t.Parallel()
610
611 testCases := map[string]struct {
612 r Rule
613 s string
614 }{
615 "empty rule": {
616 s: "ip rule 0: from all to all table 0 ",
617 },
618 "rule with src and dst equivalent to <nil>": {
619 r: Rule{
620 Priority: 100,
621 Src: &net.IPNet{IP: net.IPv4(10, 0, 0, 0)},
622 Dst: &net.IPNet{IP: net.IPv4(20, 0, 0, 0)},
623 Table: 99,
624 },
625 s: "ip rule 100: from all to all table 99 ",
626 },
627 "rule with src and dst": {
628 r: Rule{
629 Priority: 100,
630 Src: &net.IPNet{IP: net.IPv4(10, 0, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)},
631 Dst: &net.IPNet{IP: net.IPv4(20, 0, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)},
632 Table: 99,
633 },
634 s: "ip rule 100: from 10.0.0.0/24 to 20.0.0.0/24 table 99 ",
635 },
636 "rule with type": {
637 r: Rule{
638 Priority: 101,
639 Type: unix.RTN_UNREACHABLE,
640 },
641 s: "ip rule 101: from all to all table 0 unreachable",
642 },
643 }
644
645 for name, testCase := range testCases {
646 testCase := testCase
647 t.Run(name, func(t *testing.T) {
648 t.Parallel()
649
650 s := testCase.r.String()
651
652 if s != testCase.s {
653 t.Errorf("expected %q but got %q", testCase.s, s)
654 }
655 })
656 }
657 }
658
659 func ruleExists(rules []Rule, rule Rule) bool {
660 for i := range rules {
661 if ruleEquals(rules[i], rule) {
662 return true
663 }
664 }
665
666 return false
667 }
668
669 func ruleEquals(a, b Rule) bool {
670 return a.Table == b.Table &&
671 ((a.Src == nil && b.Src == nil) ||
672 (a.Src != nil && b.Src != nil && a.Src.String() == b.Src.String())) &&
673 ((a.Dst == nil && b.Dst == nil) ||
674 (a.Dst != nil && b.Dst != nil && a.Dst.String() == b.Dst.String())) &&
675 a.OifName == b.OifName &&
676 a.Priority == b.Priority &&
677 a.Family == b.Family &&
678 a.IifName == b.IifName &&
679 a.Invert == b.Invert &&
680 a.Tos == b.Tos &&
681 a.Type == b.Type &&
682 a.IPProto == b.IPProto &&
683 a.Protocol == b.Protocol &&
684 a.Mark == b.Mark &&
685 (ptrEqual(a.Mask, b.Mask) || (a.Mark != 0 &&
686 (a.Mask == nil && *b.Mask == 0xFFFFFFFF || b.Mask == nil && *a.Mask == 0xFFFFFFFF)))
687 }
688
View as plain text