nat_chain_test.go 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package firewall
  2. import (
  3. "strings"
  4. "testing"
  5. )
  6. func TestChainPlacement(t *testing.T) {
  7. cases := []struct {
  8. kind string
  9. rule any
  10. valid bool
  11. }{
  12. {"nat", NATRule{Chain: "dstnat", Action: "dst-nat"}, true},
  13. {"nat", NATRule{Chain: "prerouting", Action: "dst-nat"}, true},
  14. {"nat", NATRule{Chain: "output", Action: "dst-nat"}, true},
  15. {"nat", NATRule{Chain: "custom", Action: "dst-nat"}, true},
  16. {"nat", NATRule{Chain: "srcnat", Action: "dst-nat"}, false},
  17. {"nat", NATRule{Chain: "forward", Action: "accept"}, false},
  18. {"nat", NATRule{Chain: "srcnat", Action: "masquerade", OutInterface: "eth0"}, true},
  19. {"nat", NATRule{Chain: "input", Action: "masquerade"}, false},
  20. {"nat", NATRule{Chain: "prerouting", Action: "accept", OutInterface: "eth0"}, false},
  21. {"filter", FilterRule{Chain: "prerouting", Action: "accept"}, false},
  22. {"filter", FilterRule{Chain: "input", Action: "accept", OutInterface: "eth0"}, false},
  23. {"mangle", MangleRule{Chain: "output", Action: "accept", InInterface: "eth0"}, false},
  24. {"mangle", MangleRule{Chain: "forward", Action: "accept", InInterface: "eth0", OutInterface: "eth1"}, true},
  25. }
  26. for _, c := range cases {
  27. err := validateChainPlacement(c.kind, c.rule)
  28. if (err == nil) != c.valid {
  29. t.Errorf("%s %#v: %v", c.kind, c.rule, err)
  30. }
  31. }
  32. }
  33. func TestNATChainHooks(t *testing.T) {
  34. rules := []NATRule{{ID: "incoming", Chain: "dstnat", Action: "dst-nat", ToAddresses: "192.0.2.1"}, {ID: "local", Chain: "output", Action: "dst-nat", ToAddresses: "192.0.2.2"}, {ID: "outgoing", Chain: "srcnat", Action: "masquerade"}}
  35. payload := ownedPayload(BuildIPTablesRestore(nil, rules, nil), "")
  36. for _, want := range []string{"-A DT_nat_PREROUTING ", "-A DT_nat_OUTPUT ", "-A DT_nat_POSTROUTING ", "-I PREROUTING 1 -m comment --comment debtik:hook -j DT_nat_PREROUTING", "-I OUTPUT 1 -m comment --comment debtik:hook -j DT_nat_OUTPUT", "-I POSTROUTING 1 -m comment --comment debtik:hook -j DT_nat_POSTROUTING"} {
  37. if !strings.Contains(payload, want) {
  38. t.Errorf("missing %s", want)
  39. }
  40. }
  41. }
  42. func TestNativeTargetsAndPortValidation(t *testing.T) {
  43. for _, action := range []string{"DNAT", "dnat", "dst-nat"} {
  44. r := NATRule{Chain: "prerouting", Action: action, Protocol: "udp", DstPort: "53", ToAddresses: "192.0.2.53"}
  45. if err := ValidateRule("nat", r); err != nil {
  46. t.Fatalf("%s: %v", action, err)
  47. }
  48. normal := normalizeNativeRule("nat", r).(NATRule)
  49. if !strings.Contains(BuildIPTablesRestore(nil, []NATRule{normal}, nil), "-j DNAT --to-destination 192.0.2.53") {
  50. t.Fatalf("%s did not produce DNAT", action)
  51. }
  52. }
  53. for target, want := range map[string]string{"MARK": "mark-packet", "CONNMARK": "mark-connection", "TCPMSS": "change-mss", "DSCP": "change-dscp", "TTL": "change-ttl", "HL": "change-ttl", "CLASSIFY": "set-priority"} {
  54. got := normalizeNativeRule("mangle", MangleRule{Action: target}).(MangleRule).Action
  55. if got != want {
  56. t.Errorf("target %s normalized to %s, want %s", target, got, want)
  57. }
  58. }
  59. for _, rule := range []any{FilterRule{Protocol: "all", DstPort: "53"}, MangleRule{Protocol: "icmp", SrcPort: "53"}, NATRule{Protocol: "!udp", DstPort: "53"}} {
  60. if validateNewPortProtocol(rule) == nil {
  61. t.Fatalf("accepted unsafe port combination: %#v", rule)
  62. }
  63. }
  64. if validateNewPortProtocol(FilterRule{Protocol: "udp", DstPort: "53"}) != nil {
  65. t.Fatal("valid UDP port was rejected")
  66. }
  67. }
  68. func TestNeighboringChainRule(t *testing.T) {
  69. chains := []string{"srcnat", "input", "postrouting", "dstnat", "prerouting"}
  70. for _, tt := range []struct {
  71. index int
  72. dir string
  73. nat bool
  74. want int
  75. }{{0, "down", true, 2}, {2, "up", true, 0}, {3, "down", true, 4}, {1, "up", true, -1}, {0, "down", false, -1}} {
  76. got, err := neighboringChainRule(chains, tt.index, tt.dir, tt.nat)
  77. if err != nil || got != tt.want {
  78. t.Errorf("%+v: got %d %v", tt, got, err)
  79. }
  80. }
  81. if _, err := neighboringChainRule(chains, 0, "sideways", true); err == nil {
  82. t.Fatal("invalid direction accepted")
  83. }
  84. }