Commit 5d0aa2ccd4699a01cfdf14886191c249d7b45a01
1 parent
8fea97ec17
netfilter: nf_conntrack: add support for "conntrack zones"
Normally, each connection needs a unique identity. Conntrack zones allow to specify a numerical zone using the CT target, connections in different zones can use the same identity. Example: iptables -t raw -A PREROUTING -i veth0 -j CT --zone 1 iptables -t raw -A OUTPUT -o veth1 -j CT --zone 1 Signed-off-by: Patrick McHardy <kaber@trash.net>
Showing 25 changed files with 236 additions and 85 deletions Side-by-side Diff
- include/linux/netfilter/xt_CT.h
- include/net/ip.h
- include/net/ipv6.h
- include/net/netfilter/nf_conntrack.h
- include/net/netfilter/nf_conntrack_core.h
- include/net/netfilter/nf_conntrack_expect.h
- include/net/netfilter/nf_conntrack_extend.h
- include/net/netfilter/nf_conntrack_zones.h
- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
- net/ipv4/netfilter/nf_conntrack_proto_icmp.c
- net/ipv4/netfilter/nf_defrag_ipv4.c
- net/ipv4/netfilter/nf_nat_core.c
- net/ipv4/netfilter/nf_nat_pptp.c
- net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
- net/netfilter/Kconfig
- net/netfilter/nf_conntrack_core.c
- net/netfilter/nf_conntrack_expect.c
- net/netfilter/nf_conntrack_h323_main.c
- net/netfilter/nf_conntrack_netlink.c
- net/netfilter/nf_conntrack_pptp.c
- net/netfilter/nf_conntrack_sip.c
- net/netfilter/nf_conntrack_standalone.c
- net/netfilter/xt_CT.c
- net/netfilter/xt_connlimit.c
include/linux/netfilter/xt_CT.h
include/net/ip.h
... | ... | @@ -352,8 +352,11 @@ |
352 | 352 | IP_DEFRAG_LOCAL_DELIVER, |
353 | 353 | IP_DEFRAG_CALL_RA_CHAIN, |
354 | 354 | IP_DEFRAG_CONNTRACK_IN, |
355 | + __IP_DEFRAG_CONNTRACK_IN_END = IP_DEFRAG_CONNTRACK_IN + USHORT_MAX, | |
355 | 356 | IP_DEFRAG_CONNTRACK_OUT, |
357 | + __IP_DEFRAG_CONNTRACK_OUT_END = IP_DEFRAG_CONNTRACK_OUT + USHORT_MAX, | |
356 | 358 | IP_DEFRAG_CONNTRACK_BRIDGE_IN, |
359 | + __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX, | |
357 | 360 | IP_DEFRAG_VS_IN, |
358 | 361 | IP_DEFRAG_VS_OUT, |
359 | 362 | IP_DEFRAG_VS_FWD |
include/net/ipv6.h
... | ... | @@ -355,8 +355,11 @@ |
355 | 355 | enum ip6_defrag_users { |
356 | 356 | IP6_DEFRAG_LOCAL_DELIVER, |
357 | 357 | IP6_DEFRAG_CONNTRACK_IN, |
358 | + __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHORT_MAX, | |
358 | 359 | IP6_DEFRAG_CONNTRACK_OUT, |
360 | + __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHORT_MAX, | |
359 | 361 | IP6_DEFRAG_CONNTRACK_BRIDGE_IN, |
362 | + __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX, | |
360 | 363 | }; |
361 | 364 | |
362 | 365 | struct ip6_create_arg { |
include/net/netfilter/nf_conntrack.h
... | ... | @@ -198,7 +198,8 @@ |
198 | 198 | extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size); |
199 | 199 | |
200 | 200 | extern struct nf_conntrack_tuple_hash * |
201 | -__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); | |
201 | +__nf_conntrack_find(struct net *net, u16 zone, | |
202 | + const struct nf_conntrack_tuple *tuple); | |
202 | 203 | |
203 | 204 | extern void nf_conntrack_hash_insert(struct nf_conn *ct); |
204 | 205 | extern void nf_ct_delete_from_lists(struct nf_conn *ct); |
... | ... | @@ -267,7 +268,7 @@ |
267 | 268 | nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data); |
268 | 269 | extern void nf_conntrack_free(struct nf_conn *ct); |
269 | 270 | extern struct nf_conn * |
270 | -nf_conntrack_alloc(struct net *net, | |
271 | +nf_conntrack_alloc(struct net *net, u16 zone, | |
271 | 272 | const struct nf_conntrack_tuple *orig, |
272 | 273 | const struct nf_conntrack_tuple *repl, |
273 | 274 | gfp_t gfp); |
include/net/netfilter/nf_conntrack_core.h
... | ... | @@ -49,7 +49,8 @@ |
49 | 49 | |
50 | 50 | /* Find a connection corresponding to a tuple. */ |
51 | 51 | extern struct nf_conntrack_tuple_hash * |
52 | -nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple); | |
52 | +nf_conntrack_find_get(struct net *net, u16 zone, | |
53 | + const struct nf_conntrack_tuple *tuple); | |
53 | 54 | |
54 | 55 | extern int __nf_conntrack_confirm(struct sk_buff *skb); |
55 | 56 |
include/net/netfilter/nf_conntrack_expect.h
... | ... | @@ -74,13 +74,16 @@ |
74 | 74 | void nf_conntrack_expect_fini(struct net *net); |
75 | 75 | |
76 | 76 | struct nf_conntrack_expect * |
77 | -__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple); | |
77 | +__nf_ct_expect_find(struct net *net, u16 zone, | |
78 | + const struct nf_conntrack_tuple *tuple); | |
78 | 79 | |
79 | 80 | struct nf_conntrack_expect * |
80 | -nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple); | |
81 | +nf_ct_expect_find_get(struct net *net, u16 zone, | |
82 | + const struct nf_conntrack_tuple *tuple); | |
81 | 83 | |
82 | 84 | struct nf_conntrack_expect * |
83 | -nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple); | |
85 | +nf_ct_find_expectation(struct net *net, u16 zone, | |
86 | + const struct nf_conntrack_tuple *tuple); | |
84 | 87 | |
85 | 88 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); |
86 | 89 | void nf_ct_remove_expectations(struct nf_conn *ct); |
include/net/netfilter/nf_conntrack_extend.h
... | ... | @@ -8,6 +8,7 @@ |
8 | 8 | NF_CT_EXT_NAT, |
9 | 9 | NF_CT_EXT_ACCT, |
10 | 10 | NF_CT_EXT_ECACHE, |
11 | + NF_CT_EXT_ZONE, | |
11 | 12 | NF_CT_EXT_NUM, |
12 | 13 | }; |
13 | 14 | |
... | ... | @@ -15,6 +16,7 @@ |
15 | 16 | #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat |
16 | 17 | #define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter |
17 | 18 | #define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache |
19 | +#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone | |
18 | 20 | |
19 | 21 | /* Extensions: optional stuff which isn't permanently in struct. */ |
20 | 22 | struct nf_ct_ext { |
include/net/netfilter/nf_conntrack_zones.h
1 | +#ifndef _NF_CONNTRACK_ZONES_H | |
2 | +#define _NF_CONNTRACK_ZONES_H | |
3 | + | |
4 | +#include <net/netfilter/nf_conntrack_extend.h> | |
5 | + | |
6 | +#define NF_CT_DEFAULT_ZONE 0 | |
7 | + | |
8 | +struct nf_conntrack_zone { | |
9 | + u16 id; | |
10 | +}; | |
11 | + | |
12 | +static inline u16 nf_ct_zone(const struct nf_conn *ct) | |
13 | +{ | |
14 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
15 | + struct nf_conntrack_zone *nf_ct_zone; | |
16 | + nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE); | |
17 | + if (nf_ct_zone) | |
18 | + return nf_ct_zone->id; | |
19 | +#endif | |
20 | + return NF_CT_DEFAULT_ZONE; | |
21 | +} | |
22 | + | |
23 | +#endif /* _NF_CONNTRACK_ZONES_H */ |
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | #include <net/netfilter/nf_conntrack_helper.h> |
23 | 23 | #include <net/netfilter/nf_conntrack_l4proto.h> |
24 | 24 | #include <net/netfilter/nf_conntrack_l3proto.h> |
25 | +#include <net/netfilter/nf_conntrack_zones.h> | |
25 | 26 | #include <net/netfilter/nf_conntrack_core.h> |
26 | 27 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
27 | 28 | #include <net/netfilter/nf_nat_helper.h> |
... | ... | @@ -266,7 +267,7 @@ |
266 | 267 | return -EINVAL; |
267 | 268 | } |
268 | 269 | |
269 | - h = nf_conntrack_find_get(sock_net(sk), &tuple); | |
270 | + h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple); | |
270 | 271 | if (h) { |
271 | 272 | struct sockaddr_in sin; |
272 | 273 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); |
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | #include <net/netfilter/nf_conntrack_tuple.h> |
19 | 19 | #include <net/netfilter/nf_conntrack_l4proto.h> |
20 | 20 | #include <net/netfilter/nf_conntrack_core.h> |
21 | +#include <net/netfilter/nf_conntrack_zones.h> | |
21 | 22 | #include <net/netfilter/nf_log.h> |
22 | 23 | |
23 | 24 | static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ; |
24 | 25 | |
... | ... | @@ -114,13 +115,14 @@ |
114 | 115 | |
115 | 116 | /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ |
116 | 117 | static int |
117 | -icmp_error_message(struct net *net, struct sk_buff *skb, | |
118 | +icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, | |
118 | 119 | enum ip_conntrack_info *ctinfo, |
119 | 120 | unsigned int hooknum) |
120 | 121 | { |
121 | 122 | struct nf_conntrack_tuple innertuple, origtuple; |
122 | 123 | const struct nf_conntrack_l4proto *innerproto; |
123 | 124 | const struct nf_conntrack_tuple_hash *h; |
125 | + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; | |
124 | 126 | |
125 | 127 | NF_CT_ASSERT(skb->nfct == NULL); |
126 | 128 | |
... | ... | @@ -146,7 +148,7 @@ |
146 | 148 | |
147 | 149 | *ctinfo = IP_CT_RELATED; |
148 | 150 | |
149 | - h = nf_conntrack_find_get(net, &innertuple); | |
151 | + h = nf_conntrack_find_get(net, zone, &innertuple); | |
150 | 152 | if (!h) { |
151 | 153 | pr_debug("icmp_error_message: no match\n"); |
152 | 154 | return -NF_ACCEPT; |
... | ... | @@ -209,7 +211,7 @@ |
209 | 211 | icmph->type != ICMP_REDIRECT) |
210 | 212 | return NF_ACCEPT; |
211 | 213 | |
212 | - return icmp_error_message(net, skb, ctinfo, hooknum); | |
214 | + return icmp_error_message(net, tmpl, skb, ctinfo, hooknum); | |
213 | 215 | } |
214 | 216 | |
215 | 217 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
net/ipv4/netfilter/nf_defrag_ipv4.c
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | |
17 | 17 | #include <linux/netfilter_bridge.h> |
18 | 18 | #include <linux/netfilter_ipv4.h> |
19 | +#include <net/netfilter/nf_conntrack_zones.h> | |
19 | 20 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
20 | 21 | #include <net/netfilter/nf_conntrack.h> |
21 | 22 | |
22 | 23 | |
23 | 24 | |
24 | 25 | |
... | ... | @@ -39,15 +40,20 @@ |
39 | 40 | static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, |
40 | 41 | struct sk_buff *skb) |
41 | 42 | { |
43 | + u16 zone = NF_CT_DEFAULT_ZONE; | |
44 | + | |
45 | + if (skb->nfct) | |
46 | + zone = nf_ct_zone((struct nf_conn *)skb->nfct); | |
47 | + | |
42 | 48 | #ifdef CONFIG_BRIDGE_NETFILTER |
43 | 49 | if (skb->nf_bridge && |
44 | 50 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) |
45 | - return IP_DEFRAG_CONNTRACK_BRIDGE_IN; | |
51 | + return IP_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | |
46 | 52 | #endif |
47 | 53 | if (hooknum == NF_INET_PRE_ROUTING) |
48 | - return IP_DEFRAG_CONNTRACK_IN; | |
54 | + return IP_DEFRAG_CONNTRACK_IN + zone; | |
49 | 55 | else |
50 | - return IP_DEFRAG_CONNTRACK_OUT; | |
56 | + return IP_DEFRAG_CONNTRACK_OUT + zone; | |
51 | 57 | } |
52 | 58 | |
53 | 59 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, |
net/ipv4/netfilter/nf_nat_core.c
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 | #include <net/netfilter/nf_conntrack_helper.h> |
31 | 31 | #include <net/netfilter/nf_conntrack_l3proto.h> |
32 | 32 | #include <net/netfilter/nf_conntrack_l4proto.h> |
33 | +#include <net/netfilter/nf_conntrack_zones.h> | |
33 | 34 | |
34 | 35 | static DEFINE_SPINLOCK(nf_nat_lock); |
35 | 36 | |
36 | 37 | |
... | ... | @@ -69,13 +70,14 @@ |
69 | 70 | |
70 | 71 | /* We keep an extra hash for each conntrack, for fast searching. */ |
71 | 72 | static inline unsigned int |
72 | -hash_by_src(const struct net *net, const struct nf_conntrack_tuple *tuple) | |
73 | +hash_by_src(const struct net *net, u16 zone, | |
74 | + const struct nf_conntrack_tuple *tuple) | |
73 | 75 | { |
74 | 76 | unsigned int hash; |
75 | 77 | |
76 | 78 | /* Original src, to ensure we map it consistently if poss. */ |
77 | 79 | hash = jhash_3words((__force u32)tuple->src.u3.ip, |
78 | - (__force u32)tuple->src.u.all, | |
80 | + (__force u32)tuple->src.u.all ^ zone, | |
79 | 81 | tuple->dst.protonum, 0); |
80 | 82 | return ((u64)hash * net->ipv4.nat_htable_size) >> 32; |
81 | 83 | } |
82 | 84 | |
... | ... | @@ -139,12 +141,12 @@ |
139 | 141 | |
140 | 142 | /* Only called for SRC manip */ |
141 | 143 | static int |
142 | -find_appropriate_src(struct net *net, | |
144 | +find_appropriate_src(struct net *net, u16 zone, | |
143 | 145 | const struct nf_conntrack_tuple *tuple, |
144 | 146 | struct nf_conntrack_tuple *result, |
145 | 147 | const struct nf_nat_range *range) |
146 | 148 | { |
147 | - unsigned int h = hash_by_src(net, tuple); | |
149 | + unsigned int h = hash_by_src(net, zone, tuple); | |
148 | 150 | const struct nf_conn_nat *nat; |
149 | 151 | const struct nf_conn *ct; |
150 | 152 | const struct hlist_node *n; |
... | ... | @@ -152,7 +154,7 @@ |
152 | 154 | rcu_read_lock(); |
153 | 155 | hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) { |
154 | 156 | ct = nat->ct; |
155 | - if (same_src(ct, tuple)) { | |
157 | + if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) { | |
156 | 158 | /* Copy source part from reply tuple. */ |
157 | 159 | nf_ct_invert_tuplepr(result, |
158 | 160 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); |
... | ... | @@ -175,7 +177,7 @@ |
175 | 177 | the ip with the lowest src-ip/dst-ip/proto usage. |
176 | 178 | */ |
177 | 179 | static void |
178 | -find_best_ips_proto(struct nf_conntrack_tuple *tuple, | |
180 | +find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple, | |
179 | 181 | const struct nf_nat_range *range, |
180 | 182 | const struct nf_conn *ct, |
181 | 183 | enum nf_nat_manip_type maniptype) |
... | ... | @@ -209,7 +211,7 @@ |
209 | 211 | maxip = ntohl(range->max_ip); |
210 | 212 | j = jhash_2words((__force u32)tuple->src.u3.ip, |
211 | 213 | range->flags & IP_NAT_RANGE_PERSISTENT ? |
212 | - 0 : (__force u32)tuple->dst.u3.ip, 0); | |
214 | + 0 : (__force u32)tuple->dst.u3.ip ^ zone, 0); | |
213 | 215 | j = ((u64)j * (maxip - minip + 1)) >> 32; |
214 | 216 | *var_ipp = htonl(minip + j); |
215 | 217 | } |
... | ... | @@ -229,6 +231,7 @@ |
229 | 231 | { |
230 | 232 | struct net *net = nf_ct_net(ct); |
231 | 233 | const struct nf_nat_protocol *proto; |
234 | + u16 zone = nf_ct_zone(ct); | |
232 | 235 | |
233 | 236 | /* 1) If this srcip/proto/src-proto-part is currently mapped, |
234 | 237 | and that same mapping gives a unique tuple within the given |
... | ... | @@ -239,7 +242,7 @@ |
239 | 242 | manips not an issue. */ |
240 | 243 | if (maniptype == IP_NAT_MANIP_SRC && |
241 | 244 | !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) { |
242 | - if (find_appropriate_src(net, orig_tuple, tuple, range)) { | |
245 | + if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) { | |
243 | 246 | pr_debug("get_unique_tuple: Found current src map\n"); |
244 | 247 | if (!nf_nat_used_tuple(tuple, ct)) |
245 | 248 | return; |
... | ... | @@ -249,7 +252,7 @@ |
249 | 252 | /* 2) Select the least-used IP/proto combination in the given |
250 | 253 | range. */ |
251 | 254 | *tuple = *orig_tuple; |
252 | - find_best_ips_proto(tuple, range, ct, maniptype); | |
255 | + find_best_ips_proto(zone, tuple, range, ct, maniptype); | |
253 | 256 | |
254 | 257 | /* 3) The per-protocol part of the manip is made to map into |
255 | 258 | the range to make a unique tuple. */ |
... | ... | @@ -327,7 +330,8 @@ |
327 | 330 | if (have_to_hash) { |
328 | 331 | unsigned int srchash; |
329 | 332 | |
330 | - srchash = hash_by_src(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
333 | + srchash = hash_by_src(net, nf_ct_zone(ct), | |
334 | + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
331 | 335 | spin_lock_bh(&nf_nat_lock); |
332 | 336 | /* nf_conntrack_alter_reply might re-allocate exntension aera */ |
333 | 337 | nat = nfct_nat(ct); |
net/ipv4/netfilter/nf_nat_pptp.c
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | #include <net/netfilter/nf_nat_rule.h> |
26 | 26 | #include <net/netfilter/nf_conntrack_helper.h> |
27 | 27 | #include <net/netfilter/nf_conntrack_expect.h> |
28 | +#include <net/netfilter/nf_conntrack_zones.h> | |
28 | 29 | #include <linux/netfilter/nf_conntrack_proto_gre.h> |
29 | 30 | #include <linux/netfilter/nf_conntrack_pptp.h> |
30 | 31 | |
... | ... | @@ -74,7 +75,7 @@ |
74 | 75 | |
75 | 76 | pr_debug("trying to unexpect other dir: "); |
76 | 77 | nf_ct_dump_tuple_ip(&t); |
77 | - other_exp = nf_ct_expect_find_get(net, &t); | |
78 | + other_exp = nf_ct_expect_find_get(net, nf_ct_zone(ct), &t); | |
78 | 79 | if (other_exp) { |
79 | 80 | nf_ct_unexpect_related(other_exp); |
80 | 81 | nf_ct_expect_put(other_exp); |
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | #include <net/netfilter/nf_conntrack_l4proto.h> |
28 | 28 | #include <net/netfilter/nf_conntrack_l3proto.h> |
29 | 29 | #include <net/netfilter/nf_conntrack_core.h> |
30 | +#include <net/netfilter/nf_conntrack_zones.h> | |
30 | 31 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
31 | 32 | #include <net/netfilter/nf_log.h> |
32 | 33 | |
33 | 34 | |
34 | 35 | |
35 | 36 | |
... | ... | @@ -191,15 +192,20 @@ |
191 | 192 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, |
192 | 193 | struct sk_buff *skb) |
193 | 194 | { |
195 | + u16 zone = NF_CT_DEFAULT_ZONE; | |
196 | + | |
197 | + if (skb->nfct) | |
198 | + zone = nf_ct_zone((struct nf_conn *)skb->nfct); | |
199 | + | |
194 | 200 | #ifdef CONFIG_BRIDGE_NETFILTER |
195 | 201 | if (skb->nf_bridge && |
196 | 202 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) |
197 | - return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; | |
203 | + return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | |
198 | 204 | #endif |
199 | 205 | if (hooknum == NF_INET_PRE_ROUTING) |
200 | - return IP6_DEFRAG_CONNTRACK_IN; | |
206 | + return IP6_DEFRAG_CONNTRACK_IN + zone; | |
201 | 207 | else |
202 | - return IP6_DEFRAG_CONNTRACK_OUT; | |
208 | + return IP6_DEFRAG_CONNTRACK_OUT + zone; | |
203 | 209 | |
204 | 210 | } |
205 | 211 |
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | #include <net/netfilter/nf_conntrack_tuple.h> |
24 | 24 | #include <net/netfilter/nf_conntrack_l4proto.h> |
25 | 25 | #include <net/netfilter/nf_conntrack_core.h> |
26 | +#include <net/netfilter/nf_conntrack_zones.h> | |
26 | 27 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> |
27 | 28 | #include <net/netfilter/nf_log.h> |
28 | 29 | |
... | ... | @@ -128,7 +129,7 @@ |
128 | 129 | } |
129 | 130 | |
130 | 131 | static int |
131 | -icmpv6_error_message(struct net *net, | |
132 | +icmpv6_error_message(struct net *net, struct nf_conn *tmpl, | |
132 | 133 | struct sk_buff *skb, |
133 | 134 | unsigned int icmp6off, |
134 | 135 | enum ip_conntrack_info *ctinfo, |
... | ... | @@ -137,6 +138,7 @@ |
137 | 138 | struct nf_conntrack_tuple intuple, origtuple; |
138 | 139 | const struct nf_conntrack_tuple_hash *h; |
139 | 140 | const struct nf_conntrack_l4proto *inproto; |
141 | + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; | |
140 | 142 | |
141 | 143 | NF_CT_ASSERT(skb->nfct == NULL); |
142 | 144 | |
... | ... | @@ -163,7 +165,7 @@ |
163 | 165 | |
164 | 166 | *ctinfo = IP_CT_RELATED; |
165 | 167 | |
166 | - h = nf_conntrack_find_get(net, &intuple); | |
168 | + h = nf_conntrack_find_get(net, zone, &intuple); | |
167 | 169 | if (!h) { |
168 | 170 | pr_debug("icmpv6_error: no match\n"); |
169 | 171 | return -NF_ACCEPT; |
... | ... | @@ -216,7 +218,7 @@ |
216 | 218 | if (icmp6h->icmp6_type >= 128) |
217 | 219 | return NF_ACCEPT; |
218 | 220 | |
219 | - return icmpv6_error_message(net, skb, dataoff, ctinfo, hooknum); | |
221 | + return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum); | |
220 | 222 | } |
221 | 223 | |
222 | 224 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
net/netfilter/Kconfig
... | ... | @@ -83,6 +83,19 @@ |
83 | 83 | |
84 | 84 | If unsure, say 'N'. |
85 | 85 | |
86 | +config NF_CONNTRACK_ZONES | |
87 | + bool 'Connection tracking zones' | |
88 | + depends on NETFILTER_ADVANCED | |
89 | + depends on NETFILTER_XT_TARGET_CT | |
90 | + help | |
91 | + This option enables support for connection tracking zones. | |
92 | + Normally, each connection needs to have a unique system wide | |
93 | + identity. Connection tracking zones allow to have multiple | |
94 | + connections using the same identity, as long as they are | |
95 | + contained in different zones. | |
96 | + | |
97 | + If unsure, say `N'. | |
98 | + | |
86 | 99 | config NF_CONNTRACK_EVENTS |
87 | 100 | bool "Connection tracking events" |
88 | 101 | depends on NETFILTER_ADVANCED |
net/netfilter/nf_conntrack_core.c
... | ... | @@ -42,6 +42,7 @@ |
42 | 42 | #include <net/netfilter/nf_conntrack_extend.h> |
43 | 43 | #include <net/netfilter/nf_conntrack_acct.h> |
44 | 44 | #include <net/netfilter/nf_conntrack_ecache.h> |
45 | +#include <net/netfilter/nf_conntrack_zones.h> | |
45 | 46 | #include <net/netfilter/nf_nat.h> |
46 | 47 | #include <net/netfilter/nf_nat_core.h> |
47 | 48 | |
... | ... | @@ -68,7 +69,7 @@ |
68 | 69 | static unsigned int nf_conntrack_hash_rnd; |
69 | 70 | |
70 | 71 | static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple, |
71 | - unsigned int size, unsigned int rnd) | |
72 | + u16 zone, unsigned int size, unsigned int rnd) | |
72 | 73 | { |
73 | 74 | unsigned int n; |
74 | 75 | u_int32_t h; |
75 | 76 | |
76 | 77 | |
... | ... | @@ -79,16 +80,16 @@ |
79 | 80 | */ |
80 | 81 | n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32); |
81 | 82 | h = jhash2((u32 *)tuple, n, |
82 | - rnd ^ (((__force __u16)tuple->dst.u.all << 16) | | |
83 | - tuple->dst.protonum)); | |
83 | + zone ^ rnd ^ (((__force __u16)tuple->dst.u.all << 16) | | |
84 | + tuple->dst.protonum)); | |
84 | 85 | |
85 | 86 | return ((u64)h * size) >> 32; |
86 | 87 | } |
87 | 88 | |
88 | -static inline u_int32_t hash_conntrack(const struct net *net, | |
89 | +static inline u_int32_t hash_conntrack(const struct net *net, u16 zone, | |
89 | 90 | const struct nf_conntrack_tuple *tuple) |
90 | 91 | { |
91 | - return __hash_conntrack(tuple, net->ct.htable_size, | |
92 | + return __hash_conntrack(tuple, zone, net->ct.htable_size, | |
92 | 93 | nf_conntrack_hash_rnd); |
93 | 94 | } |
94 | 95 | |
95 | 96 | |
... | ... | @@ -292,11 +293,12 @@ |
292 | 293 | * - Caller must lock nf_conntrack_lock before calling this function |
293 | 294 | */ |
294 | 295 | struct nf_conntrack_tuple_hash * |
295 | -__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) | |
296 | +__nf_conntrack_find(struct net *net, u16 zone, | |
297 | + const struct nf_conntrack_tuple *tuple) | |
296 | 298 | { |
297 | 299 | struct nf_conntrack_tuple_hash *h; |
298 | 300 | struct hlist_nulls_node *n; |
299 | - unsigned int hash = hash_conntrack(net, tuple); | |
301 | + unsigned int hash = hash_conntrack(net, zone, tuple); | |
300 | 302 | |
301 | 303 | /* Disable BHs the entire time since we normally need to disable them |
302 | 304 | * at least once for the stats anyway. |
... | ... | @@ -304,7 +306,8 @@ |
304 | 306 | local_bh_disable(); |
305 | 307 | begin: |
306 | 308 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { |
307 | - if (nf_ct_tuple_equal(tuple, &h->tuple)) { | |
309 | + if (nf_ct_tuple_equal(tuple, &h->tuple) && | |
310 | + nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) { | |
308 | 311 | NF_CT_STAT_INC(net, found); |
309 | 312 | local_bh_enable(); |
310 | 313 | return h; |
311 | 314 | |
312 | 315 | |
... | ... | @@ -326,21 +329,23 @@ |
326 | 329 | |
327 | 330 | /* Find a connection corresponding to a tuple. */ |
328 | 331 | struct nf_conntrack_tuple_hash * |
329 | -nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) | |
332 | +nf_conntrack_find_get(struct net *net, u16 zone, | |
333 | + const struct nf_conntrack_tuple *tuple) | |
330 | 334 | { |
331 | 335 | struct nf_conntrack_tuple_hash *h; |
332 | 336 | struct nf_conn *ct; |
333 | 337 | |
334 | 338 | rcu_read_lock(); |
335 | 339 | begin: |
336 | - h = __nf_conntrack_find(net, tuple); | |
340 | + h = __nf_conntrack_find(net, zone, tuple); | |
337 | 341 | if (h) { |
338 | 342 | ct = nf_ct_tuplehash_to_ctrack(h); |
339 | 343 | if (unlikely(nf_ct_is_dying(ct) || |
340 | 344 | !atomic_inc_not_zero(&ct->ct_general.use))) |
341 | 345 | h = NULL; |
342 | 346 | else { |
343 | - if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) { | |
347 | + if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) || | |
348 | + nf_ct_zone(ct) != zone)) { | |
344 | 349 | nf_ct_put(ct); |
345 | 350 | goto begin; |
346 | 351 | } |
347 | 352 | |
... | ... | @@ -368,9 +373,11 @@ |
368 | 373 | { |
369 | 374 | struct net *net = nf_ct_net(ct); |
370 | 375 | unsigned int hash, repl_hash; |
376 | + u16 zone; | |
371 | 377 | |
372 | - hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
373 | - repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
378 | + zone = nf_ct_zone(ct); | |
379 | + hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
380 | + repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
374 | 381 | |
375 | 382 | __nf_conntrack_hash_insert(ct, hash, repl_hash); |
376 | 383 | } |
... | ... | @@ -387,6 +394,7 @@ |
387 | 394 | struct hlist_nulls_node *n; |
388 | 395 | enum ip_conntrack_info ctinfo; |
389 | 396 | struct net *net; |
397 | + u16 zone; | |
390 | 398 | |
391 | 399 | ct = nf_ct_get(skb, &ctinfo); |
392 | 400 | net = nf_ct_net(ct); |
... | ... | @@ -398,8 +406,9 @@ |
398 | 406 | if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) |
399 | 407 | return NF_ACCEPT; |
400 | 408 | |
401 | - hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
402 | - repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
409 | + zone = nf_ct_zone(ct); | |
410 | + hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
411 | + repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
403 | 412 | |
404 | 413 | /* We're not in hash table, and we refuse to set up related |
405 | 414 | connections for unconfirmed conns. But packet copies and |
406 | 415 | |
... | ... | @@ -418,11 +427,13 @@ |
418 | 427 | not in the hash. If there is, we lost race. */ |
419 | 428 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) |
420 | 429 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
421 | - &h->tuple)) | |
430 | + &h->tuple) && | |
431 | + zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) | |
422 | 432 | goto out; |
423 | 433 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) |
424 | 434 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
425 | - &h->tuple)) | |
435 | + &h->tuple) && | |
436 | + zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) | |
426 | 437 | goto out; |
427 | 438 | |
428 | 439 | /* Remove from unconfirmed list */ |
429 | 440 | |
... | ... | @@ -469,15 +480,19 @@ |
469 | 480 | struct net *net = nf_ct_net(ignored_conntrack); |
470 | 481 | struct nf_conntrack_tuple_hash *h; |
471 | 482 | struct hlist_nulls_node *n; |
472 | - unsigned int hash = hash_conntrack(net, tuple); | |
483 | + struct nf_conn *ct; | |
484 | + u16 zone = nf_ct_zone(ignored_conntrack); | |
485 | + unsigned int hash = hash_conntrack(net, zone, tuple); | |
473 | 486 | |
474 | 487 | /* Disable BHs the entire time since we need to disable them at |
475 | 488 | * least once for the stats anyway. |
476 | 489 | */ |
477 | 490 | rcu_read_lock_bh(); |
478 | 491 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { |
479 | - if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && | |
480 | - nf_ct_tuple_equal(tuple, &h->tuple)) { | |
492 | + ct = nf_ct_tuplehash_to_ctrack(h); | |
493 | + if (ct != ignored_conntrack && | |
494 | + nf_ct_tuple_equal(tuple, &h->tuple) && | |
495 | + nf_ct_zone(ct) == zone) { | |
481 | 496 | NF_CT_STAT_INC(net, found); |
482 | 497 | rcu_read_unlock_bh(); |
483 | 498 | return 1; |
... | ... | @@ -540,7 +555,7 @@ |
540 | 555 | return dropped; |
541 | 556 | } |
542 | 557 | |
543 | -struct nf_conn *nf_conntrack_alloc(struct net *net, | |
558 | +struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone, | |
544 | 559 | const struct nf_conntrack_tuple *orig, |
545 | 560 | const struct nf_conntrack_tuple *repl, |
546 | 561 | gfp_t gfp) |
... | ... | @@ -558,7 +573,7 @@ |
558 | 573 | |
559 | 574 | if (nf_conntrack_max && |
560 | 575 | unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) { |
561 | - unsigned int hash = hash_conntrack(net, orig); | |
576 | + unsigned int hash = hash_conntrack(net, zone, orig); | |
562 | 577 | if (!early_drop(net, hash)) { |
563 | 578 | atomic_dec(&net->ct.count); |
564 | 579 | if (net_ratelimit()) |
565 | 580 | |
566 | 581 | |
... | ... | @@ -595,13 +610,28 @@ |
595 | 610 | #ifdef CONFIG_NET_NS |
596 | 611 | ct->ct_net = net; |
597 | 612 | #endif |
613 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
614 | + if (zone) { | |
615 | + struct nf_conntrack_zone *nf_ct_zone; | |
598 | 616 | |
617 | + nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, GFP_ATOMIC); | |
618 | + if (!nf_ct_zone) | |
619 | + goto out_free; | |
620 | + nf_ct_zone->id = zone; | |
621 | + } | |
622 | +#endif | |
599 | 623 | /* |
600 | 624 | * changes to lookup keys must be done before setting refcnt to 1 |
601 | 625 | */ |
602 | 626 | smp_wmb(); |
603 | 627 | atomic_set(&ct->ct_general.use, 1); |
604 | 628 | return ct; |
629 | + | |
630 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
631 | +out_free: | |
632 | + kmem_cache_free(net->ct.nf_conntrack_cachep, ct); | |
633 | + return ERR_PTR(-ENOMEM); | |
634 | +#endif | |
605 | 635 | } |
606 | 636 | EXPORT_SYMBOL_GPL(nf_conntrack_alloc); |
607 | 637 | |
608 | 638 | |
... | ... | @@ -631,13 +661,14 @@ |
631 | 661 | struct nf_conntrack_tuple repl_tuple; |
632 | 662 | struct nf_conntrack_ecache *ecache; |
633 | 663 | struct nf_conntrack_expect *exp; |
664 | + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; | |
634 | 665 | |
635 | 666 | if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { |
636 | 667 | pr_debug("Can't invert tuple.\n"); |
637 | 668 | return NULL; |
638 | 669 | } |
639 | 670 | |
640 | - ct = nf_conntrack_alloc(net, tuple, &repl_tuple, GFP_ATOMIC); | |
671 | + ct = nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC); | |
641 | 672 | if (IS_ERR(ct)) { |
642 | 673 | pr_debug("Can't allocate conntrack.\n"); |
643 | 674 | return (struct nf_conntrack_tuple_hash *)ct; |
... | ... | @@ -657,7 +688,7 @@ |
657 | 688 | GFP_ATOMIC); |
658 | 689 | |
659 | 690 | spin_lock_bh(&nf_conntrack_lock); |
660 | - exp = nf_ct_find_expectation(net, tuple); | |
691 | + exp = nf_ct_find_expectation(net, zone, tuple); | |
661 | 692 | if (exp) { |
662 | 693 | pr_debug("conntrack: expectation arrives ct=%p exp=%p\n", |
663 | 694 | ct, exp); |
... | ... | @@ -713,6 +744,7 @@ |
713 | 744 | struct nf_conntrack_tuple tuple; |
714 | 745 | struct nf_conntrack_tuple_hash *h; |
715 | 746 | struct nf_conn *ct; |
747 | + u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; | |
716 | 748 | |
717 | 749 | if (!nf_ct_get_tuple(skb, skb_network_offset(skb), |
718 | 750 | dataoff, l3num, protonum, &tuple, l3proto, |
... | ... | @@ -722,7 +754,7 @@ |
722 | 754 | } |
723 | 755 | |
724 | 756 | /* look for tuple match */ |
725 | - h = nf_conntrack_find_get(net, &tuple); | |
757 | + h = nf_conntrack_find_get(net, zone, &tuple); | |
726 | 758 | if (!h) { |
727 | 759 | h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, |
728 | 760 | skb, dataoff); |
... | ... | @@ -958,6 +990,14 @@ |
958 | 990 | } |
959 | 991 | EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); |
960 | 992 | |
993 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
994 | +static struct nf_ct_ext_type nf_ct_zone_extend __read_mostly = { | |
995 | + .len = sizeof(struct nf_conntrack_zone), | |
996 | + .align = __alignof__(struct nf_conntrack_zone), | |
997 | + .id = NF_CT_EXT_ZONE, | |
998 | +}; | |
999 | +#endif | |
1000 | + | |
961 | 1001 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
962 | 1002 | |
963 | 1003 | #include <linux/netfilter/nfnetlink.h> |
... | ... | @@ -1139,6 +1179,9 @@ |
1139 | 1179 | |
1140 | 1180 | nf_conntrack_helper_fini(); |
1141 | 1181 | nf_conntrack_proto_fini(); |
1182 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
1183 | + nf_ct_extend_unregister(&nf_ct_zone_extend); | |
1184 | +#endif | |
1142 | 1185 | } |
1143 | 1186 | |
1144 | 1187 | static void nf_conntrack_cleanup_net(struct net *net) |
... | ... | @@ -1214,6 +1257,7 @@ |
1214 | 1257 | unsigned int hashsize, old_size; |
1215 | 1258 | struct hlist_nulls_head *hash, *old_hash; |
1216 | 1259 | struct nf_conntrack_tuple_hash *h; |
1260 | + struct nf_conn *ct; | |
1217 | 1261 | |
1218 | 1262 | if (current->nsproxy->net_ns != &init_net) |
1219 | 1263 | return -EOPNOTSUPP; |
1220 | 1264 | |
... | ... | @@ -1240,8 +1284,10 @@ |
1240 | 1284 | while (!hlist_nulls_empty(&init_net.ct.hash[i])) { |
1241 | 1285 | h = hlist_nulls_entry(init_net.ct.hash[i].first, |
1242 | 1286 | struct nf_conntrack_tuple_hash, hnnode); |
1287 | + ct = nf_ct_tuplehash_to_ctrack(h); | |
1243 | 1288 | hlist_nulls_del_rcu(&h->hnnode); |
1244 | - bucket = __hash_conntrack(&h->tuple, hashsize, | |
1289 | + bucket = __hash_conntrack(&h->tuple, nf_ct_zone(ct), | |
1290 | + hashsize, | |
1245 | 1291 | nf_conntrack_hash_rnd); |
1246 | 1292 | hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]); |
1247 | 1293 | } |
... | ... | @@ -1299,6 +1345,11 @@ |
1299 | 1345 | if (ret < 0) |
1300 | 1346 | goto err_helper; |
1301 | 1347 | |
1348 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
1349 | + ret = nf_ct_extend_register(&nf_ct_zone_extend); | |
1350 | + if (ret < 0) | |
1351 | + goto err_extend; | |
1352 | +#endif | |
1302 | 1353 | /* Set up fake conntrack: to never be deleted, not in any hashes */ |
1303 | 1354 | #ifdef CONFIG_NET_NS |
1304 | 1355 | nf_conntrack_untracked.ct_net = &init_net; |
... | ... | @@ -1309,6 +1360,10 @@ |
1309 | 1360 | |
1310 | 1361 | return 0; |
1311 | 1362 | |
1363 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
1364 | +err_extend: | |
1365 | + nf_conntrack_helper_fini(); | |
1366 | +#endif | |
1312 | 1367 | err_helper: |
1313 | 1368 | nf_conntrack_proto_fini(); |
1314 | 1369 | err_proto: |
net/netfilter/nf_conntrack_expect.c
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | #include <net/netfilter/nf_conntrack_expect.h> |
28 | 28 | #include <net/netfilter/nf_conntrack_helper.h> |
29 | 29 | #include <net/netfilter/nf_conntrack_tuple.h> |
30 | +#include <net/netfilter/nf_conntrack_zones.h> | |
30 | 31 | |
31 | 32 | unsigned int nf_ct_expect_hsize __read_mostly; |
32 | 33 | EXPORT_SYMBOL_GPL(nf_ct_expect_hsize); |
... | ... | @@ -84,7 +85,8 @@ |
84 | 85 | } |
85 | 86 | |
86 | 87 | struct nf_conntrack_expect * |
87 | -__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple) | |
88 | +__nf_ct_expect_find(struct net *net, u16 zone, | |
89 | + const struct nf_conntrack_tuple *tuple) | |
88 | 90 | { |
89 | 91 | struct nf_conntrack_expect *i; |
90 | 92 | struct hlist_node *n; |
... | ... | @@ -95,7 +97,8 @@ |
95 | 97 | |
96 | 98 | h = nf_ct_expect_dst_hash(tuple); |
97 | 99 | hlist_for_each_entry_rcu(i, n, &net->ct.expect_hash[h], hnode) { |
98 | - if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) | |
100 | + if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) && | |
101 | + nf_ct_zone(i->master) == zone) | |
99 | 102 | return i; |
100 | 103 | } |
101 | 104 | return NULL; |
102 | 105 | |
... | ... | @@ -104,12 +107,13 @@ |
104 | 107 | |
105 | 108 | /* Just find a expectation corresponding to a tuple. */ |
106 | 109 | struct nf_conntrack_expect * |
107 | -nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) | |
110 | +nf_ct_expect_find_get(struct net *net, u16 zone, | |
111 | + const struct nf_conntrack_tuple *tuple) | |
108 | 112 | { |
109 | 113 | struct nf_conntrack_expect *i; |
110 | 114 | |
111 | 115 | rcu_read_lock(); |
112 | - i = __nf_ct_expect_find(net, tuple); | |
116 | + i = __nf_ct_expect_find(net, zone, tuple); | |
113 | 117 | if (i && !atomic_inc_not_zero(&i->use)) |
114 | 118 | i = NULL; |
115 | 119 | rcu_read_unlock(); |
... | ... | @@ -121,7 +125,8 @@ |
121 | 125 | /* If an expectation for this connection is found, it gets delete from |
122 | 126 | * global list then returned. */ |
123 | 127 | struct nf_conntrack_expect * |
124 | -nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple) | |
128 | +nf_ct_find_expectation(struct net *net, u16 zone, | |
129 | + const struct nf_conntrack_tuple *tuple) | |
125 | 130 | { |
126 | 131 | struct nf_conntrack_expect *i, *exp = NULL; |
127 | 132 | struct hlist_node *n; |
... | ... | @@ -133,7 +138,8 @@ |
133 | 138 | h = nf_ct_expect_dst_hash(tuple); |
134 | 139 | hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) { |
135 | 140 | if (!(i->flags & NF_CT_EXPECT_INACTIVE) && |
136 | - nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { | |
141 | + nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) && | |
142 | + nf_ct_zone(i->master) == zone) { | |
137 | 143 | exp = i; |
138 | 144 | break; |
139 | 145 | } |
... | ... | @@ -204,7 +210,8 @@ |
204 | 210 | { |
205 | 211 | return a->master == b->master && a->class == b->class && |
206 | 212 | nf_ct_tuple_equal(&a->tuple, &b->tuple) && |
207 | - nf_ct_tuple_mask_equal(&a->mask, &b->mask); | |
213 | + nf_ct_tuple_mask_equal(&a->mask, &b->mask) && | |
214 | + nf_ct_zone(a->master) == nf_ct_zone(b->master); | |
208 | 215 | } |
209 | 216 | |
210 | 217 | /* Generally a bad idea to call this: could have matched already. */ |
net/netfilter/nf_conntrack_h323_main.c
... | ... | @@ -29,6 +29,7 @@ |
29 | 29 | #include <net/netfilter/nf_conntrack_expect.h> |
30 | 30 | #include <net/netfilter/nf_conntrack_ecache.h> |
31 | 31 | #include <net/netfilter/nf_conntrack_helper.h> |
32 | +#include <net/netfilter/nf_conntrack_zones.h> | |
32 | 33 | #include <linux/netfilter/nf_conntrack_h323.h> |
33 | 34 | |
34 | 35 | /* Parameters */ |
... | ... | @@ -1216,7 +1217,7 @@ |
1216 | 1217 | tuple.dst.u.tcp.port = port; |
1217 | 1218 | tuple.dst.protonum = IPPROTO_TCP; |
1218 | 1219 | |
1219 | - exp = __nf_ct_expect_find(net, &tuple); | |
1220 | + exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple); | |
1220 | 1221 | if (exp && exp->master == ct) |
1221 | 1222 | return exp; |
1222 | 1223 | return NULL; |
net/netfilter/nf_conntrack_netlink.c
... | ... | @@ -811,7 +811,7 @@ |
811 | 811 | if (err < 0) |
812 | 812 | return err; |
813 | 813 | |
814 | - h = nf_conntrack_find_get(net, &tuple); | |
814 | + h = nf_conntrack_find_get(net, 0, &tuple); | |
815 | 815 | if (!h) |
816 | 816 | return -ENOENT; |
817 | 817 | |
... | ... | @@ -872,7 +872,7 @@ |
872 | 872 | if (err < 0) |
873 | 873 | return err; |
874 | 874 | |
875 | - h = nf_conntrack_find_get(net, &tuple); | |
875 | + h = nf_conntrack_find_get(net, 0, &tuple); | |
876 | 876 | if (!h) |
877 | 877 | return -ENOENT; |
878 | 878 | |
... | ... | @@ -1221,7 +1221,7 @@ |
1221 | 1221 | int err = -EINVAL; |
1222 | 1222 | struct nf_conntrack_helper *helper; |
1223 | 1223 | |
1224 | - ct = nf_conntrack_alloc(net, otuple, rtuple, GFP_ATOMIC); | |
1224 | + ct = nf_conntrack_alloc(net, 0, otuple, rtuple, GFP_ATOMIC); | |
1225 | 1225 | if (IS_ERR(ct)) |
1226 | 1226 | return ERR_PTR(-ENOMEM); |
1227 | 1227 | |
... | ... | @@ -1325,7 +1325,7 @@ |
1325 | 1325 | if (err < 0) |
1326 | 1326 | goto err2; |
1327 | 1327 | |
1328 | - master_h = nf_conntrack_find_get(net, &master); | |
1328 | + master_h = nf_conntrack_find_get(net, 0, &master); | |
1329 | 1329 | if (master_h == NULL) { |
1330 | 1330 | err = -ENOENT; |
1331 | 1331 | goto err2; |
1332 | 1332 | |
... | ... | @@ -1374,9 +1374,9 @@ |
1374 | 1374 | |
1375 | 1375 | spin_lock_bh(&nf_conntrack_lock); |
1376 | 1376 | if (cda[CTA_TUPLE_ORIG]) |
1377 | - h = __nf_conntrack_find(net, &otuple); | |
1377 | + h = __nf_conntrack_find(net, 0, &otuple); | |
1378 | 1378 | else if (cda[CTA_TUPLE_REPLY]) |
1379 | - h = __nf_conntrack_find(net, &rtuple); | |
1379 | + h = __nf_conntrack_find(net, 0, &rtuple); | |
1380 | 1380 | |
1381 | 1381 | if (h == NULL) { |
1382 | 1382 | err = -ENOENT; |
... | ... | @@ -1714,7 +1714,7 @@ |
1714 | 1714 | if (err < 0) |
1715 | 1715 | return err; |
1716 | 1716 | |
1717 | - exp = nf_ct_expect_find_get(net, &tuple); | |
1717 | + exp = nf_ct_expect_find_get(net, 0, &tuple); | |
1718 | 1718 | if (!exp) |
1719 | 1719 | return -ENOENT; |
1720 | 1720 | |
... | ... | @@ -1770,7 +1770,7 @@ |
1770 | 1770 | return err; |
1771 | 1771 | |
1772 | 1772 | /* bump usage count to 2 */ |
1773 | - exp = nf_ct_expect_find_get(net, &tuple); | |
1773 | + exp = nf_ct_expect_find_get(net, 0, &tuple); | |
1774 | 1774 | if (!exp) |
1775 | 1775 | return -ENOENT; |
1776 | 1776 | |
... | ... | @@ -1855,7 +1855,7 @@ |
1855 | 1855 | return err; |
1856 | 1856 | |
1857 | 1857 | /* Look for master conntrack of this expectation */ |
1858 | - h = nf_conntrack_find_get(net, &master_tuple); | |
1858 | + h = nf_conntrack_find_get(net, 0, &master_tuple); | |
1859 | 1859 | if (!h) |
1860 | 1860 | return -ENOENT; |
1861 | 1861 | ct = nf_ct_tuplehash_to_ctrack(h); |
... | ... | @@ -1912,7 +1912,7 @@ |
1912 | 1912 | return err; |
1913 | 1913 | |
1914 | 1914 | spin_lock_bh(&nf_conntrack_lock); |
1915 | - exp = __nf_ct_expect_find(net, &tuple); | |
1915 | + exp = __nf_ct_expect_find(net, 0, &tuple); | |
1916 | 1916 | |
1917 | 1917 | if (!exp) { |
1918 | 1918 | spin_unlock_bh(&nf_conntrack_lock); |
net/netfilter/nf_conntrack_pptp.c
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | #include <net/netfilter/nf_conntrack.h> |
29 | 29 | #include <net/netfilter/nf_conntrack_core.h> |
30 | 30 | #include <net/netfilter/nf_conntrack_helper.h> |
31 | +#include <net/netfilter/nf_conntrack_zones.h> | |
31 | 32 | #include <linux/netfilter/nf_conntrack_proto_gre.h> |
32 | 33 | #include <linux/netfilter/nf_conntrack_pptp.h> |
33 | 34 | |
... | ... | @@ -123,7 +124,7 @@ |
123 | 124 | pr_debug("trying to unexpect other dir: "); |
124 | 125 | nf_ct_dump_tuple(&inv_t); |
125 | 126 | |
126 | - exp_other = nf_ct_expect_find_get(net, &inv_t); | |
127 | + exp_other = nf_ct_expect_find_get(net, nf_ct_zone(ct), &inv_t); | |
127 | 128 | if (exp_other) { |
128 | 129 | /* delete other expectation. */ |
129 | 130 | pr_debug("found\n"); |
130 | 131 | |
131 | 132 | |
... | ... | @@ -136,17 +137,18 @@ |
136 | 137 | rcu_read_unlock(); |
137 | 138 | } |
138 | 139 | |
139 | -static int destroy_sibling_or_exp(struct net *net, | |
140 | +static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct, | |
140 | 141 | const struct nf_conntrack_tuple *t) |
141 | 142 | { |
142 | 143 | const struct nf_conntrack_tuple_hash *h; |
143 | 144 | struct nf_conntrack_expect *exp; |
144 | 145 | struct nf_conn *sibling; |
146 | + u16 zone = nf_ct_zone(ct); | |
145 | 147 | |
146 | 148 | pr_debug("trying to timeout ct or exp for tuple "); |
147 | 149 | nf_ct_dump_tuple(t); |
148 | 150 | |
149 | - h = nf_conntrack_find_get(net, t); | |
151 | + h = nf_conntrack_find_get(net, zone, t); | |
150 | 152 | if (h) { |
151 | 153 | sibling = nf_ct_tuplehash_to_ctrack(h); |
152 | 154 | pr_debug("setting timeout of conntrack %p to 0\n", sibling); |
... | ... | @@ -157,7 +159,7 @@ |
157 | 159 | nf_ct_put(sibling); |
158 | 160 | return 1; |
159 | 161 | } else { |
160 | - exp = nf_ct_expect_find_get(net, t); | |
162 | + exp = nf_ct_expect_find_get(net, zone, t); | |
161 | 163 | if (exp) { |
162 | 164 | pr_debug("unexpect_related of expect %p\n", exp); |
163 | 165 | nf_ct_unexpect_related(exp); |
... | ... | @@ -182,7 +184,7 @@ |
182 | 184 | t.dst.protonum = IPPROTO_GRE; |
183 | 185 | t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id; |
184 | 186 | t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id; |
185 | - if (!destroy_sibling_or_exp(net, &t)) | |
187 | + if (!destroy_sibling_or_exp(net, ct, &t)) | |
186 | 188 | pr_debug("failed to timeout original pns->pac ct/exp\n"); |
187 | 189 | |
188 | 190 | /* try reply (pac->pns) tuple */ |
... | ... | @@ -190,7 +192,7 @@ |
190 | 192 | t.dst.protonum = IPPROTO_GRE; |
191 | 193 | t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id; |
192 | 194 | t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id; |
193 | - if (!destroy_sibling_or_exp(net, &t)) | |
195 | + if (!destroy_sibling_or_exp(net, ct, &t)) | |
194 | 196 | pr_debug("failed to timeout reply pac->pns ct/exp\n"); |
195 | 197 | } |
196 | 198 |
net/netfilter/nf_conntrack_sip.c
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | #include <net/netfilter/nf_conntrack_core.h> |
24 | 24 | #include <net/netfilter/nf_conntrack_expect.h> |
25 | 25 | #include <net/netfilter/nf_conntrack_helper.h> |
26 | +#include <net/netfilter/nf_conntrack_zones.h> | |
26 | 27 | #include <linux/netfilter/nf_conntrack_sip.h> |
27 | 28 | |
28 | 29 | MODULE_LICENSE("GPL"); |
... | ... | @@ -836,7 +837,7 @@ |
836 | 837 | |
837 | 838 | rcu_read_lock(); |
838 | 839 | do { |
839 | - exp = __nf_ct_expect_find(net, &tuple); | |
840 | + exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple); | |
840 | 841 | |
841 | 842 | if (!exp || exp->master == ct || |
842 | 843 | nfct_help(exp->master)->helper != nfct_help(ct)->helper || |
net/netfilter/nf_conntrack_standalone.c
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | #include <net/netfilter/nf_conntrack_expect.h> |
27 | 27 | #include <net/netfilter/nf_conntrack_helper.h> |
28 | 28 | #include <net/netfilter/nf_conntrack_acct.h> |
29 | +#include <net/netfilter/nf_conntrack_zones.h> | |
29 | 30 | |
30 | 31 | MODULE_LICENSE("GPL"); |
31 | 32 | |
... | ... | @@ -168,6 +169,11 @@ |
168 | 169 | |
169 | 170 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
170 | 171 | if (seq_printf(s, "secmark=%u ", ct->secmark)) |
172 | + goto release; | |
173 | +#endif | |
174 | + | |
175 | +#ifdef CONFIG_NF_CONNTRACK_ZONES | |
176 | + if (seq_printf(s, "zone=%u ", nf_ct_zone(ct))) | |
171 | 177 | goto release; |
172 | 178 | #endif |
173 | 179 |
net/netfilter/xt_CT.c
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | #include <net/netfilter/nf_conntrack.h> |
17 | 17 | #include <net/netfilter/nf_conntrack_helper.h> |
18 | 18 | #include <net/netfilter/nf_conntrack_ecache.h> |
19 | +#include <net/netfilter/nf_conntrack_zones.h> | |
19 | 20 | |
20 | 21 | static unsigned int xt_ct_target(struct sk_buff *skb, |
21 | 22 | const struct xt_target_param *par) |
22 | 23 | |
... | ... | @@ -69,11 +70,16 @@ |
69 | 70 | goto out; |
70 | 71 | } |
71 | 72 | |
73 | +#ifndef CONFIG_NF_CONNTRACK_ZONES | |
74 | + if (info->zone) | |
75 | + goto err1; | |
76 | +#endif | |
77 | + | |
72 | 78 | if (nf_ct_l3proto_try_module_get(par->family) < 0) |
73 | 79 | goto err1; |
74 | 80 | |
75 | 81 | memset(&t, 0, sizeof(t)); |
76 | - ct = nf_conntrack_alloc(par->net, &t, &t, GFP_KERNEL); | |
82 | + ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); | |
77 | 83 | if (IS_ERR(ct)) |
78 | 84 | goto err2; |
79 | 85 |
net/netfilter/xt_connlimit.c
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | #include <net/netfilter/nf_conntrack.h> |
29 | 29 | #include <net/netfilter/nf_conntrack_core.h> |
30 | 30 | #include <net/netfilter/nf_conntrack_tuple.h> |
31 | +#include <net/netfilter/nf_conntrack_zones.h> | |
31 | 32 | |
32 | 33 | /* we will save the tuples of all connections we care about */ |
33 | 34 | struct xt_connlimit_conn { |
... | ... | @@ -114,7 +115,8 @@ |
114 | 115 | |
115 | 116 | /* check the saved connections */ |
116 | 117 | list_for_each_entry_safe(conn, tmp, hash, list) { |
117 | - found = nf_conntrack_find_get(net, &conn->tuple); | |
118 | + found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE, | |
119 | + &conn->tuple); | |
118 | 120 | found_ct = NULL; |
119 | 121 | |
120 | 122 | if (found != NULL) |