mirror of
https://github.com/LiBwrt-op/ipq50xx.git
synced 2025-12-16 06:59:52 +00:00
package: nft-fullcone
Add firewall4 and nftables support for fullcone NAT.
This commit is contained in:
parent
b3ba002761
commit
389d8bd58a
@ -23,6 +23,7 @@ PKG_LICENSE_FILES:=COPYING
|
||||
PKG_INSTALL:=1
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_BUILD_FLAGS:=lto
|
||||
PKG_FIXUP:=autoreconf
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
||||
@ -0,0 +1,253 @@
|
||||
From 6c39f04febd7cfdbd474233379416babcd0fc341 Mon Sep 17 00:00:00 2001
|
||||
From: Syrone Wong <wong.syrone@gmail.com>
|
||||
Date: Fri, 8 Apr 2022 23:52:11 +0800
|
||||
Subject: [PATCH] libnftnl: add fullcone expression support
|
||||
|
||||
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
|
||||
---
|
||||
include/libnftnl/expr.h | 6 +
|
||||
include/linux/netfilter/nf_tables.h | 16 +++
|
||||
src/Makefile.am | 1 +
|
||||
src/expr/fullcone.c | 167 ++++++++++++++++++++++++++++
|
||||
src/expr_ops.c | 2 +
|
||||
5 files changed, 192 insertions(+)
|
||||
create mode 100644 src/expr/fullcone.c
|
||||
|
||||
--- a/include/libnftnl/expr.h
|
||||
+++ b/include/libnftnl/expr.h
|
||||
@@ -245,6 +245,12 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
+ NFTNL_EXPR_FULLCONE_FLAGS = NFTNL_EXPR_BASE,
|
||||
+ NFTNL_EXPR_FULLCONE_REG_PROTO_MIN,
|
||||
+ NFTNL_EXPR_FULLCONE_REG_PROTO_MAX,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
NFTNL_EXPR_REDIR_REG_PROTO_MIN = NFTNL_EXPR_BASE,
|
||||
NFTNL_EXPR_REDIR_REG_PROTO_MAX,
|
||||
NFTNL_EXPR_REDIR_FLAGS,
|
||||
--- a/include/linux/netfilter/nf_tables.h
|
||||
+++ b/include/linux/netfilter/nf_tables.h
|
||||
@@ -1464,6 +1464,22 @@ enum nft_masq_attributes {
|
||||
#define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1)
|
||||
|
||||
/**
|
||||
+ * enum nft_fullcone_attributes - nf_tables fullcone expression attributes
|
||||
+ *
|
||||
+ * @NFTA_FULLCONE_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
|
||||
+ * @NFTA_FULLCONE_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
|
||||
+ * @NFTA_FULLCONE_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
|
||||
+ */
|
||||
+enum nft_fullcone_attributes {
|
||||
+ NFTA_FULLCONE_UNSPEC,
|
||||
+ NFTA_FULLCONE_FLAGS,
|
||||
+ NFTA_FULLCONE_REG_PROTO_MIN,
|
||||
+ NFTA_FULLCONE_REG_PROTO_MAX,
|
||||
+ __NFTA_FULLCONE_MAX
|
||||
+};
|
||||
+#define NFTA_FULLCONE_MAX (__NFTA_FULLCONE_MAX - 1)
|
||||
+
|
||||
+/**
|
||||
* enum nft_redir_attributes - nf_tables redirect expression netlink attributes
|
||||
*
|
||||
* @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -55,6 +55,7 @@ libnftnl_la_SOURCES = utils.c \
|
||||
expr/target.c \
|
||||
expr/tunnel.c \
|
||||
expr/masq.c \
|
||||
+ expr/fullcone.c \
|
||||
expr/redir.c \
|
||||
expr/hash.c \
|
||||
expr/socket.c \
|
||||
--- /dev/null
|
||||
+++ b/src/expr/fullcone.c
|
||||
@@ -0,0 +1,167 @@
|
||||
+/*
|
||||
+ * (C) 2022 wongsyrone
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published
|
||||
+ * by the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <stdint.h>
|
||||
+#include <arpa/inet.h>
|
||||
+#include <errno.h>
|
||||
+#include <inttypes.h>
|
||||
+
|
||||
+#include <linux/netfilter/nf_tables.h>
|
||||
+
|
||||
+#include "internal.h"
|
||||
+#include <libmnl/libmnl.h>
|
||||
+#include <libnftnl/expr.h>
|
||||
+#include <libnftnl/rule.h>
|
||||
+
|
||||
+struct nftnl_expr_fullcone {
|
||||
+ uint32_t flags;
|
||||
+ enum nft_registers sreg_proto_min;
|
||||
+ enum nft_registers sreg_proto_max;
|
||||
+};
|
||||
+
|
||||
+static int
|
||||
+nftnl_expr_fullcone_set(struct nftnl_expr *e, uint16_t type,
|
||||
+ const void *data, uint32_t data_len)
|
||||
+{
|
||||
+ struct nftnl_expr_fullcone *fullcone = nftnl_expr_data(e);
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case NFTNL_EXPR_FULLCONE_FLAGS:
|
||||
+ memcpy(&fullcone->flags, data, sizeof(fullcone->flags));
|
||||
+ break;
|
||||
+ case NFTNL_EXPR_FULLCONE_REG_PROTO_MIN:
|
||||
+ memcpy(&fullcone->sreg_proto_min, data, sizeof(fullcone->sreg_proto_min));
|
||||
+ break;
|
||||
+ case NFTNL_EXPR_FULLCONE_REG_PROTO_MAX:
|
||||
+ memcpy(&fullcone->sreg_proto_max, data, sizeof(fullcone->sreg_proto_max));
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const void *
|
||||
+nftnl_expr_fullcone_get(const struct nftnl_expr *e, uint16_t type,
|
||||
+ uint32_t *data_len)
|
||||
+{
|
||||
+ struct nftnl_expr_fullcone *fullcone = nftnl_expr_data(e);
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case NFTNL_EXPR_FULLCONE_FLAGS:
|
||||
+ *data_len = sizeof(fullcone->flags);
|
||||
+ return &fullcone->flags;
|
||||
+ case NFTNL_EXPR_FULLCONE_REG_PROTO_MIN:
|
||||
+ *data_len = sizeof(fullcone->sreg_proto_min);
|
||||
+ return &fullcone->sreg_proto_min;
|
||||
+ case NFTNL_EXPR_FULLCONE_REG_PROTO_MAX:
|
||||
+ *data_len = sizeof(fullcone->sreg_proto_max);
|
||||
+ return &fullcone->sreg_proto_max;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int nftnl_expr_fullcone_cb(const struct nlattr *attr, void *data)
|
||||
+{
|
||||
+ const struct nlattr **tb = data;
|
||||
+ int type = mnl_attr_get_type(attr);
|
||||
+
|
||||
+ if (mnl_attr_type_valid(attr, NFTA_FULLCONE_MAX) < 0)
|
||||
+ return MNL_CB_OK;
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case NFTA_FULLCONE_REG_PROTO_MIN:
|
||||
+ case NFTA_FULLCONE_REG_PROTO_MAX:
|
||||
+ case NFTA_FULLCONE_FLAGS:
|
||||
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
|
||||
+ abi_breakage();
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ tb[type] = attr;
|
||||
+ return MNL_CB_OK;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+nftnl_expr_fullcone_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
|
||||
+{
|
||||
+ struct nftnl_expr_fullcone *fullcone = nftnl_expr_data(e);
|
||||
+
|
||||
+ if (e->flags & (1 << NFTNL_EXPR_FULLCONE_FLAGS))
|
||||
+ mnl_attr_put_u32(nlh, NFTA_FULLCONE_FLAGS, htobe32(fullcone->flags));
|
||||
+ if (e->flags & (1 << NFTNL_EXPR_FULLCONE_REG_PROTO_MIN))
|
||||
+ mnl_attr_put_u32(nlh, NFTA_FULLCONE_REG_PROTO_MIN,
|
||||
+ htobe32(fullcone->sreg_proto_min));
|
||||
+ if (e->flags & (1 << NFTNL_EXPR_FULLCONE_REG_PROTO_MAX))
|
||||
+ mnl_attr_put_u32(nlh, NFTA_FULLCONE_REG_PROTO_MAX,
|
||||
+ htobe32(fullcone->sreg_proto_max));
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+nftnl_expr_fullcone_parse(struct nftnl_expr *e, struct nlattr *attr)
|
||||
+{
|
||||
+ struct nftnl_expr_fullcone *fullcone = nftnl_expr_data(e);
|
||||
+ struct nlattr *tb[NFTA_FULLCONE_MAX+1] = {};
|
||||
+
|
||||
+ if (mnl_attr_parse_nested(attr, nftnl_expr_fullcone_cb, tb) < 0)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (tb[NFTA_FULLCONE_FLAGS]) {
|
||||
+ fullcone->flags = be32toh(mnl_attr_get_u32(tb[NFTA_FULLCONE_FLAGS]));
|
||||
+ e->flags |= (1 << NFTNL_EXPR_FULLCONE_FLAGS);
|
||||
+ }
|
||||
+ if (tb[NFTA_FULLCONE_REG_PROTO_MIN]) {
|
||||
+ fullcone->sreg_proto_min =
|
||||
+ be32toh(mnl_attr_get_u32(tb[NFTA_FULLCONE_REG_PROTO_MIN]));
|
||||
+ e->flags |= (1 << NFTNL_EXPR_FULLCONE_REG_PROTO_MIN);
|
||||
+ }
|
||||
+ if (tb[NFTA_FULLCONE_REG_PROTO_MAX]) {
|
||||
+ fullcone->sreg_proto_max =
|
||||
+ be32toh(mnl_attr_get_u32(tb[NFTA_FULLCONE_REG_PROTO_MAX]));
|
||||
+ e->flags |= (1 << NFTNL_EXPR_FULLCONE_REG_PROTO_MAX);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int nftnl_expr_fullcone_snprintf(char *buf, size_t remain,
|
||||
+ uint32_t flags, const struct nftnl_expr *e)
|
||||
+{
|
||||
+ struct nftnl_expr_fullcone *fullcone = nftnl_expr_data(e);
|
||||
+ int offset = 0, ret = 0;
|
||||
+
|
||||
+ if (e->flags & (1 << NFTNL_EXPR_FULLCONE_REG_PROTO_MIN)) {
|
||||
+ ret = snprintf(buf + offset, remain, "proto_min reg %u ",
|
||||
+ fullcone->sreg_proto_min);
|
||||
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
||||
+ }
|
||||
+ if (e->flags & (1 << NFTNL_EXPR_FULLCONE_REG_PROTO_MAX)) {
|
||||
+ ret = snprintf(buf + offset, remain, "proto_max reg %u ",
|
||||
+ fullcone->sreg_proto_max);
|
||||
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
||||
+ }
|
||||
+ if (e->flags & (1 << NFTNL_EXPR_FULLCONE_FLAGS)) {
|
||||
+ ret = snprintf(buf + offset, remain, "flags 0x%x ", fullcone->flags);
|
||||
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
||||
+ }
|
||||
+
|
||||
+ return offset;
|
||||
+}
|
||||
+
|
||||
+struct expr_ops expr_ops_fullcone = {
|
||||
+ .name = "fullcone",
|
||||
+ .alloc_len = sizeof(struct nftnl_expr_fullcone),
|
||||
+ .max_attr = NFTA_FULLCONE_MAX,
|
||||
+ .set = nftnl_expr_fullcone_set,
|
||||
+ .get = nftnl_expr_fullcone_get,
|
||||
+ .parse = nftnl_expr_fullcone_parse,
|
||||
+ .build = nftnl_expr_fullcone_build,
|
||||
+ .output = nftnl_expr_fullcone_snprintf,
|
||||
+};
|
||||
--- a/src/expr_ops.c
|
||||
+++ b/src/expr_ops.c
|
||||
@@ -20,6 +20,7 @@ extern struct expr_ops expr_ops_limit;
|
||||
extern struct expr_ops expr_ops_log;
|
||||
extern struct expr_ops expr_ops_lookup;
|
||||
extern struct expr_ops expr_ops_masq;
|
||||
+extern struct expr_ops expr_ops_fullcone;
|
||||
extern struct expr_ops expr_ops_match;
|
||||
extern struct expr_ops expr_ops_meta;
|
||||
extern struct expr_ops expr_ops_ng;
|
||||
@@ -65,6 +66,7 @@ static struct expr_ops *expr_ops[] = {
|
||||
&expr_ops_log,
|
||||
&expr_ops_lookup,
|
||||
&expr_ops_masq,
|
||||
+ &expr_ops_fullcone,
|
||||
&expr_ops_match,
|
||||
&expr_ops_meta,
|
||||
&expr_ops_ng,
|
||||
@ -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-nat +kmod-nft-fullcone \
|
||||
+nftables-json \
|
||||
+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci
|
||||
EXTRA_DEPENDS:=ucode (>=2022.03.22)
|
||||
@ -47,4 +47,4 @@ endef
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,firewall4))
|
||||
$(eval $(call BuildPackage,firewall4))
|
||||
@ -0,0 +1,215 @@
|
||||
From aa3b56e289fba7425e649a608c333622ffd9c367 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
|
||||
|
||||
defaults.fullcone and defaults.fullcone6 are switches for IPv4 and IPv6
|
||||
respectively, most IPv6 traffic do NOT need this FullCone NAT functionality.
|
||||
|
||||
Renew: ZiMing Mo <msylgj@immortalwrt.org>
|
||||
---
|
||||
root/etc/config/firewall | 2 ++
|
||||
root/usr/share/firewall4/templates/ruleset.uc | 16 ++++++++++++++--
|
||||
.../firewall4/templates/zone-fullcone.uc | 4 ++++
|
||||
root/usr/share/ucode/fw4.uc | 69 ++++++++++++++++++-
|
||||
4 files changed, 89 insertions(+), 4 deletions(-)
|
||||
create mode 100644 root/usr/share/firewall4/templates/zone-fullcone.uc
|
||||
|
||||
--- a/root/etc/config/firewall
|
||||
+++ b/root/etc/config/firewall
|
||||
@@ -5,6 +5,9 @@ config defaults
|
||||
option forward REJECT
|
||||
# Uncomment this line to disable ipv6 rules
|
||||
# option disable_ipv6 1
|
||||
+ option flow_offloading 1
|
||||
+ option fullcone 1
|
||||
+ option fullcone6 0
|
||||
|
||||
config zone
|
||||
option name lan
|
||||
--- a/root/usr/share/firewall4/templates/ruleset.uc
|
||||
+++ b/root/usr/share/firewall4/templates/ruleset.uc
|
||||
@@ -316,6 +316,12 @@ table inet fw4 {
|
||||
{% for (let redirect in fw4.redirects(`dstnat_${zone.name}`)): %}
|
||||
{%+ include("redirect.uc", { fw4, redirect }) %}
|
||||
{% endfor %}
|
||||
+{% if (zone.masq && fw4.default_option("fullcone")): %}
|
||||
+ {%+ include("zone-fullcone.uc", { fw4, zone, family: 4, direction: "dstnat" }) %}
|
||||
+{% endif %}
|
||||
+{% if (zone.masq6 && fw4.default_option("fullcone6")): %}
|
||||
+ {%+ include("zone-fullcone.uc", { fw4, zone, family: 6, direction: "dstnat" }) %}
|
||||
+{% endif %}
|
||||
{% fw4.includes('chain-append', `dstnat_${zone.name}`) %}
|
||||
}
|
||||
|
||||
@@ -326,20 +326,26 @@ table inet fw4 {
|
||||
{% for (let redirect in fw4.redirects(`srcnat_${zone.name}`)): %}
|
||||
{%+ include("redirect.uc", { fw4, redirect }) %}
|
||||
{% endfor %}
|
||||
-{% if (zone.masq): %}
|
||||
+{% if (zone.masq && !fw4.default_option("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 && !fw4.default_option("fullcone6")): %}
|
||||
{% 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.masq && fw4.default_option("fullcone")): %}
|
||||
+ {%+ include("zone-fullcone.uc", { fw4, zone, family: 4, direction: "srcnat" }) %}
|
||||
+{% endif %}
|
||||
+{% if (zone.masq6 && fw4.default_option("fullcone6")): %}
|
||||
+ {%+ include("zone-fullcone.uc", { fw4, zone, family: 6, direction: "srcnat" }) %}
|
||||
+{% endif %}
|
||||
{% fw4.includes('chain-append', `srcnat_${zone.name}`) %}
|
||||
}
|
||||
|
||||
--- /dev/null
|
||||
+++ b/root/usr/share/firewall4/templates/zone-fullcone.uc
|
||||
@@ -0,0 +1,4 @@
|
||||
+{# /usr/share/firewall4/templates/zone-fullcone.uc #}
|
||||
+ meta nfproto {{ fw4.nfproto(family) }} fullcone comment "!fw4: Handle {{
|
||||
+ zone.name
|
||||
+}} {{ fw4.nfproto(family, true) }} fullcone NAT {{ direction }} traffic"
|
||||
--- a/root/usr/share/ucode/fw4.uc
|
||||
+++ b/root/usr/share/ucode/fw4.uc
|
||||
@@ -1,3 +1,5 @@
|
||||
+// /usr/share/ucode/fw4.uc
|
||||
+
|
||||
const fs = require("fs");
|
||||
const uci = require("uci");
|
||||
const ubus = require("ubus");
|
||||
@@ -428,6 +430,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() {
|
||||
@@ -778,6 +799,18 @@ return {
|
||||
warn(`[!] ${msg}\n`);
|
||||
},
|
||||
|
||||
+ myinfo: function(fmt, ...args) {
|
||||
+ if (getenv("QUIET"))
|
||||
+ return;
|
||||
+
|
||||
+ let msg = sprintf(fmt, ...args);
|
||||
+
|
||||
+ if (getenv("TTY"))
|
||||
+ warn(`\033[32m${msg}\033[m\n`);
|
||||
+ else
|
||||
+ warn(`[I] ${msg}\n`);
|
||||
+ },
|
||||
+
|
||||
get: function(sid, opt) {
|
||||
return this.cursor.get("firewall", sid, opt);
|
||||
},
|
||||
@@ -959,6 +992,21 @@ return {
|
||||
}
|
||||
},
|
||||
|
||||
+ myinfo_section: function(s, msg) {
|
||||
+ if (s[".name"]) {
|
||||
+ if (s.name)
|
||||
+ this.myinfo("Section %s (%s) %s", this.section_id(s[".name"]), s.name, msg);
|
||||
+ else
|
||||
+ this.myinfo("Section %s %s", this.section_id(s[".name"]), msg);
|
||||
+ }
|
||||
+ else {
|
||||
+ if (s.name)
|
||||
+ this.myinfo("ubus %s (%s) %s", s.type || "rule", s.name, msg);
|
||||
+ else
|
||||
+ this.myinfo("ubus %s %s", s.type || "rule", msg);
|
||||
+ }
|
||||
+ },
|
||||
+
|
||||
parse_policy: function(val) {
|
||||
return this.parse_enum(val, [
|
||||
"accept",
|
||||
@@ -1398,6 +1446,7 @@ return {
|
||||
"dnat",
|
||||
"snat",
|
||||
"masquerade",
|
||||
+ "fullcone",
|
||||
"accept",
|
||||
"reject",
|
||||
"drop"
|
||||
@@ -1865,6 +1914,8 @@ return {
|
||||
}
|
||||
|
||||
let defs = this.parse_options(data, {
|
||||
+ fullcone: [ "bool", "0" ],
|
||||
+ fullcone6: [ "bool", "0" ],
|
||||
input: [ "policy", "drop" ],
|
||||
output: [ "policy", "drop" ],
|
||||
forward: [ "policy", "drop" ],
|
||||
@@ -1899,6 +1950,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;
|
||||
},
|
||||
|
||||
@@ -2124,10 +2180,23 @@ return {
|
||||
zone.related_subnets = related_subnets;
|
||||
zone.related_physdevs = related_physdevs;
|
||||
|
||||
- if (zone.masq || zone.masq6)
|
||||
+ if (zone.masq) {
|
||||
zone.dflags.snat = true;
|
||||
+ if (this.state.defaults.fullcone) {
|
||||
+ zone.dflags.dnat = true;
|
||||
+ this.myinfo_section(data, "IPv4 fullcone enabled for zone '" + zone.name + "'");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (zone.masq6) {
|
||||
+ zone.dflags.snat = true;
|
||||
+ if (this.state.defaults.fullcone6) {
|
||||
+ zone.dflags.dnat = true;
|
||||
+ this.myinfo_section(data, "IPv6 fullcone enabled for zone '" + zone.name + "'");
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- if ((zone.auto_helper && !(zone.masq || zone.masq6)) || length(zone.helper)) {
|
||||
+ if ((zone.auto_helper && !(zone.masq || zone.masq6 || this.state.defaults.fullcone || this.state.defaults.fullcone6)) || length(zone.helper)) {
|
||||
zone.dflags.helper = true;
|
||||
|
||||
for (let helper in (length(zone.helper) ? zone.helper : this.state.helpers)) {
|
||||
50
package/network/utils/fullconenat-nft/Makefile
Normal file
50
package/network/utils/fullconenat-nft/Makefile
Normal file
@ -0,0 +1,50 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2018 Chion Tang <tech@chionlab.moe>
|
||||
# Original xt_FULLCONENAT and related iptables extension author
|
||||
# Copyright (c) 2019-2022 GitHub/llccd Twitter/@gNodeB
|
||||
# Added IPv6 support for xt_FULLCONENAT and ip6tables extension
|
||||
# Ported to recent kernel versions
|
||||
# Copyright (c) 2022 Syrone Wong <wong.syrone@gmail.com>
|
||||
# Massively rewrite the whole module, split the original code into library and nftables 'fullcone' expression module
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=fullconenat-nft
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/fullcone-nat-nftables/nft-fullcone.git
|
||||
PKG_SOURCE_DATE:=2023-05-17
|
||||
PKG_SOURCE_VERSION:=07d93b626ce5ea885cd16f9ab07fac3213c355d9
|
||||
PKG_MIRROR_HASH:=84d54b5e6091148c31d4eddff2f8ead763c9ef318fdf35098a6f9cea9a29b7c8
|
||||
|
||||
PKG_LICENSE:=GPL-2.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
PKG_MAINTAINER:=Syrone Wong <wong.syrone@gmail.com>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define KernelPackage/nft-fullcone
|
||||
SUBMENU:=Netfilter Extensions
|
||||
DEPENDS:=+kmod-nft-nat
|
||||
TITLE:=nftables fullcone expression support
|
||||
FILES:= $(PKG_BUILD_DIR)/src/nft_fullcone.ko
|
||||
KCONFIG:= \
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y \
|
||||
CONFIG_NF_CONNTRACK_CHAIN_EVENTS=n
|
||||
AUTOLOAD:=$(call AutoProbe,nft_fullcone)
|
||||
endef
|
||||
|
||||
define KernelPackage/nft-fullcone/Description
|
||||
Kernel module adds the fullcone expression that you can use
|
||||
to perform NAT in the RFC3489-compatible full cone SNAT flavour.
|
||||
Currently only UDP traffic is supported for full-cone NAT.
|
||||
For other protos FULLCONENAT is equivalent to MASQUERADE.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
+$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)/src" modules
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,nft-fullcone))
|
||||
@ -0,0 +1,208 @@
|
||||
From 58c89e8768711a959fdc6e953df3ea2254ff93c1 Mon Sep 17 00:00:00 2001
|
||||
From: Syrone Wong <wong.syrone@gmail.com>
|
||||
Date: Sat, 9 Apr 2022 00:38:51 +0800
|
||||
Subject: [PATCH] nftables: add fullcone expression support
|
||||
|
||||
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
|
||||
---
|
||||
include/linux/netfilter/nf_tables.h | 16 ++++++++++
|
||||
include/statement.h | 1 +
|
||||
src/netlink_delinearize.c | 48 +++++++++++++++++++++++++++++
|
||||
src/netlink_linearize.c | 7 +++++
|
||||
src/parser_bison.y | 28 +++++++++++++++--
|
||||
src/scanner.l | 1 +
|
||||
src/statement.c | 1 +
|
||||
7 files changed, 100 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/include/linux/netfilter/nf_tables.h
|
||||
+++ b/include/linux/netfilter/nf_tables.h
|
||||
@@ -1485,6 +1485,22 @@ enum nft_masq_attributes {
|
||||
#define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1)
|
||||
|
||||
/**
|
||||
+ * enum nft_fullcone_attributes - nf_tables fullcone expression attributes
|
||||
+ *
|
||||
+ * @NFTA_FULLCONE_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
|
||||
+ * @NFTA_FULLCONE_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
|
||||
+ * @NFTA_FULLCONE_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
|
||||
+ */
|
||||
+enum nft_fullcone_attributes {
|
||||
+ NFTA_FULLCONE_UNSPEC,
|
||||
+ NFTA_FULLCONE_FLAGS,
|
||||
+ NFTA_FULLCONE_REG_PROTO_MIN,
|
||||
+ NFTA_FULLCONE_REG_PROTO_MAX,
|
||||
+ __NFTA_FULLCONE_MAX
|
||||
+};
|
||||
+#define NFTA_FULLCONE_MAX (__NFTA_FULLCONE_MAX - 1)
|
||||
+
|
||||
+/**
|
||||
* enum nft_redir_attributes - nf_tables redirect expression netlink attributes
|
||||
*
|
||||
* @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
|
||||
--- a/include/statement.h
|
||||
+++ b/include/statement.h
|
||||
@@ -129,6 +129,7 @@ enum nft_nat_etypes {
|
||||
__NFT_NAT_SNAT = NFT_NAT_SNAT,
|
||||
__NFT_NAT_DNAT = NFT_NAT_DNAT,
|
||||
NFT_NAT_MASQ,
|
||||
+ NFT_NAT_FULLCONE,
|
||||
NFT_NAT_REDIR,
|
||||
};
|
||||
|
||||
--- a/src/netlink_delinearize.c
|
||||
+++ b/src/netlink_delinearize.c
|
||||
@@ -1473,6 +1473,53 @@ out_err:
|
||||
stmt_free(stmt);
|
||||
}
|
||||
|
||||
+static void netlink_parse_fullcone(struct netlink_parse_ctx *ctx,
|
||||
+ const struct location *loc,
|
||||
+ const struct nftnl_expr *nle)
|
||||
+{
|
||||
+ enum nft_registers reg1, reg2;
|
||||
+ struct expr *proto;
|
||||
+ struct stmt *stmt;
|
||||
+ uint32_t flags = 0;
|
||||
+
|
||||
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_FULLCONE_FLAGS))
|
||||
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_FULLCONE_FLAGS);
|
||||
+
|
||||
+ stmt = nat_stmt_alloc(loc, NFT_NAT_FULLCONE);
|
||||
+ stmt->nat.flags = flags;
|
||||
+
|
||||
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_FULLCONE_REG_PROTO_MIN);
|
||||
+ if (reg1) {
|
||||
+ proto = netlink_get_register(ctx, loc, reg1);
|
||||
+ if (proto == NULL) {
|
||||
+ netlink_error(ctx, loc,
|
||||
+ "fullcone statement has no proto expression");
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
|
||||
+ stmt->nat.proto = proto;
|
||||
+ }
|
||||
+
|
||||
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_FULLCONE_REG_PROTO_MAX);
|
||||
+ if (reg2 && reg2 != reg1) {
|
||||
+ proto = netlink_get_register(ctx, loc, reg2);
|
||||
+ if (proto == NULL) {
|
||||
+ netlink_error(ctx, loc,
|
||||
+ "fullcone statement has no proto expression");
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
|
||||
+ if (stmt->nat.proto != NULL)
|
||||
+ proto = range_expr_alloc(loc, stmt->nat.proto, proto);
|
||||
+ stmt->nat.proto = proto;
|
||||
+ }
|
||||
+
|
||||
+ ctx->stmt = stmt;
|
||||
+ return;
|
||||
+out_err:
|
||||
+ stmt_free(stmt);
|
||||
+}
|
||||
+
|
||||
static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
|
||||
const struct location *loc,
|
||||
const struct nftnl_expr *nle)
|
||||
@@ -1901,6 +1948,7 @@ static const struct expr_handler netlink
|
||||
{ .name = "tproxy", .parse = netlink_parse_tproxy },
|
||||
{ .name = "notrack", .parse = netlink_parse_notrack },
|
||||
{ .name = "masq", .parse = netlink_parse_masq },
|
||||
+ { .name = "fullcone", .parse = netlink_parse_fullcone },
|
||||
{ .name = "redir", .parse = netlink_parse_redir },
|
||||
{ .name = "dup", .parse = netlink_parse_dup },
|
||||
{ .name = "queue", .parse = netlink_parse_queue },
|
||||
--- a/src/netlink_linearize.c
|
||||
+++ b/src/netlink_linearize.c
|
||||
@@ -1221,6 +1221,13 @@ static void netlink_gen_nat_stmt(struct
|
||||
nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN;
|
||||
nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX;
|
||||
break;
|
||||
+ case NFT_NAT_FULLCONE:
|
||||
+ nle = alloc_nft_expr("fullcone");
|
||||
+
|
||||
+ nftnl_flag_attr = NFTNL_EXPR_FULLCONE_FLAGS;
|
||||
+ nftnl_reg_pmin = NFTNL_EXPR_FULLCONE_REG_PROTO_MIN;
|
||||
+ nftnl_reg_pmax = NFTNL_EXPR_FULLCONE_REG_PROTO_MAX;
|
||||
+ break;
|
||||
case NFT_NAT_REDIR:
|
||||
nle = alloc_nft_expr("redir");
|
||||
|
||||
--- a/src/parser_bison.y
|
||||
+++ b/src/parser_bison.y
|
||||
@@ -621,6 +621,7 @@ int nft_lex(void *, void *, void *);
|
||||
%token SNAT "snat"
|
||||
%token DNAT "dnat"
|
||||
%token MASQUERADE "masquerade"
|
||||
+%token FULLCONE "fullcone"
|
||||
%token REDIRECT "redirect"
|
||||
%token RANDOM "random"
|
||||
%token FULLY_RANDOM "fully-random"
|
||||
@@ -755,8 +756,8 @@ int nft_lex(void *, void *, void *);
|
||||
%type <val> limit_burst_pkts limit_burst_bytes limit_mode limit_bytes time_unit quota_mode
|
||||
%type <stmt> reject_stmt reject_stmt_alloc
|
||||
%destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
|
||||
-%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
|
||||
-%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
|
||||
+%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc fullcone_stmt fullcone_stmt_alloc redir_stmt redir_stmt_alloc
|
||||
+%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc fullcone_stmt fullcone_stmt_alloc redir_stmt redir_stmt_alloc
|
||||
%type <val> nf_nat_flags nf_nat_flag offset_opt
|
||||
%type <stmt> tproxy_stmt
|
||||
%destructor { stmt_free($$); } tproxy_stmt
|
||||
@@ -3064,6 +3065,7 @@ stmt : verdict_stmt
|
||||
| queue_stmt
|
||||
| ct_stmt
|
||||
| masq_stmt close_scope_nat
|
||||
+ | fullcone_stmt close_scope_nat
|
||||
| redir_stmt close_scope_nat
|
||||
| dup_stmt close_scope_dup
|
||||
| fwd_stmt close_scope_fwd
|
||||
@@ -3976,6 +3978,28 @@ masq_stmt_args : TO COLON stmt_expr
|
||||
{
|
||||
$<stmt>0->nat.proto = $3;
|
||||
}
|
||||
+ | TO COLON stmt_expr nf_nat_flags
|
||||
+ {
|
||||
+ $<stmt>0->nat.proto = $3;
|
||||
+ $<stmt>0->nat.flags = $4;
|
||||
+ }
|
||||
+ | nf_nat_flags
|
||||
+ {
|
||||
+ $<stmt>0->nat.flags = $1;
|
||||
+ }
|
||||
+ ;
|
||||
+
|
||||
+fullcone_stmt : fullcone_stmt_alloc fullcone_stmt_args
|
||||
+ | fullcone_stmt_alloc
|
||||
+ ;
|
||||
+
|
||||
+fullcone_stmt_alloc : FULLCONE { $$ = nat_stmt_alloc(&@$, NFT_NAT_FULLCONE); }
|
||||
+ ;
|
||||
+
|
||||
+fullcone_stmt_args : TO COLON stmt_expr
|
||||
+ {
|
||||
+ $<stmt>0->nat.proto = $3;
|
||||
+ }
|
||||
| TO COLON stmt_expr nf_nat_flags
|
||||
{
|
||||
$<stmt>0->nat.proto = $3;
|
||||
--- a/src/scanner.l
|
||||
+++ b/src/scanner.l
|
||||
@@ -460,6 +460,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr
|
||||
"snat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; }
|
||||
"dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; }
|
||||
"masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; }
|
||||
+"fullcone" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return FULLCONE; }
|
||||
"redirect" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return REDIRECT; }
|
||||
"random" { return RANDOM; }
|
||||
<SCANSTATE_STMT_NAT>{
|
||||
--- a/src/statement.c
|
||||
+++ b/src/statement.c
|
||||
@@ -681,6 +681,7 @@ const char *nat_etype2str(enum nft_nat_e
|
||||
[NFT_NAT_SNAT] = "snat",
|
||||
[NFT_NAT_DNAT] = "dnat",
|
||||
[NFT_NAT_MASQ] = "masquerade",
|
||||
+ [NFT_NAT_FULLCONE] = "fullcone",
|
||||
[NFT_NAT_REDIR] = "redirect",
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user