mirror of
https://github.com/fail0verflow/switch-linux.git
synced 2025-05-04 02:34:21 -04:00
netfilter: conntrack: Flush connections with a given mark
This patch adds support for selective flushing of conntrack mappings. By adding CTA_MARK and CTA_MARK_MASK to a delete-message, the mark (and mask) is checked before a connection is deleted while flushing. Configuring the flush is moved out of ctnetlink_del_conntrack(), and instead of calling nf_conntrack_flush_report(), we always call nf_ct_iterate_cleanup(). This enables us to only make one call from the new ctnetlink_flush_conntrack() and makes it easy to add more filter parameters. Filtering is done in the ctnetlink_filter_match()-function, which is also called from ctnetlink_dump_table(). ctnetlink_dump_filter has been renamed ctnetlink_filter, to indicated that it is no longer only used when dumping conntrack entries. Moreover, reject mark filters with -EOPNOTSUPP if no ct mark support is available. Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
b44b565cf5
commit
866476f323
1 changed files with 64 additions and 25 deletions
|
@ -749,13 +749,47 @@ static int ctnetlink_done(struct netlink_callback *cb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ctnetlink_dump_filter {
|
struct ctnetlink_filter {
|
||||||
struct {
|
struct {
|
||||||
u_int32_t val;
|
u_int32_t val;
|
||||||
u_int32_t mask;
|
u_int32_t mask;
|
||||||
} mark;
|
} mark;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ctnetlink_filter *
|
||||||
|
ctnetlink_alloc_filter(const struct nlattr * const cda[])
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_NF_CONNTRACK_MARK
|
||||||
|
struct ctnetlink_filter *filter;
|
||||||
|
|
||||||
|
filter = kzalloc(sizeof(*filter), GFP_KERNEL);
|
||||||
|
if (filter == NULL)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
|
||||||
|
filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
#else
|
||||||
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
|
||||||
|
{
|
||||||
|
struct ctnetlink_filter *filter = data;
|
||||||
|
|
||||||
|
if (filter == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NF_CONNTRACK_MARK
|
||||||
|
if ((ct->mark & filter->mark.mask) == filter->mark.val)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
{
|
{
|
||||||
|
@ -768,10 +802,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
int res;
|
int res;
|
||||||
spinlock_t *lockp;
|
spinlock_t *lockp;
|
||||||
|
|
||||||
#ifdef CONFIG_NF_CONNTRACK_MARK
|
|
||||||
const struct ctnetlink_dump_filter *filter = cb->data;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
last = (struct nf_conn *)cb->args[1];
|
last = (struct nf_conn *)cb->args[1];
|
||||||
|
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
|
@ -798,12 +828,9 @@ restart:
|
||||||
continue;
|
continue;
|
||||||
cb->args[1] = 0;
|
cb->args[1] = 0;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_NF_CONNTRACK_MARK
|
if (!ctnetlink_filter_match(ct, cb->data))
|
||||||
if (filter && !((ct->mark & filter->mark.mask) ==
|
|
||||||
filter->mark.val)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
res =
|
res =
|
||||||
ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
|
ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
|
||||||
|
@ -1001,6 +1028,25 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
|
||||||
.len = NF_CT_LABELS_MAX_SIZE },
|
.len = NF_CT_LABELS_MAX_SIZE },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int ctnetlink_flush_conntrack(struct net *net,
|
||||||
|
const struct nlattr * const cda[],
|
||||||
|
u32 portid, int report)
|
||||||
|
{
|
||||||
|
struct ctnetlink_filter *filter = NULL;
|
||||||
|
|
||||||
|
if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
|
||||||
|
filter = ctnetlink_alloc_filter(cda);
|
||||||
|
if (IS_ERR(filter))
|
||||||
|
return PTR_ERR(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
nf_ct_iterate_cleanup(net, ctnetlink_filter_match, filter,
|
||||||
|
portid, report);
|
||||||
|
kfree(filter);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
|
@ -1024,11 +1070,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
||||||
else if (cda[CTA_TUPLE_REPLY])
|
else if (cda[CTA_TUPLE_REPLY])
|
||||||
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
|
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
|
||||||
else {
|
else {
|
||||||
/* Flush the whole table */
|
return ctnetlink_flush_conntrack(net, cda,
|
||||||
nf_conntrack_flush_report(net,
|
|
||||||
NETLINK_CB(skb).portid,
|
NETLINK_CB(skb).portid,
|
||||||
nlmsg_report(nlh));
|
nlmsg_report(nlh));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -1076,21 +1120,16 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
||||||
.dump = ctnetlink_dump_table,
|
.dump = ctnetlink_dump_table,
|
||||||
.done = ctnetlink_done,
|
.done = ctnetlink_done,
|
||||||
};
|
};
|
||||||
#ifdef CONFIG_NF_CONNTRACK_MARK
|
|
||||||
if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
|
if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
|
||||||
struct ctnetlink_dump_filter *filter;
|
struct ctnetlink_filter *filter;
|
||||||
|
|
||||||
filter = kzalloc(sizeof(struct ctnetlink_dump_filter),
|
filter = ctnetlink_alloc_filter(cda);
|
||||||
GFP_ATOMIC);
|
if (IS_ERR(filter))
|
||||||
if (filter == NULL)
|
return PTR_ERR(filter);
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
|
|
||||||
filter->mark.mask =
|
|
||||||
ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
|
|
||||||
c.data = filter;
|
c.data = filter;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return netlink_dump_start(ctnl, skb, nlh, &c);
|
return netlink_dump_start(ctnl, skb, nlh, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue