OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From: Florian Westphal <fw@strlen.de> |
2 | Date: Fri, 8 Dec 2017 17:01:54 +0100 |
||
3 | Subject: [PATCH] netfilter: core: only allow one nat hook per hook point |
||
4 | |||
5 | The netfilter NAT core cannot deal with more than one NAT hook per hook |
||
6 | location (prerouting, input ...), because the NAT hooks install a NAT null |
||
7 | binding in case the iptables nat table (iptable_nat hooks) or the |
||
8 | corresponding nftables chain (nft nat hooks) doesn't specify a nat |
||
9 | transformation. |
||
10 | |||
11 | Null bindings are needed to detect port collsisions between NAT-ed and |
||
12 | non-NAT-ed connections. |
||
13 | |||
14 | This causes nftables NAT rules to not work when iptable_nat module is |
||
15 | loaded, and vice versa because nat binding has already been attached |
||
16 | when the second nat hook is consulted. |
||
17 | |||
18 | The netfilter core is not really the correct location to handle this |
||
19 | (hooks are just hooks, the core has no notion of what kinds of side |
||
20 | effects a hook implements), but its the only place where we can check |
||
21 | for conflicts between both iptables hooks and nftables hooks without |
||
22 | adding dependencies. |
||
23 | |||
24 | So add nat annotation to hook_ops to describe those hooks that will |
||
25 | add NAT bindings and then make core reject if such a hook already exists. |
||
26 | The annotation fills a padding hole, in case further restrictions appar |
||
27 | we might change this to a 'u8 type' instead of bool. |
||
28 | |||
29 | iptables error if nft nat hook active: |
||
30 | iptables -t nat -A POSTROUTING -j MASQUERADE |
||
31 | iptables v1.4.21: can't initialize iptables table `nat': File exists |
||
32 | Perhaps iptables or your kernel needs to be upgraded. |
||
33 | |||
34 | nftables error if iptables nat table present: |
||
35 | nft -f /etc/nftables/ipv4-nat |
||
36 | /usr/etc/nftables/ipv4-nat:3:1-2: Error: Could not process rule: File exists |
||
37 | table nat { |
||
38 | ^^ |
||
39 | |||
40 | Signed-off-by: Florian Westphal <fw@strlen.de> |
||
41 | Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> |
||
42 | --- |
||
43 | |||
44 | --- a/include/linux/netfilter.h |
||
45 | +++ b/include/linux/netfilter.h |
||
46 | @@ -67,6 +67,7 @@ struct nf_hook_ops { |
||
47 | struct net_device *dev; |
||
48 | void *priv; |
||
49 | u_int8_t pf; |
||
50 | + bool nat_hook; |
||
51 | unsigned int hooknum; |
||
52 | /* Hooks are ordered in ascending priority. */ |
||
53 | int priority; |
||
54 | --- a/net/ipv4/netfilter/iptable_nat.c |
||
55 | +++ b/net/ipv4/netfilter/iptable_nat.c |
||
56 | @@ -72,6 +72,7 @@ static const struct nf_hook_ops nf_nat_i |
||
57 | { |
||
58 | .hook = iptable_nat_ipv4_in, |
||
59 | .pf = NFPROTO_IPV4, |
||
60 | + .nat_hook = true, |
||
61 | .hooknum = NF_INET_PRE_ROUTING, |
||
62 | .priority = NF_IP_PRI_NAT_DST, |
||
63 | }, |
||
64 | @@ -79,6 +80,7 @@ static const struct nf_hook_ops nf_nat_i |
||
65 | { |
||
66 | .hook = iptable_nat_ipv4_out, |
||
67 | .pf = NFPROTO_IPV4, |
||
68 | + .nat_hook = true, |
||
69 | .hooknum = NF_INET_POST_ROUTING, |
||
70 | .priority = NF_IP_PRI_NAT_SRC, |
||
71 | }, |
||
72 | @@ -86,6 +88,7 @@ static const struct nf_hook_ops nf_nat_i |
||
73 | { |
||
74 | .hook = iptable_nat_ipv4_local_fn, |
||
75 | .pf = NFPROTO_IPV4, |
||
76 | + .nat_hook = true, |
||
77 | .hooknum = NF_INET_LOCAL_OUT, |
||
78 | .priority = NF_IP_PRI_NAT_DST, |
||
79 | }, |
||
80 | @@ -93,6 +96,7 @@ static const struct nf_hook_ops nf_nat_i |
||
81 | { |
||
82 | .hook = iptable_nat_ipv4_fn, |
||
83 | .pf = NFPROTO_IPV4, |
||
84 | + .nat_hook = true, |
||
85 | .hooknum = NF_INET_LOCAL_IN, |
||
86 | .priority = NF_IP_PRI_NAT_SRC, |
||
87 | }, |
||
88 | --- a/net/ipv6/netfilter/ip6table_nat.c |
||
89 | +++ b/net/ipv6/netfilter/ip6table_nat.c |
||
90 | @@ -74,6 +74,7 @@ static const struct nf_hook_ops nf_nat_i |
||
91 | { |
||
92 | .hook = ip6table_nat_in, |
||
93 | .pf = NFPROTO_IPV6, |
||
94 | + .nat_hook = true, |
||
95 | .hooknum = NF_INET_PRE_ROUTING, |
||
96 | .priority = NF_IP6_PRI_NAT_DST, |
||
97 | }, |
||
98 | @@ -81,6 +82,7 @@ static const struct nf_hook_ops nf_nat_i |
||
99 | { |
||
100 | .hook = ip6table_nat_out, |
||
101 | .pf = NFPROTO_IPV6, |
||
102 | + .nat_hook = true, |
||
103 | .hooknum = NF_INET_POST_ROUTING, |
||
104 | .priority = NF_IP6_PRI_NAT_SRC, |
||
105 | }, |
||
106 | @@ -88,12 +90,14 @@ static const struct nf_hook_ops nf_nat_i |
||
107 | { |
||
108 | .hook = ip6table_nat_local_fn, |
||
109 | .pf = NFPROTO_IPV6, |
||
110 | + .nat_hook = true, |
||
111 | .hooknum = NF_INET_LOCAL_OUT, |
||
112 | .priority = NF_IP6_PRI_NAT_DST, |
||
113 | }, |
||
114 | /* After packet filtering, change source */ |
||
115 | { |
||
116 | .hook = ip6table_nat_fn, |
||
117 | + .nat_hook = true, |
||
118 | .pf = NFPROTO_IPV6, |
||
119 | .hooknum = NF_INET_LOCAL_IN, |
||
120 | .priority = NF_IP6_PRI_NAT_SRC, |
||
121 | --- a/net/netfilter/core.c |
||
122 | +++ b/net/netfilter/core.c |
||
3 | office | 123 | @@ -135,6 +135,12 @@ nf_hook_entries_grow(const struct nf_hoo |
1 | office | 124 | ++i; |
125 | continue; |
||
126 | } |
||
127 | + |
||
128 | + if (reg->nat_hook && orig_ops[i]->nat_hook) { |
||
129 | + kvfree(new); |
||
130 | + return ERR_PTR(-EEXIST); |
||
131 | + } |
||
132 | + |
||
133 | if (inserted || reg->priority > orig_ops[i]->priority) { |
||
134 | new_ops[nhooks] = (void *)orig_ops[i]; |
||
135 | new->hooks[nhooks] = old->hooks[i]; |
||
136 | --- a/net/netfilter/nf_tables_api.c |
||
137 | +++ b/net/netfilter/nf_tables_api.c |
||
138 | @@ -1431,6 +1431,8 @@ static int nf_tables_addchain(struct nft |
||
139 | ops->hook = hookfn; |
||
140 | if (afi->hook_ops_init) |
||
141 | afi->hook_ops_init(ops, i); |
||
142 | + if (basechain->type->type == NFT_CHAIN_T_NAT) |
||
143 | + ops->nat_hook = true; |
||
144 | } |
||
145 | |||
146 | chain->flags |= NFT_BASE_CHAIN; |