firewall4: add fullcone support

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
Signed-off-by: ZiMing Mo <msylgj@immortalwrt.org>
This commit is contained in:
Syrone Wong 2022-04-21 17:42:30 +08:00 committed by ZiMing Mo
parent fb1a04f94b
commit ae33beb603
No known key found for this signature in database
GPG Key ID: 1BED2E3A77AE5ECF
2 changed files with 199 additions and 1 deletions

View File

@ -23,7 +23,7 @@ define Package/firewall4
TITLE:=OpenWrt 4th gen firewall
DEPENDS:= \
+kmod-nft-core +kmod-nft-fib +kmod-nft-offload \
+kmod-nft-nat +kmod-nft-nat6 \
+kmod-nft-nat +kmod-nft-nat6 +kmod-nft-fullcone \
+nftables-json \
+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci
EXTRA_DEPENDS:=ucode (>= 2022-03-22)

View File

@ -0,0 +1,198 @@
From 980594ee7bcb0bcded95731bb12cf118d7f48951 Mon Sep 17 00:00:00 2001
From: Syrone Wong <wong.syrone@gmail.com>
Date: Sat, 9 Apr 2022 13:24:19 +0800
Subject: [PATCH] firewall4: add fullcone support
fullcone is drop-in replacement of masq for non-udp traffic
add runtime fullcone rule check, disable it globally if fullcone expr is
invalid
---
root/etc/config/firewall | 2 +
root/usr/share/firewall4/templates/ruleset.uc | 13 +++++-
.../firewall4/templates/zone-fullcone.uc | 4 ++
root/usr/share/ucode/fw4.uc | 44 ++++++++++++++++++-
4 files changed, 60 insertions(+), 3 deletions(-)
create mode 100644 root/usr/share/firewall4/templates/zone-fullcone.uc
diff --git a/root/etc/config/firewall b/root/etc/config/firewall
index f4a3322..2f17ad2 100644
--- a/root/etc/config/firewall
+++ b/root/etc/config/firewall
@@ -5,6 +5,7 @@ config defaults
option forward REJECT
# Uncomment this line to disable ipv6 rules
# option disable_ipv6 1
+ option fullcone '1'
config zone
option name lan
@@ -20,6 +21,7 @@ config zone
option input REJECT
option output ACCEPT
option forward REJECT
+ option fullcone '1'
option masq 1
option mtu_fix 1
diff --git a/root/usr/share/firewall4/templates/ruleset.uc b/root/usr/share/firewall4/templates/ruleset.uc
index b402315..aae698f 100644
--- a/root/usr/share/firewall4/templates/ruleset.uc
+++ b/root/usr/share/firewall4/templates/ruleset.uc
@@ -1,3 +1,4 @@
+{# /usr/share/firewall4/templates/ruleset.uc #}
{% let flowtable_devices = fw4.resolve_offload_devices(); -%}
table inet fw4
@@ -237,6 +238,10 @@ table inet fw4 {
{% for (let redirect in fw4.redirects("dstnat_"+zone.name)): %}
{%+ include("redirect.uc", { fw4, redirect }) %}
{% endfor %}
+{% if (zone.fullcone): %}
+ {%+ include("zone-fullcone.uc", { fw4, zone, direction: "dstnat" }) %}
+{% endif %}
+
}
{% endif %}
@@ -245,20 +250,24 @@ table inet fw4 {
{% for (let redirect in fw4.redirects("srcnat_"+zone.name)): %}
{%+ include("redirect.uc", { fw4, redirect }) %}
{% endfor %}
-{% if (zone.masq): %}
+{% if (zone.masq && !zone.fullcone): %}
{% for (let saddrs in zone.masq4_src_subnets): %}
{% for (let daddrs in zone.masq4_dest_subnets): %}
{%+ include("zone-masq.uc", { fw4, zone, family: 4, saddrs, daddrs }) %}
{% endfor %}
{% endfor %}
{% endif %}
-{% if (zone.masq6): %}
+{% if (zone.masq6 && !zone.fullcone): %}
{% for (let saddrs in zone.masq6_src_subnets): %}
{% for (let daddrs in zone.masq6_dest_subnets): %}
{%+ include("zone-masq.uc", { fw4, zone, family: 6, saddrs, daddrs }) %}
{% endfor %}
{% endfor %}
{% endif %}
+{% if (zone.fullcone): %}
+ {%+ include("zone-fullcone.uc", { fw4, zone, direction: "srcnat" }) %}
+{% endif %}
+
}
{% endif %}
diff --git a/root/usr/share/firewall4/templates/zone-fullcone.uc b/root/usr/share/firewall4/templates/zone-fullcone.uc
new file mode 100644
index 0000000..f0647da
--- /dev/null
+++ b/root/usr/share/firewall4/templates/zone-fullcone.uc
@@ -0,0 +1,4 @@
+{# /usr/share/firewall4/templates/zone-fullcone.uc #}
+ fullcone comment "!fw4: Handle {{
+ zone.name
+}} IPv4/IPv6 fullcone NAT traffic"
diff --git a/root/usr/share/ucode/fw4.uc b/root/usr/share/ucode/fw4.uc
index b81f9ad..ec5958e 100644
--- a/root/usr/share/ucode/fw4.uc
+++ b/root/usr/share/ucode/fw4.uc
@@ -1,3 +1,5 @@
+// /usr/share/ucode/fw4.uc
+
let fs = require("fs");
let uci = require("uci");
let ubus = require("ubus");
@@ -419,6 +421,25 @@ function nft_try_hw_offload(devices) {
return (rc == 0);
}
+function nft_try_fullcone() {
+ let nft_test =
+ 'add table inet fw4-fullcone-test; ' +
+ 'add chain inet fw4-fullcone-test dstnat { ' +
+ 'type nat hook prerouting priority -100; policy accept; ' +
+ 'fullcone; ' +
+ '}; ' +
+ 'add chain inet fw4-fullcone-test srcnat { ' +
+ 'type nat hook postrouting priority -100; policy accept; ' +
+ 'fullcone; ' +
+ '}; ';
+ let cmd = sprintf("/usr/sbin/nft -c '%s' 2>/dev/null", replace(nft_test, "'", "'\\''"));
+ let ok = system(cmd) == 0;
+ if (!ok) {
+ warn("nft_try_fullcone: cmd "+ cmd + "\n");
+ }
+ return ok;
+}
+
return {
read_kernel_version: function() {
@@ -1382,6 +1403,7 @@ return {
"dnat",
"snat",
"masquerade",
+ "fullcone",
"accept",
"reject",
"drop"
@@ -1787,6 +1809,7 @@ return {
}
let defs = this.parse_options(data, {
+ fullcone: [ "bool", "0" ],
input: [ "policy", "drop" ],
output: [ "policy", "drop" ],
forward: [ "policy", "drop" ],
@@ -1819,6 +1842,11 @@ return {
delete defs.syn_flood;
+ if (!nft_try_fullcone()) {
+ delete defs.fullcone;
+ warn("nft_try_fullcone failed, disable fullcone globally\n");
+ }
+
this.state.defaults = defs;
},
@@ -1843,6 +1871,7 @@ return {
masq_dest: [ "network", null, PARSE_LIST ],
masq6: [ "bool" ],
+ fullcone: [ "bool", "0" ],
extra: [ "string", null, UNSUPPORTED ],
extra_src: [ "string", null, UNSUPPORTED ],
@@ -1873,6 +1902,14 @@ return {
return;
}
+ if (this.state.defaults && !this.state.defaults.fullcone) {
+ this.warn_section(data, "fullcone in defaults not enabled, ignore zone fullcone setting");
+ zone.fullcone = false;
+ }
+ if (zone.fullcone) {
+ this.warn_section(data, "fullcone enabled for zone '" + zone.name + "'");
+ }
+
if (zone.mtu_fix && this.kernel < 0x040a0000) {
this.warn_section(data, "option 'mtu_fix' requires kernel 4.10 or later");
return;
@@ -2041,10 +2078,15 @@ return {
zone.related_subnets = related_subnets;
zone.related_physdevs = related_physdevs;
+ if (zone.fullcone) {
+ zone.dflags.snat = true;
+ zone.dflags.dnat = true;
+ }
+
if (zone.masq || zone.masq6)
zone.dflags.snat = true;
- if ((zone.auto_helper && !(zone.masq || zone.masq6)) || length(zone.helper)) {
+ if ((zone.auto_helper && !(zone.masq || zone.masq6 || zone.fullcone)) || length(zone.helper)) {
zone.dflags.helper = true;
for (let helper in (length(zone.helper) ? zone.helper : this.state.helpers)) {