From e1cb763b65262eef5958d19fe922380aa1e96570 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Tue, 14 Jun 2022 14:59:58 +0200 Subject: [PATCH] ruleset: reuse zone-jump.uc template for notrack and helper chain jumps Avoid some code-duplication by reusing the zone-jump.uc partial template to emit the helper_* chain jump rules. Also add some test coverage for notrack rules. Signed-off-by: Jo-Philipp Wich --- root/usr/share/firewall4/templates/ruleset.uc | 20 +- .../share/firewall4/templates/zone-jump.uc | 2 +- tests/01_configuration/01_ruleset | 2 +- tests/02_zones/01_policies | 6 +- tests/02_zones/04_wildcard_devices | 16 +- tests/02_zones/05_subnet_mask_matches | 6 +- tests/02_zones/07_helpers | 8 +- tests/03_rules/05_mangle | 4 +- tests/03_rules/10_notrack | 275 ++++++++++++++++++ 9 files changed, 301 insertions(+), 38 deletions(-) create mode 100644 tests/03_rules/10_notrack diff --git a/root/usr/share/firewall4/templates/ruleset.uc b/root/usr/share/firewall4/templates/ruleset.uc index 9d3be7f..d374984 100644 --- a/root/usr/share/firewall4/templates/ruleset.uc +++ b/root/usr/share/firewall4/templates/ruleset.uc @@ -147,10 +147,7 @@ table inet fw4 { {% let devices_pos = fw4.filter_loopback_devs(rule.devices_pos, true); %} {% let subnets_pos = fw4.filter_loopback_addrs(rule.subnets_pos, true); %} {% if (devices_pos || subnets_pos): %} - {%+ if (rule.family): -%} - meta nfproto {{ fw4.nfproto(rule.family) }} {%+ endif -%} - {%+ include("zone-match.uc", { fw4, egress: false, rule: { ...rule, devices_pos, subnets_pos } }) -%} - jump helper_{{ zone.name }} comment "!fw4: {{ zone.name }} {{ fw4.nfproto(rule.family, true) }} CT helper assignment" + {%+ include("zone-jump.uc", { fw4, zone, rule: { ...rule, devices_pos, subnets_pos }, direction: "helper" }) %} {% endif %} {% endif %} {%+ include("zone-jump.uc", { fw4, zone, rule, direction: "output" }) %} @@ -169,10 +166,7 @@ table inet fw4 { {% let devices_pos = fw4.filter_loopback_devs(rule.devices_pos, false); %} {% let subnets_pos = fw4.filter_loopback_addrs(rule.subnets_pos, false); %} {% if (rule.devices_neg || rule.subnets_neg || devices_pos || subnets_pos): %} - {%+ if (rule.family): -%} - meta nfproto {{ fw4.nfproto(rule.family) }} {%+ endif -%} - {%+ include("zone-match.uc", { fw4, egress: false, rule: { ...rule, devices_pos, subnets_pos } }) -%} - jump helper_{{ zone.name }} comment "!fw4: {{ zone.name }} {{ fw4.nfproto(rule.family, true) }} CT helper assignment" + {%+ include("zone-jump.uc", { fw4, zone, rule: { ...rule, devices_pos, subnets_pos }, direction: "helper" }) %} {% endif %} {% endfor %} {% endif %} @@ -333,10 +327,7 @@ table inet fw4 { {% let devices_pos = fw4.filter_loopback_devs(rule.devices_pos, false); %} {% let subnets_pos = fw4.filter_loopback_addrs(rule.subnets_pos, false); %} {% if (rule.devices_neg || rule.subnets_neg || devices_pos || subnets_pos): %} - {%+ if (rule.family): -%} - meta nfproto {{ fw4.nfproto(rule.family) }} {%+ endif -%} - {%+ include("zone-match.uc", { fw4, egress: false, rule: { ...rule, devices_pos, subnets_pos } }) -%} - jump notrack_{{ zone.name }} comment "!fw4: {{ zone.name }} {{ fw4.nfproto(rule.family, true) }} CT bypass" + {%+ include("zone-jump.uc", { fw4, zone, rule: { ...rule, devices_pos, subnets_pos }, direction: "notrack" }) %} {% endif %} {% endfor %} {% endif %} @@ -351,10 +342,7 @@ table inet fw4 { {% let devices_pos = fw4.filter_loopback_devs(rule.devices_pos, true); %} {% let subnets_pos = fw4.filter_loopback_addrs(rule.subnets_pos, true); %} {% if (devices_pos || subnets_pos): %} - {%+ if (rule.family): -%} - meta nfproto {{ fw4.nfproto(rule.family) }} {%+ endif -%} - {%+ include("zone-match.uc", { fw4, egress: false, rule: { ...rule, devices_pos, subnets_pos } }) -%} - jump notrack_{{ zone.name }} comment "!fw4: {{ zone.name }} {{ fw4.nfproto(rule.family, true) }} CT bypass" + {%+ include("zone-jump.uc", { fw4, zone, rule: { ...rule, devices_pos, subnets_pos }, direction: "notrack" }) %} {% endif %} {% endfor %} {% endif %} diff --git a/root/usr/share/firewall4/templates/zone-jump.uc b/root/usr/share/firewall4/templates/zone-jump.uc index 902321f..e31b0bc 100644 --- a/root/usr/share/firewall4/templates/zone-jump.uc +++ b/root/usr/share/firewall4/templates/zone-jump.uc @@ -3,4 +3,4 @@ {%+ include("zone-match.uc", { egress: (direction in ["output", "srcnat"]), rule }) -%} jump {{ direction }}_{{ zone.name }} comment "!fw4: Handle {{ zone.name }} {{ fw4.nfproto(rule.family, true) -}} {{ direction }} traffic" +}} {{ direction }} {{ (direction == 'helper') ? "assignment" : "traffic" }}" diff --git a/tests/01_configuration/01_ruleset b/tests/01_configuration/01_ruleset index cd32edc..9acb429 100644 --- a/tests/01_configuration/01_ruleset +++ b/tests/01_configuration/01_ruleset @@ -142,7 +142,7 @@ table inet fw4 { chain prerouting { type filter hook prerouting priority filter; policy accept; - iifname "br-lan" jump helper_lan comment "!fw4: lan IPv4/IPv6 CT helper assignment" + iifname "br-lan" jump helper_lan comment "!fw4: Handle lan IPv4/IPv6 helper assignment" } chain handle_reject { diff --git a/tests/02_zones/01_policies b/tests/02_zones/01_policies index 86c2910..5a2eeac 100644 --- a/tests/02_zones/01_policies +++ b/tests/02_zones/01_policies @@ -122,9 +122,9 @@ table inet fw4 { chain prerouting { type filter hook prerouting priority filter; policy accept; - iifname "zone1" jump helper_test1 comment "!fw4: test1 IPv4/IPv6 CT helper assignment" - iifname "zone2" jump helper_test2 comment "!fw4: test2 IPv4/IPv6 CT helper assignment" - iifname "zone3" jump helper_test3 comment "!fw4: test3 IPv4/IPv6 CT helper assignment" + iifname "zone1" jump helper_test1 comment "!fw4: Handle test1 IPv4/IPv6 helper assignment" + iifname "zone2" jump helper_test2 comment "!fw4: Handle test2 IPv4/IPv6 helper assignment" + iifname "zone3" jump helper_test3 comment "!fw4: Handle test3 IPv4/IPv6 helper assignment" } chain handle_reject { diff --git a/tests/02_zones/04_wildcard_devices b/tests/02_zones/04_wildcard_devices index 8695594..b7e01e1 100644 --- a/tests/02_zones/04_wildcard_devices +++ b/tests/02_zones/04_wildcard_devices @@ -163,14 +163,14 @@ table inet fw4 { chain prerouting { type filter hook prerouting priority filter; policy accept; - iifname "/never/" jump helper_test2 comment "!fw4: test2 IPv4/IPv6 CT helper assignment" - iifname "test*" jump helper_test3 comment "!fw4: test3 IPv4/IPv6 CT helper assignment" - iifname "foo*" jump helper_test4 comment "!fw4: test4 IPv4/IPv6 CT helper assignment" - iifname "bar*" jump helper_test4 comment "!fw4: test4 IPv4/IPv6 CT helper assignment" - iifname { "test1", "test2" } jump helper_test4 comment "!fw4: test4 IPv4/IPv6 CT helper assignment" - iifname "foo*" iifname != { "test3", "test4" } iifname != "baz*" iifname != "qrx*" jump helper_test5 comment "!fw4: test5 IPv4/IPv6 CT helper assignment" - iifname "bar*" iifname != { "test3", "test4" } iifname != "baz*" iifname != "qrx*" jump helper_test5 comment "!fw4: test5 IPv4/IPv6 CT helper assignment" - iifname { "test1", "test2" } iifname != { "test3", "test4" } iifname != "baz*" iifname != "qrx*" jump helper_test5 comment "!fw4: test5 IPv4/IPv6 CT helper assignment" + iifname "/never/" jump helper_test2 comment "!fw4: Handle test2 IPv4/IPv6 helper assignment" + iifname "test*" jump helper_test3 comment "!fw4: Handle test3 IPv4/IPv6 helper assignment" + iifname "foo*" jump helper_test4 comment "!fw4: Handle test4 IPv4/IPv6 helper assignment" + iifname "bar*" jump helper_test4 comment "!fw4: Handle test4 IPv4/IPv6 helper assignment" + iifname { "test1", "test2" } jump helper_test4 comment "!fw4: Handle test4 IPv4/IPv6 helper assignment" + iifname "foo*" iifname != { "test3", "test4" } iifname != "baz*" iifname != "qrx*" jump helper_test5 comment "!fw4: Handle test5 IPv4/IPv6 helper assignment" + iifname "bar*" iifname != { "test3", "test4" } iifname != "baz*" iifname != "qrx*" jump helper_test5 comment "!fw4: Handle test5 IPv4/IPv6 helper assignment" + iifname { "test1", "test2" } iifname != { "test3", "test4" } iifname != "baz*" iifname != "qrx*" jump helper_test5 comment "!fw4: Handle test5 IPv4/IPv6 helper assignment" } chain handle_reject { diff --git a/tests/02_zones/05_subnet_mask_matches b/tests/02_zones/05_subnet_mask_matches index 2910800..27f9dbc 100644 --- a/tests/02_zones/05_subnet_mask_matches +++ b/tests/02_zones/05_subnet_mask_matches @@ -112,9 +112,9 @@ table inet fw4 { chain prerouting { type filter hook prerouting priority filter; policy accept; - meta nfproto ipv6 ip6 saddr != { ::7, ::8 } ip6 saddr & ::ffff == ::1 ip6 saddr & ::ffff != ::5 ip6 saddr & ::ffff != ::6 jump helper_test2 comment "!fw4: test2 IPv6 CT helper assignment" - meta nfproto ipv6 ip6 saddr != { ::7, ::8 } ip6 saddr & ::ffff == ::2 ip6 saddr & ::ffff != ::5 ip6 saddr & ::ffff != ::6 jump helper_test2 comment "!fw4: test2 IPv6 CT helper assignment" - meta nfproto ipv6 ip6 saddr { ::3, ::4 } ip6 saddr != { ::7, ::8 } ip6 saddr & ::ffff != ::5 ip6 saddr & ::ffff != ::6 jump helper_test2 comment "!fw4: test2 IPv6 CT helper assignment" + meta nfproto ipv6 ip6 saddr != { ::7, ::8 } ip6 saddr & ::ffff == ::1 ip6 saddr & ::ffff != ::5 ip6 saddr & ::ffff != ::6 jump helper_test2 comment "!fw4: Handle test2 IPv6 helper assignment" + meta nfproto ipv6 ip6 saddr != { ::7, ::8 } ip6 saddr & ::ffff == ::2 ip6 saddr & ::ffff != ::5 ip6 saddr & ::ffff != ::6 jump helper_test2 comment "!fw4: Handle test2 IPv6 helper assignment" + meta nfproto ipv6 ip6 saddr { ::3, ::4 } ip6 saddr != { ::7, ::8 } ip6 saddr & ::ffff != ::5 ip6 saddr & ::ffff != ::6 jump helper_test2 comment "!fw4: Handle test2 IPv6 helper assignment" } chain handle_reject { diff --git a/tests/02_zones/07_helpers b/tests/02_zones/07_helpers index c6f68de..ceef65a 100644 --- a/tests/02_zones/07_helpers +++ b/tests/02_zones/07_helpers @@ -196,10 +196,10 @@ table inet fw4 { chain prerouting { type filter hook prerouting priority filter; policy accept; - iifname "zone1" jump helper_test1 comment "!fw4: test1 IPv4/IPv6 CT helper assignment" - iifname "zone2" jump helper_test2 comment "!fw4: test2 IPv4/IPv6 CT helper assignment" - iifname "zone3" jump helper_test3 comment "!fw4: test3 IPv4/IPv6 CT helper assignment" - iifname "zone4" jump helper_test4 comment "!fw4: test4 IPv4/IPv6 CT helper assignment" + iifname "zone1" jump helper_test1 comment "!fw4: Handle test1 IPv4/IPv6 helper assignment" + iifname "zone2" jump helper_test2 comment "!fw4: Handle test2 IPv4/IPv6 helper assignment" + iifname "zone3" jump helper_test3 comment "!fw4: Handle test3 IPv4/IPv6 helper assignment" + iifname "zone4" jump helper_test4 comment "!fw4: Handle test4 IPv4/IPv6 helper assignment" } chain handle_reject { diff --git a/tests/03_rules/05_mangle b/tests/03_rules/05_mangle index 79ae8ec..04ae461 100644 --- a/tests/03_rules/05_mangle +++ b/tests/03_rules/05_mangle @@ -204,8 +204,8 @@ table inet fw4 { chain prerouting { type filter hook prerouting priority filter; policy accept; - iifname { "eth0", "eth1" } jump helper_lan comment "!fw4: lan IPv4/IPv6 CT helper assignment" - iifname { "eth2", "eth3" } jump helper_wan comment "!fw4: wan IPv4/IPv6 CT helper assignment" + iifname { "eth0", "eth1" } jump helper_lan comment "!fw4: Handle lan IPv4/IPv6 helper assignment" + iifname { "eth2", "eth3" } jump helper_wan comment "!fw4: Handle wan IPv4/IPv6 helper assignment" } chain handle_reject { diff --git a/tests/03_rules/10_notrack b/tests/03_rules/10_notrack new file mode 100644 index 0000000..717894b --- /dev/null +++ b/tests/03_rules/10_notrack @@ -0,0 +1,275 @@ +Ensure that NOTRACK rules end up in the appropriate chains, depending on +the src and dest options. + +-- Testcase -- +{% + include("./root/usr/share/firewall4/main.uc", { + getenv: function(varname) { + switch (varname) { + case 'ACTION': + return 'print'; + } + } + }) +%} +-- End -- + +-- File uci/helpers.json -- +{} +-- End -- + +-- File fs/open~_sys_class_net_eth0_flags.txt -- +0x1103 +-- End -- + +-- File fs/open~_sys_class_net_lo_flags.txt -- +0x9 +-- End -- + +-- File uci/firewall.json -- +{ + "zone": [ + { + "name": "zone1", + "device": [ "eth0" ], + "auto_helper": 0 + }, + { + "name": "zone2", + "device": [ "lo" ], + "auto_helper": 0 + }, + { + "name": "zone3", + "subnet": [ "127.0.0.1/8", "::1/128" ], + "auto_helper": 0 + } + ], + "rule": [ + { + ".description": "An ordinary notrack rule should end up in the raw_prerouting chain", + "name": "Notrack rule #1", + "src": "zone1", + "target": "NOTRACK" + }, + { + ".description": "A notrack rule with loopback source device should end up in the raw_output chain", + "name": "Notrack rule #2", + "src": "zone2", + "target": "NOTRACK" + }, + { + ".description": "A notrack rule with loopback source address should end up in the raw_output chain", + "name": "Notrack rule #3", + "src": "zone3", + "target": "NOTRACK" + } + ] +} +-- End -- + +-- Expect stdout -- +table inet fw4 +flush table inet fw4 + +table inet fw4 { + # + # Set definitions + # + + + # + # Defines + # + + define zone1_devices = { "eth0" } + define zone2_devices = { "lo" } + define zone3_subnets = { 127.0.0.0/8, ::1 } + + # + # User includes + # + + include "/etc/nftables.d/*.nft" + + + # + # Filter rules + # + + chain input { + type filter hook input priority filter; policy drop; + + iifname "lo" accept comment "!fw4: Accept traffic from loopback" + + ct state established,related accept comment "!fw4: Allow inbound established and related flows" + iifname "eth0" jump input_zone1 comment "!fw4: Handle zone1 IPv4/IPv6 input traffic" + iifname "lo" jump input_zone2 comment "!fw4: Handle zone2 IPv4/IPv6 input traffic" + meta nfproto ipv4 ip saddr 127.0.0.0/8 jump input_zone3 comment "!fw4: Handle zone3 IPv4 input traffic" + meta nfproto ipv6 ip6 saddr ::1 jump input_zone3 comment "!fw4: Handle zone3 IPv6 input traffic" + } + + chain forward { + type filter hook forward priority filter; policy drop; + + ct state established,related accept comment "!fw4: Allow forwarded established and related flows" + iifname "eth0" jump forward_zone1 comment "!fw4: Handle zone1 IPv4/IPv6 forward traffic" + iifname "lo" jump forward_zone2 comment "!fw4: Handle zone2 IPv4/IPv6 forward traffic" + meta nfproto ipv4 ip saddr 127.0.0.0/8 jump forward_zone3 comment "!fw4: Handle zone3 IPv4 forward traffic" + meta nfproto ipv6 ip6 saddr ::1 jump forward_zone3 comment "!fw4: Handle zone3 IPv6 forward traffic" + } + + chain output { + type filter hook output priority filter; policy drop; + + oifname "lo" accept comment "!fw4: Accept traffic towards loopback" + + ct state established,related accept comment "!fw4: Allow outbound established and related flows" + oifname "eth0" jump output_zone1 comment "!fw4: Handle zone1 IPv4/IPv6 output traffic" + oifname "lo" jump output_zone2 comment "!fw4: Handle zone2 IPv4/IPv6 output traffic" + meta nfproto ipv4 ip daddr 127.0.0.0/8 jump output_zone3 comment "!fw4: Handle zone3 IPv4 output traffic" + meta nfproto ipv6 ip6 daddr ::1 jump output_zone3 comment "!fw4: Handle zone3 IPv6 output traffic" + } + + chain prerouting { + type filter hook prerouting priority filter; policy accept; + } + + chain handle_reject { + meta l4proto tcp reject with tcp reset comment "!fw4: Reject TCP traffic" + reject with icmpx type port-unreachable comment "!fw4: Reject any other traffic" + } + + chain input_zone1 { + jump drop_from_zone1 + } + + chain output_zone1 { + jump drop_to_zone1 + } + + chain forward_zone1 { + jump drop_to_zone1 + } + + chain drop_from_zone1 { + iifname "eth0" counter drop comment "!fw4: drop zone1 IPv4/IPv6 traffic" + } + + chain drop_to_zone1 { + oifname "eth0" counter drop comment "!fw4: drop zone1 IPv4/IPv6 traffic" + } + + chain input_zone2 { + jump drop_from_zone2 + } + + chain output_zone2 { + jump drop_to_zone2 + } + + chain forward_zone2 { + jump drop_to_zone2 + } + + chain drop_from_zone2 { + iifname "lo" counter drop comment "!fw4: drop zone2 IPv4/IPv6 traffic" + } + + chain drop_to_zone2 { + oifname "lo" counter drop comment "!fw4: drop zone2 IPv4/IPv6 traffic" + } + + chain input_zone3 { + jump drop_from_zone3 + } + + chain output_zone3 { + jump drop_to_zone3 + } + + chain forward_zone3 { + jump drop_to_zone3 + } + + chain drop_from_zone3 { + meta nfproto ipv4 ip saddr 127.0.0.0/8 counter drop comment "!fw4: drop zone3 IPv4 traffic" + meta nfproto ipv6 ip6 saddr ::1 counter drop comment "!fw4: drop zone3 IPv6 traffic" + } + + chain drop_to_zone3 { + meta nfproto ipv4 ip daddr 127.0.0.0/8 counter drop comment "!fw4: drop zone3 IPv4 traffic" + meta nfproto ipv6 ip6 daddr ::1 counter drop comment "!fw4: drop zone3 IPv6 traffic" + } + + + # + # NAT rules + # + + chain dstnat { + type nat hook prerouting priority dstnat; policy accept; + } + + chain srcnat { + type nat hook postrouting priority srcnat; policy accept; + } + + + # + # Raw rules (notrack) + # + + chain raw_prerouting { + type filter hook prerouting priority raw; policy accept; + iifname "eth0" jump notrack_zone1 comment "!fw4: Handle zone1 IPv4/IPv6 notrack traffic" + } + + chain raw_output { + type filter hook output priority raw; policy accept; + iifname "lo" jump notrack_zone2 comment "!fw4: Handle zone2 IPv4/IPv6 notrack traffic" + meta nfproto ipv4 ip saddr 127.0.0.0/8 jump notrack_zone3 comment "!fw4: Handle zone3 IPv4 notrack traffic" + meta nfproto ipv6 ip6 saddr ::1 jump notrack_zone3 comment "!fw4: Handle zone3 IPv6 notrack traffic" + } + + chain notrack_zone1 { + meta l4proto tcp counter notrack comment "!fw4: Notrack rule #1" + meta l4proto udp counter notrack comment "!fw4: Notrack rule #1" + } + + chain notrack_zone2 { + meta l4proto tcp counter notrack comment "!fw4: Notrack rule #2" + meta l4proto udp counter notrack comment "!fw4: Notrack rule #2" + } + + chain notrack_zone3 { + meta l4proto tcp counter notrack comment "!fw4: Notrack rule #3" + meta l4proto udp counter notrack comment "!fw4: Notrack rule #3" + } + + + # + # Mangle rules + # + + chain mangle_prerouting { + type filter hook prerouting priority mangle; policy accept; + } + + chain mangle_postrouting { + type filter hook postrouting priority mangle; policy accept; + } + + chain mangle_input { + type filter hook input priority mangle; policy accept; + } + + chain mangle_output { + type route hook output priority mangle; policy accept; + } + + chain mangle_forward { + type filter hook forward priority mangle; policy accept; + } +} +-- End -- -- 2.30.2