diff options
Diffstat (limited to 'target/linux/generic/backport-4.19/301-v4.16-netfilter-core-only-allow-one-nat-hook-per-hook-poin.patch')
-rw-r--r-- | target/linux/generic/backport-4.19/301-v4.16-netfilter-core-only-allow-one-nat-hook-per-hook-poin.patch | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/target/linux/generic/backport-4.19/301-v4.16-netfilter-core-only-allow-one-nat-hook-per-hook-poin.patch b/target/linux/generic/backport-4.19/301-v4.16-netfilter-core-only-allow-one-nat-hook-per-hook-poin.patch new file mode 100644 index 0000000000..05888a070e --- /dev/null +++ b/target/linux/generic/backport-4.19/301-v4.16-netfilter-core-only-allow-one-nat-hook-per-hook-poin.patch @@ -0,0 +1,146 @@ +From: Florian Westphal <fw@strlen.de> +Date: Fri, 8 Dec 2017 17:01:54 +0100 +Subject: [PATCH] netfilter: core: only allow one nat hook per hook point + +The netfilter NAT core cannot deal with more than one NAT hook per hook +location (prerouting, input ...), because the NAT hooks install a NAT null +binding in case the iptables nat table (iptable_nat hooks) or the +corresponding nftables chain (nft nat hooks) doesn't specify a nat +transformation. + +Null bindings are needed to detect port collsisions between NAT-ed and +non-NAT-ed connections. + +This causes nftables NAT rules to not work when iptable_nat module is +loaded, and vice versa because nat binding has already been attached +when the second nat hook is consulted. + +The netfilter core is not really the correct location to handle this +(hooks are just hooks, the core has no notion of what kinds of side + effects a hook implements), but its the only place where we can check +for conflicts between both iptables hooks and nftables hooks without +adding dependencies. + +So add nat annotation to hook_ops to describe those hooks that will +add NAT bindings and then make core reject if such a hook already exists. +The annotation fills a padding hole, in case further restrictions appar +we might change this to a 'u8 type' instead of bool. + +iptables error if nft nat hook active: +iptables -t nat -A POSTROUTING -j MASQUERADE +iptables v1.4.21: can't initialize iptables table `nat': File exists +Perhaps iptables or your kernel needs to be upgraded. + +nftables error if iptables nat table present: +nft -f /etc/nftables/ipv4-nat +/usr/etc/nftables/ipv4-nat:3:1-2: Error: Could not process rule: File exists +table nat { +^^ + +Signed-off-by: Florian Westphal <fw@strlen.de> +Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> +--- + +--- a/include/linux/netfilter.h ++++ b/include/linux/netfilter.h +@@ -67,6 +67,7 @@ struct nf_hook_ops { + struct net_device *dev; + void *priv; + u_int8_t pf; ++ bool nat_hook; + unsigned int hooknum; + /* Hooks are ordered in ascending priority. */ + int priority; +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -72,6 +72,7 @@ static const struct nf_hook_ops nf_nat_i + { + .hook = iptable_nat_ipv4_in, + .pf = NFPROTO_IPV4, ++ .nat_hook = true, + .hooknum = NF_INET_PRE_ROUTING, + .priority = NF_IP_PRI_NAT_DST, + }, +@@ -79,6 +80,7 @@ static const struct nf_hook_ops nf_nat_i + { + .hook = iptable_nat_ipv4_out, + .pf = NFPROTO_IPV4, ++ .nat_hook = true, + .hooknum = NF_INET_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SRC, + }, +@@ -86,6 +88,7 @@ static const struct nf_hook_ops nf_nat_i + { + .hook = iptable_nat_ipv4_local_fn, + .pf = NFPROTO_IPV4, ++ .nat_hook = true, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP_PRI_NAT_DST, + }, +@@ -93,6 +96,7 @@ static const struct nf_hook_ops nf_nat_i + { + .hook = iptable_nat_ipv4_fn, + .pf = NFPROTO_IPV4, ++ .nat_hook = true, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SRC, + }, +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -74,6 +74,7 @@ static const struct nf_hook_ops nf_nat_i + { + .hook = ip6table_nat_in, + .pf = NFPROTO_IPV6, ++ .nat_hook = true, + .hooknum = NF_INET_PRE_ROUTING, + .priority = NF_IP6_PRI_NAT_DST, + }, +@@ -81,6 +82,7 @@ static const struct nf_hook_ops nf_nat_i + { + .hook = ip6table_nat_out, + .pf = NFPROTO_IPV6, ++ .nat_hook = true, + .hooknum = NF_INET_POST_ROUTING, + .priority = NF_IP6_PRI_NAT_SRC, + }, +@@ -88,12 +90,14 @@ static const struct nf_hook_ops nf_nat_i + { + .hook = ip6table_nat_local_fn, + .pf = NFPROTO_IPV6, ++ .nat_hook = true, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP6_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = ip6table_nat_fn, ++ .nat_hook = true, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP6_PRI_NAT_SRC, +--- a/net/netfilter/core.c ++++ b/net/netfilter/core.c +@@ -160,6 +160,12 @@ nf_hook_entries_grow(const struct nf_hoo + ++i; + continue; + } ++ ++ if (reg->nat_hook && orig_ops[i]->nat_hook) { ++ kvfree(new); ++ return ERR_PTR(-EEXIST); ++ } ++ + if (inserted || reg->priority > orig_ops[i]->priority) { + new_ops[nhooks] = (void *)orig_ops[i]; + new->hooks[nhooks] = old->hooks[i]; +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -1431,6 +1431,8 @@ static int nf_tables_addchain(struct nft + ops->hook = hookfn; + if (afi->hook_ops_init) + afi->hook_ops_init(ops, i); ++ if (basechain->type->type == NFT_CHAIN_T_NAT) ++ ops->nat_hook = true; + } + + chain->flags |= NFT_BASE_CHAIN; |