Commit 5d0aa2ccd4699a01cfdf14886191c249d7b45a01

Authored by Patrick McHardy
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
... ... @@ -5,7 +5,7 @@
5 5  
6 6 struct xt_ct_target_info {
7 7 u_int16_t flags;
8   - u_int16_t __unused;
  8 + u_int16_t zone;
9 9 u_int32_t ct_events;
10 10 u_int32_t exp_events;
11 11 char helper[16];
... ... @@ -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
... ... @@ -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)