diff options
| author | Florian Westphal <fw@strlen.de> | 2014-11-14 07:21:48 -0500 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-11-17 06:44:20 -0500 |
| commit | e59ea3df3fc290b91c52a250c19091c18b4e6d7e (patch) | |
| tree | 20e3e6a02a4168c7af67285c96b369bdf31d1722 /net/netfilter | |
| parent | 8225161545a67bdb68cf86beafcdce1604720605 (diff) | |
netfilter: xt_connlimit: honor conntrack zone if available
Currently all the conntrack lookups are done using default zone.
In case the skb has a ct attached (e.g. template) we should use this zone
for lookups instead. This makes connlimit work with connections assigned
to other zones.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
| -rw-r--r-- | net/netfilter/xt_connlimit.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index fbc66bb250d5..29ba6218a820 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c | |||
| @@ -134,6 +134,7 @@ static bool add_hlist(struct hlist_head *head, | |||
| 134 | static unsigned int check_hlist(struct net *net, | 134 | static unsigned int check_hlist(struct net *net, |
| 135 | struct hlist_head *head, | 135 | struct hlist_head *head, |
| 136 | const struct nf_conntrack_tuple *tuple, | 136 | const struct nf_conntrack_tuple *tuple, |
| 137 | u16 zone, | ||
| 137 | bool *addit) | 138 | bool *addit) |
| 138 | { | 139 | { |
| 139 | const struct nf_conntrack_tuple_hash *found; | 140 | const struct nf_conntrack_tuple_hash *found; |
| @@ -147,8 +148,7 @@ static unsigned int check_hlist(struct net *net, | |||
| 147 | 148 | ||
| 148 | /* check the saved connections */ | 149 | /* check the saved connections */ |
| 149 | hlist_for_each_entry_safe(conn, n, head, node) { | 150 | hlist_for_each_entry_safe(conn, n, head, node) { |
| 150 | found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE, | 151 | found = nf_conntrack_find_get(net, zone, &conn->tuple); |
| 151 | &conn->tuple); | ||
| 152 | if (found == NULL) { | 152 | if (found == NULL) { |
| 153 | hlist_del(&conn->node); | 153 | hlist_del(&conn->node); |
| 154 | kmem_cache_free(connlimit_conn_cachep, conn); | 154 | kmem_cache_free(connlimit_conn_cachep, conn); |
| @@ -201,7 +201,7 @@ static unsigned int | |||
| 201 | count_tree(struct net *net, struct rb_root *root, | 201 | count_tree(struct net *net, struct rb_root *root, |
| 202 | const struct nf_conntrack_tuple *tuple, | 202 | const struct nf_conntrack_tuple *tuple, |
| 203 | const union nf_inet_addr *addr, const union nf_inet_addr *mask, | 203 | const union nf_inet_addr *addr, const union nf_inet_addr *mask, |
| 204 | u8 family) | 204 | u8 family, u16 zone) |
| 205 | { | 205 | { |
| 206 | struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES]; | 206 | struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES]; |
| 207 | struct rb_node **rbnode, *parent; | 207 | struct rb_node **rbnode, *parent; |
| @@ -229,7 +229,7 @@ count_tree(struct net *net, struct rb_root *root, | |||
| 229 | } else { | 229 | } else { |
| 230 | /* same source network -> be counted! */ | 230 | /* same source network -> be counted! */ |
| 231 | unsigned int count; | 231 | unsigned int count; |
| 232 | count = check_hlist(net, &rbconn->hhead, tuple, &addit); | 232 | count = check_hlist(net, &rbconn->hhead, tuple, zone, &addit); |
| 233 | 233 | ||
| 234 | tree_nodes_free(root, gc_nodes, gc_count); | 234 | tree_nodes_free(root, gc_nodes, gc_count); |
| 235 | if (!addit) | 235 | if (!addit) |
| @@ -245,7 +245,7 @@ count_tree(struct net *net, struct rb_root *root, | |||
| 245 | continue; | 245 | continue; |
| 246 | 246 | ||
| 247 | /* only used for GC on hhead, retval and 'addit' ignored */ | 247 | /* only used for GC on hhead, retval and 'addit' ignored */ |
| 248 | check_hlist(net, &rbconn->hhead, tuple, &addit); | 248 | check_hlist(net, &rbconn->hhead, tuple, zone, &addit); |
| 249 | if (hlist_empty(&rbconn->hhead)) | 249 | if (hlist_empty(&rbconn->hhead)) |
| 250 | gc_nodes[gc_count++] = rbconn; | 250 | gc_nodes[gc_count++] = rbconn; |
| 251 | } | 251 | } |
| @@ -290,7 +290,7 @@ static int count_them(struct net *net, | |||
| 290 | const struct nf_conntrack_tuple *tuple, | 290 | const struct nf_conntrack_tuple *tuple, |
| 291 | const union nf_inet_addr *addr, | 291 | const union nf_inet_addr *addr, |
| 292 | const union nf_inet_addr *mask, | 292 | const union nf_inet_addr *mask, |
| 293 | u_int8_t family) | 293 | u_int8_t family, u16 zone) |
| 294 | { | 294 | { |
| 295 | struct rb_root *root; | 295 | struct rb_root *root; |
| 296 | int count; | 296 | int count; |
| @@ -306,7 +306,7 @@ static int count_them(struct net *net, | |||
| 306 | 306 | ||
| 307 | spin_lock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); | 307 | spin_lock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); |
| 308 | 308 | ||
| 309 | count = count_tree(net, root, tuple, addr, mask, family); | 309 | count = count_tree(net, root, tuple, addr, mask, family, zone); |
| 310 | 310 | ||
| 311 | spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); | 311 | spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); |
| 312 | 312 | ||
| @@ -324,13 +324,16 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 324 | enum ip_conntrack_info ctinfo; | 324 | enum ip_conntrack_info ctinfo; |
| 325 | const struct nf_conn *ct; | 325 | const struct nf_conn *ct; |
| 326 | unsigned int connections; | 326 | unsigned int connections; |
| 327 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
| 327 | 328 | ||
| 328 | ct = nf_ct_get(skb, &ctinfo); | 329 | ct = nf_ct_get(skb, &ctinfo); |
| 329 | if (ct != NULL) | 330 | if (ct != NULL) { |
| 330 | tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | 331 | tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
| 331 | else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), | 332 | zone = nf_ct_zone(ct); |
| 332 | par->family, &tuple)) | 333 | } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), |
| 334 | par->family, &tuple)) { | ||
| 333 | goto hotdrop; | 335 | goto hotdrop; |
| 336 | } | ||
| 334 | 337 | ||
| 335 | if (par->family == NFPROTO_IPV6) { | 338 | if (par->family == NFPROTO_IPV6) { |
| 336 | const struct ipv6hdr *iph = ipv6_hdr(skb); | 339 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
| @@ -343,7 +346,7 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 343 | } | 346 | } |
| 344 | 347 | ||
| 345 | connections = count_them(net, info->data, tuple_ptr, &addr, | 348 | connections = count_them(net, info->data, tuple_ptr, &addr, |
| 346 | &info->mask, par->family); | 349 | &info->mask, par->family, zone); |
| 347 | if (connections == 0) | 350 | if (connections == 0) |
| 348 | /* kmalloc failed, drop it entirely */ | 351 | /* kmalloc failed, drop it entirely */ |
| 349 | goto hotdrop; | 352 | goto hotdrop; |
