diff options
author | Patrick McHardy <kaber@trash.net> | 2010-02-15 12:13:33 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-02-15 12:13:33 -0500 |
commit | 5d0aa2ccd4699a01cfdf14886191c249d7b45a01 (patch) | |
tree | 6ea81b5eede26bd6a04bcc3cd79770c334139381 /net/ipv4 | |
parent | 8fea97ec1772bbf553d89187340ef624d548e115 (diff) |
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>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 8 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_defrag_ipv4.c | 12 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_core.c | 24 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_pptp.c | 3 |
5 files changed, 32 insertions, 18 deletions
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index d1ea38a7c490..2bb1f87051c4 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <net/netfilter/nf_conntrack_helper.h> | 22 | #include <net/netfilter/nf_conntrack_helper.h> |
23 | #include <net/netfilter/nf_conntrack_l4proto.h> | 23 | #include <net/netfilter/nf_conntrack_l4proto.h> |
24 | #include <net/netfilter/nf_conntrack_l3proto.h> | 24 | #include <net/netfilter/nf_conntrack_l3proto.h> |
25 | #include <net/netfilter/nf_conntrack_zones.h> | ||
25 | #include <net/netfilter/nf_conntrack_core.h> | 26 | #include <net/netfilter/nf_conntrack_core.h> |
26 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 27 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
27 | #include <net/netfilter/nf_nat_helper.h> | 28 | #include <net/netfilter/nf_nat_helper.h> |
@@ -266,7 +267,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) | |||
266 | return -EINVAL; | 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 | if (h) { | 271 | if (h) { |
271 | struct sockaddr_in sin; | 272 | struct sockaddr_in sin; |
272 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); | 273 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); |
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 327826a968a8..7404bde95994 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <net/netfilter/nf_conntrack_tuple.h> | 18 | #include <net/netfilter/nf_conntrack_tuple.h> |
19 | #include <net/netfilter/nf_conntrack_l4proto.h> | 19 | #include <net/netfilter/nf_conntrack_l4proto.h> |
20 | #include <net/netfilter/nf_conntrack_core.h> | 20 | #include <net/netfilter/nf_conntrack_core.h> |
21 | #include <net/netfilter/nf_conntrack_zones.h> | ||
21 | #include <net/netfilter/nf_log.h> | 22 | #include <net/netfilter/nf_log.h> |
22 | 23 | ||
23 | static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ; | 24 | static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ; |
@@ -114,13 +115,14 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
114 | 115 | ||
115 | /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ | 116 | /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ |
116 | static int | 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 | enum ip_conntrack_info *ctinfo, | 119 | enum ip_conntrack_info *ctinfo, |
119 | unsigned int hooknum) | 120 | unsigned int hooknum) |
120 | { | 121 | { |
121 | struct nf_conntrack_tuple innertuple, origtuple; | 122 | struct nf_conntrack_tuple innertuple, origtuple; |
122 | const struct nf_conntrack_l4proto *innerproto; | 123 | const struct nf_conntrack_l4proto *innerproto; |
123 | const struct nf_conntrack_tuple_hash *h; | 124 | const struct nf_conntrack_tuple_hash *h; |
125 | u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; | ||
124 | 126 | ||
125 | NF_CT_ASSERT(skb->nfct == NULL); | 127 | NF_CT_ASSERT(skb->nfct == NULL); |
126 | 128 | ||
@@ -146,7 +148,7 @@ icmp_error_message(struct net *net, struct sk_buff *skb, | |||
146 | 148 | ||
147 | *ctinfo = IP_CT_RELATED; | 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 | if (!h) { | 152 | if (!h) { |
151 | pr_debug("icmp_error_message: no match\n"); | 153 | pr_debug("icmp_error_message: no match\n"); |
152 | return -NF_ACCEPT; | 154 | return -NF_ACCEPT; |
@@ -209,7 +211,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl, | |||
209 | icmph->type != ICMP_REDIRECT) | 211 | icmph->type != ICMP_REDIRECT) |
210 | return NF_ACCEPT; | 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 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 217 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index f6f46686cbc0..d498a704d456 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/netfilter_bridge.h> | 17 | #include <linux/netfilter_bridge.h> |
18 | #include <linux/netfilter_ipv4.h> | 18 | #include <linux/netfilter_ipv4.h> |
19 | #include <net/netfilter/nf_conntrack_zones.h> | ||
19 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | 20 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
20 | #include <net/netfilter/nf_conntrack.h> | 21 | #include <net/netfilter/nf_conntrack.h> |
21 | 22 | ||
@@ -39,15 +40,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) | |||
39 | static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, | 40 | static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, |
40 | struct sk_buff *skb) | 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 | #ifdef CONFIG_BRIDGE_NETFILTER | 48 | #ifdef CONFIG_BRIDGE_NETFILTER |
43 | if (skb->nf_bridge && | 49 | if (skb->nf_bridge && |
44 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | 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 | #endif | 52 | #endif |
47 | if (hooknum == NF_INET_PRE_ROUTING) | 53 | if (hooknum == NF_INET_PRE_ROUTING) |
48 | return IP_DEFRAG_CONNTRACK_IN; | 54 | return IP_DEFRAG_CONNTRACK_IN + zone; |
49 | else | 55 | else |
50 | return IP_DEFRAG_CONNTRACK_OUT; | 56 | return IP_DEFRAG_CONNTRACK_OUT + zone; |
51 | } | 57 | } |
52 | 58 | ||
53 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, | 59 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, |
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 26066a2327ad..4595281c2863 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <net/netfilter/nf_conntrack_helper.h> | 30 | #include <net/netfilter/nf_conntrack_helper.h> |
31 | #include <net/netfilter/nf_conntrack_l3proto.h> | 31 | #include <net/netfilter/nf_conntrack_l3proto.h> |
32 | #include <net/netfilter/nf_conntrack_l4proto.h> | 32 | #include <net/netfilter/nf_conntrack_l4proto.h> |
33 | #include <net/netfilter/nf_conntrack_zones.h> | ||
33 | 34 | ||
34 | static DEFINE_SPINLOCK(nf_nat_lock); | 35 | static DEFINE_SPINLOCK(nf_nat_lock); |
35 | 36 | ||
@@ -69,13 +70,14 @@ EXPORT_SYMBOL_GPL(nf_nat_proto_put); | |||
69 | 70 | ||
70 | /* We keep an extra hash for each conntrack, for fast searching. */ | 71 | /* We keep an extra hash for each conntrack, for fast searching. */ |
71 | static inline unsigned int | 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 | unsigned int hash; | 76 | unsigned int hash; |
75 | 77 | ||
76 | /* Original src, to ensure we map it consistently if poss. */ | 78 | /* Original src, to ensure we map it consistently if poss. */ |
77 | hash = jhash_3words((__force u32)tuple->src.u3.ip, | 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 | tuple->dst.protonum, 0); | 81 | tuple->dst.protonum, 0); |
80 | return ((u64)hash * net->ipv4.nat_htable_size) >> 32; | 82 | return ((u64)hash * net->ipv4.nat_htable_size) >> 32; |
81 | } | 83 | } |
@@ -139,12 +141,12 @@ same_src(const struct nf_conn *ct, | |||
139 | 141 | ||
140 | /* Only called for SRC manip */ | 142 | /* Only called for SRC manip */ |
141 | static int | 143 | static int |
142 | find_appropriate_src(struct net *net, | 144 | find_appropriate_src(struct net *net, u16 zone, |
143 | const struct nf_conntrack_tuple *tuple, | 145 | const struct nf_conntrack_tuple *tuple, |
144 | struct nf_conntrack_tuple *result, | 146 | struct nf_conntrack_tuple *result, |
145 | const struct nf_nat_range *range) | 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 | const struct nf_conn_nat *nat; | 150 | const struct nf_conn_nat *nat; |
149 | const struct nf_conn *ct; | 151 | const struct nf_conn *ct; |
150 | const struct hlist_node *n; | 152 | const struct hlist_node *n; |
@@ -152,7 +154,7 @@ find_appropriate_src(struct net *net, | |||
152 | rcu_read_lock(); | 154 | rcu_read_lock(); |
153 | hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) { | 155 | hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) { |
154 | ct = nat->ct; | 156 | ct = nat->ct; |
155 | if (same_src(ct, tuple)) { | 157 | if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) { |
156 | /* Copy source part from reply tuple. */ | 158 | /* Copy source part from reply tuple. */ |
157 | nf_ct_invert_tuplepr(result, | 159 | nf_ct_invert_tuplepr(result, |
158 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | 160 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); |
@@ -175,7 +177,7 @@ find_appropriate_src(struct net *net, | |||
175 | the ip with the lowest src-ip/dst-ip/proto usage. | 177 | the ip with the lowest src-ip/dst-ip/proto usage. |
176 | */ | 178 | */ |
177 | static void | 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 | const struct nf_nat_range *range, | 181 | const struct nf_nat_range *range, |
180 | const struct nf_conn *ct, | 182 | const struct nf_conn *ct, |
181 | enum nf_nat_manip_type maniptype) | 183 | enum nf_nat_manip_type maniptype) |
@@ -209,7 +211,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple, | |||
209 | maxip = ntohl(range->max_ip); | 211 | maxip = ntohl(range->max_ip); |
210 | j = jhash_2words((__force u32)tuple->src.u3.ip, | 212 | j = jhash_2words((__force u32)tuple->src.u3.ip, |
211 | range->flags & IP_NAT_RANGE_PERSISTENT ? | 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 | j = ((u64)j * (maxip - minip + 1)) >> 32; | 215 | j = ((u64)j * (maxip - minip + 1)) >> 32; |
214 | *var_ipp = htonl(minip + j); | 216 | *var_ipp = htonl(minip + j); |
215 | } | 217 | } |
@@ -229,6 +231,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
229 | { | 231 | { |
230 | struct net *net = nf_ct_net(ct); | 232 | struct net *net = nf_ct_net(ct); |
231 | const struct nf_nat_protocol *proto; | 233 | const struct nf_nat_protocol *proto; |
234 | u16 zone = nf_ct_zone(ct); | ||
232 | 235 | ||
233 | /* 1) If this srcip/proto/src-proto-part is currently mapped, | 236 | /* 1) If this srcip/proto/src-proto-part is currently mapped, |
234 | and that same mapping gives a unique tuple within the given | 237 | and that same mapping gives a unique tuple within the given |
@@ -239,7 +242,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
239 | manips not an issue. */ | 242 | manips not an issue. */ |
240 | if (maniptype == IP_NAT_MANIP_SRC && | 243 | if (maniptype == IP_NAT_MANIP_SRC && |
241 | !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) { | 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 | pr_debug("get_unique_tuple: Found current src map\n"); | 246 | pr_debug("get_unique_tuple: Found current src map\n"); |
244 | if (!nf_nat_used_tuple(tuple, ct)) | 247 | if (!nf_nat_used_tuple(tuple, ct)) |
245 | return; | 248 | return; |
@@ -249,7 +252,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
249 | /* 2) Select the least-used IP/proto combination in the given | 252 | /* 2) Select the least-used IP/proto combination in the given |
250 | range. */ | 253 | range. */ |
251 | *tuple = *orig_tuple; | 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 | /* 3) The per-protocol part of the manip is made to map into | 257 | /* 3) The per-protocol part of the manip is made to map into |
255 | the range to make a unique tuple. */ | 258 | the range to make a unique tuple. */ |
@@ -327,7 +330,8 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
327 | if (have_to_hash) { | 330 | if (have_to_hash) { |
328 | unsigned int srchash; | 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 | spin_lock_bh(&nf_nat_lock); | 335 | spin_lock_bh(&nf_nat_lock); |
332 | /* nf_conntrack_alter_reply might re-allocate exntension aera */ | 336 | /* nf_conntrack_alter_reply might re-allocate exntension aera */ |
333 | nat = nfct_nat(ct); | 337 | nat = nfct_nat(ct); |
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c index 9eb171056c63..4c060038d29f 100644 --- a/net/ipv4/netfilter/nf_nat_pptp.c +++ b/net/ipv4/netfilter/nf_nat_pptp.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <net/netfilter/nf_nat_rule.h> | 25 | #include <net/netfilter/nf_nat_rule.h> |
26 | #include <net/netfilter/nf_conntrack_helper.h> | 26 | #include <net/netfilter/nf_conntrack_helper.h> |
27 | #include <net/netfilter/nf_conntrack_expect.h> | 27 | #include <net/netfilter/nf_conntrack_expect.h> |
28 | #include <net/netfilter/nf_conntrack_zones.h> | ||
28 | #include <linux/netfilter/nf_conntrack_proto_gre.h> | 29 | #include <linux/netfilter/nf_conntrack_proto_gre.h> |
29 | #include <linux/netfilter/nf_conntrack_pptp.h> | 30 | #include <linux/netfilter/nf_conntrack_pptp.h> |
30 | 31 | ||
@@ -74,7 +75,7 @@ static void pptp_nat_expected(struct nf_conn *ct, | |||
74 | 75 | ||
75 | pr_debug("trying to unexpect other dir: "); | 76 | pr_debug("trying to unexpect other dir: "); |
76 | nf_ct_dump_tuple_ip(&t); | 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 | if (other_exp) { | 79 | if (other_exp) { |
79 | nf_ct_unexpect_related(other_exp); | 80 | nf_ct_unexpect_related(other_exp); |
80 | nf_ct_expect_put(other_exp); | 81 | nf_ct_expect_put(other_exp); |