From patchwork Wed Jan 7 18:56:53 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 426376 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 33BCF1400B7 for ; Thu, 8 Jan 2015 05:54:11 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754088AbbAGSyK (ORCPT ); Wed, 7 Jan 2015 13:54:10 -0500 Received: from mail.us.es ([193.147.175.20]:57937 "EHLO mail.us.es" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753718AbbAGSyJ (ORCPT ); Wed, 7 Jan 2015 13:54:09 -0500 Received: (qmail 26129 invoked from network); 7 Jan 2015 19:54:06 +0100 Received: from unknown (HELO us.es) (192.168.2.11) by us.es with SMTP; 7 Jan 2015 19:54:06 +0100 Received: (qmail 12652 invoked by uid 507); 7 Jan 2015 18:54:06 -0000 X-Qmail-Scanner-Diagnostics: from 127.0.0.1 by antivirus1 (envelope-from , uid 501) with qmail-scanner-2.10 (clamdscan: 0.98.5/19892. spamassassin: 3.3.2. Clear:RC:1(127.0.0.1):SA:0(-103.2/7.5):. Processed in 2.248005 secs); 07 Jan 2015 18:54:06 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on antivirus1 X-Spam-Level: X-Spam-Status: No, score=-103.2 required=7.5 tests=BAYES_50,SMTPAUTH_US, SPF_HELO_FAIL,USER_IN_WHITELIST autolearn=disabled version=3.3.2 X-Spam-ASN: AS12715 87.216.0.0/16 X-Envelope-From: pneira@us.es Received: from unknown (HELO antivirus1) (127.0.0.1) by us.es with SMTP; 7 Jan 2015 18:54:04 -0000 Received: from 192.168.1.13 (192.168.1.13) by antivirus1 (F-Secure/fsigk_smtp/412/antivirus1); Wed, 07 Jan 2015 19:54:04 +0100 (CET) X-Virus-Status: clean(F-Secure/fsigk_smtp/412/antivirus1) Received: (qmail 15539 invoked from network); 7 Jan 2015 19:54:03 +0100 Received: from 129.166.216.87.static.jazztel.es (HELO us.es) (1984lsi@87.216.166.129) by mail.us.es with AES128-SHA encrypted SMTP; 7 Jan 2015 19:54:03 +0100 Date: Wed, 7 Jan 2015 19:56:53 +0100 From: Pablo Neira Ayuso To: Kristian Evensen Cc: netfilter-devel@vger.kernel.org Subject: Re: [PATCH v2 1/2] conntrack: Flush connections with a given mark Message-ID: <20150107185653.GA3469@salvia> References: <1419411431-24715-1-git-send-email-kristian.evensen@gmail.com> <1419411431-24715-2-git-send-email-kristian.evensen@gmail.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1419411431-24715-2-git-send-email-kristian.evensen@gmail.com> User-Agent: Mutt/1.5.21 (2010-09-15) Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Hi Kristian, On Wed, Dec 24, 2014 at 09:57:10AM +0100, Kristian Evensen wrote: > 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_apply_filter()-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. I'm attaching a revisited version of your patch, main changes are: 1) strict type checking in the dump case (for the ctnetlink_filter object), instead of relying on the genering void * to keep the ct_iterate happy. It adds a bit more code but I prefer it like this. 2) Explicitly reject mark filters when marks are not supported. This changes the previous behaviour, but I think this is good to have so userspace knows that what it is requesting is not support (instead of silently ignoring it). 3) add helper function to allocate the filter object, so this always needs explicit release. Please, have a look a it and let me know if you're fine with it. I'll pass it to net-next (upcoming 3.20). Thanks for your patience. From 2ee5d3941fd06694ddb945e2b96795e8693bfef1 Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Wed, 24 Dec 2014 09:57:10 +0100 Subject: [PATCH] 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_apply_filter()-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 Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 90 ++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 1bd9ed9..5df801a 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -749,13 +749,44 @@ static int ctnetlink_done(struct netlink_callback *cb) return 0; } -struct ctnetlink_dump_filter { +struct ctnetlink_filter { struct { u_int32_t val; u_int32_t mask; } 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; +#endif + return ERR_PTR(-EOPNOTSUPP); +} + +static int ctnetlink_filter(struct nf_conn *i, struct ctnetlink_filter *filter) +{ + if (filter == NULL) + return 0; + +#ifdef CONFIG_NF_CONNTRACK_MARK + if ((i->mark & filter->mark.mask) == filter->mark.val) + return 0; +#endif + + return 1; +} + static int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { @@ -768,10 +799,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) int res; spinlock_t *lockp; -#ifdef CONFIG_NF_CONNTRACK_MARK - const struct ctnetlink_dump_filter *filter = cb->data; -#endif - last = (struct nf_conn *)cb->args[1]; local_bh_disable(); @@ -798,12 +825,9 @@ restart: continue; cb->args[1] = 0; } -#ifdef CONFIG_NF_CONNTRACK_MARK - if (filter && !((ct->mark & filter->mark.mask) == - filter->mark.val)) { + if (ctnetlink_filter(ct, cb->data)) continue; - } -#endif + rcu_read_lock(); res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid, @@ -1001,6 +1025,29 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { .len = NF_CT_LABELS_MAX_SIZE }, }; +static int ctnl_flush_filter(struct nf_conn *i, void *data) +{ + return ctnetlink_filter(i, data) == 0; +} + +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, ctnl_flush_filter, filter, portid, report); + kfree(filter); + + return 0; +} + static int ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, @@ -1024,11 +1071,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, else if (cda[CTA_TUPLE_REPLY]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else { - /* Flush the whole table */ - nf_conntrack_flush_report(net, - NETLINK_CB(skb).portid, - nlmsg_report(nlh)); - return 0; + return ctnetlink_flush_conntrack(net, cda, + NETLINK_CB(skb).portid, + nlmsg_report(nlh)); } if (err < 0) @@ -1076,21 +1121,16 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, .dump = ctnetlink_dump_table, .done = ctnetlink_done, }; -#ifdef CONFIG_NF_CONNTRACK_MARK + if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { - struct ctnetlink_dump_filter *filter; + struct ctnetlink_filter *filter; - filter = kzalloc(sizeof(struct ctnetlink_dump_filter), - GFP_ATOMIC); - if (filter == NULL) - return -ENOMEM; + filter = ctnetlink_alloc_filter(cda); + if (IS_ERR(filter)) + return PTR_ERR(filter); - filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); - filter->mark.mask = - ntohl(nla_get_be32(cda[CTA_MARK_MASK])); c.data = filter; } -#endif return netlink_dump_start(ctnl, skb, nlh, &c); } -- 1.7.10.4