Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
e59ea3df 82251615

+14 -11
+14 -11
net/netfilter/xt_connlimit.c
··· 134 134 static unsigned int check_hlist(struct net *net, 135 135 struct hlist_head *head, 136 136 const struct nf_conntrack_tuple *tuple, 137 + u16 zone, 137 138 bool *addit) 138 139 { 139 140 const struct nf_conntrack_tuple_hash *found; ··· 148 147 149 148 /* check the saved connections */ 150 149 hlist_for_each_entry_safe(conn, n, head, node) { 151 - found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE, 152 - &conn->tuple); 150 + found = nf_conntrack_find_get(net, zone, &conn->tuple); 153 151 if (found == NULL) { 154 152 hlist_del(&conn->node); 155 153 kmem_cache_free(connlimit_conn_cachep, conn); ··· 201 201 count_tree(struct net *net, struct rb_root *root, 202 202 const struct nf_conntrack_tuple *tuple, 203 203 const union nf_inet_addr *addr, const union nf_inet_addr *mask, 204 - u8 family) 204 + u8 family, u16 zone) 205 205 { 206 206 struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES]; 207 207 struct rb_node **rbnode, *parent; ··· 229 229 } else { 230 230 /* same source network -> be counted! */ 231 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 234 tree_nodes_free(root, gc_nodes, gc_count); 235 235 if (!addit) ··· 245 245 continue; 246 246 247 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 249 if (hlist_empty(&rbconn->hhead)) 250 250 gc_nodes[gc_count++] = rbconn; 251 251 } ··· 290 290 const struct nf_conntrack_tuple *tuple, 291 291 const union nf_inet_addr *addr, 292 292 const union nf_inet_addr *mask, 293 - u_int8_t family) 293 + u_int8_t family, u16 zone) 294 294 { 295 295 struct rb_root *root; 296 296 int count; ··· 306 306 307 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 311 spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); 312 312 ··· 324 324 enum ip_conntrack_info ctinfo; 325 325 const struct nf_conn *ct; 326 326 unsigned int connections; 327 + u16 zone = NF_CT_DEFAULT_ZONE; 327 328 328 329 ct = nf_ct_get(skb, &ctinfo); 329 - if (ct != NULL) 330 + if (ct != NULL) { 330 331 tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 331 - else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), 332 - par->family, &tuple)) 332 + zone = nf_ct_zone(ct); 333 + } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), 334 + par->family, &tuple)) { 333 335 goto hotdrop; 336 + } 334 337 335 338 if (par->family == NFPROTO_IPV6) { 336 339 const struct ipv6hdr *iph = ipv6_hdr(skb); ··· 346 343 } 347 344 348 345 connections = count_them(net, info->data, tuple_ptr, &addr, 349 - &info->mask, par->family); 346 + &info->mask, par->family, zone); 350 347 if (connections == 0) 351 348 /* kmalloc failed, drop it entirely */ 352 349 goto hotdrop;