Skip to content

Commit

Permalink
netfilter: xt_connlimit: honor conntrack zone if available
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
Florian Westphal authored and ummakynes committed Nov 17, 2014
1 parent 8225161 commit e59ea3d
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions net/netfilter/xt_connlimit.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ static bool add_hlist(struct hlist_head *head,
static unsigned int check_hlist(struct net *net,
struct hlist_head *head,
const struct nf_conntrack_tuple *tuple,
u16 zone,
bool *addit)
{
const struct nf_conntrack_tuple_hash *found;
Expand All @@ -147,8 +148,7 @@ static unsigned int check_hlist(struct net *net,

/* check the saved connections */
hlist_for_each_entry_safe(conn, n, head, node) {
found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE,
&conn->tuple);
found = nf_conntrack_find_get(net, zone, &conn->tuple);
if (found == NULL) {
hlist_del(&conn->node);
kmem_cache_free(connlimit_conn_cachep, conn);
Expand Down Expand Up @@ -201,7 +201,7 @@ static unsigned int
count_tree(struct net *net, struct rb_root *root,
const struct nf_conntrack_tuple *tuple,
const union nf_inet_addr *addr, const union nf_inet_addr *mask,
u8 family)
u8 family, u16 zone)
{
struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES];
struct rb_node **rbnode, *parent;
Expand Down Expand Up @@ -229,7 +229,7 @@ count_tree(struct net *net, struct rb_root *root,
} else {
/* same source network -> be counted! */
unsigned int count;
count = check_hlist(net, &rbconn->hhead, tuple, &addit);
count = check_hlist(net, &rbconn->hhead, tuple, zone, &addit);

tree_nodes_free(root, gc_nodes, gc_count);
if (!addit)
Expand All @@ -245,7 +245,7 @@ count_tree(struct net *net, struct rb_root *root,
continue;

/* only used for GC on hhead, retval and 'addit' ignored */
check_hlist(net, &rbconn->hhead, tuple, &addit);
check_hlist(net, &rbconn->hhead, tuple, zone, &addit);
if (hlist_empty(&rbconn->hhead))
gc_nodes[gc_count++] = rbconn;
}
Expand Down Expand Up @@ -290,7 +290,7 @@ static int count_them(struct net *net,
const struct nf_conntrack_tuple *tuple,
const union nf_inet_addr *addr,
const union nf_inet_addr *mask,
u_int8_t family)
u_int8_t family, u16 zone)
{
struct rb_root *root;
int count;
Expand All @@ -306,7 +306,7 @@ static int count_them(struct net *net,

spin_lock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]);

count = count_tree(net, root, tuple, addr, mask, family);
count = count_tree(net, root, tuple, addr, mask, family, zone);

spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]);

Expand All @@ -324,13 +324,16 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
enum ip_conntrack_info ctinfo;
const struct nf_conn *ct;
unsigned int connections;
u16 zone = NF_CT_DEFAULT_ZONE;

ct = nf_ct_get(skb, &ctinfo);
if (ct != NULL)
if (ct != NULL) {
tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
par->family, &tuple))
zone = nf_ct_zone(ct);
} else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
par->family, &tuple)) {
goto hotdrop;
}

if (par->family == NFPROTO_IPV6) {
const struct ipv6hdr *iph = ipv6_hdr(skb);
Expand All @@ -343,7 +346,7 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
}

connections = count_them(net, info->data, tuple_ptr, &addr,
&info->mask, par->family);
&info->mask, par->family, zone);
if (connections == 0)
/* kmalloc failed, drop it entirely */
goto hotdrop;
Expand Down

0 comments on commit e59ea3d

Please sign in to comment.