From patchwork Wed Jan 14 20:34:48 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: 429084 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 AC4D9140146 for ; Thu, 15 Jan 2015 07:32:19 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752115AbbANUcK (ORCPT ); Wed, 14 Jan 2015 15:32:10 -0500 Received: from mail.us.es ([193.147.175.20]:49663 "EHLO mail.us.es" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752261AbbANUcG (ORCPT ); Wed, 14 Jan 2015 15:32:06 -0500 Received: (qmail 28519 invoked from network); 14 Jan 2015 21:32:05 +0100 Received: from unknown (HELO us.es) (192.168.2.12) by us.es with SMTP; 14 Jan 2015 21:32:05 +0100 Received: (qmail 11800 invoked by uid 507); 14 Jan 2015 20:32:05 -0000 X-Qmail-Scanner-Diagnostics: from 127.0.0.1 by antivirus2 (envelope-from , uid 501) with qmail-scanner-2.10 (clamdscan: 0.98.5/19927. spamassassin: 3.4.0. Clear:RC:1(127.0.0.1):SA:0(-103.2/7.5):. Processed in 2.002417 secs); 14 Jan 2015 20:32:05 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on antivirus2 X-Spam-Level: X-Spam-Status: No, score=-103.2 required=7.5 tests=BAYES_50,SMTPAUTH_US, USER_IN_WHITELIST autolearn=disabled version=3.4.0 X-Spam-ASN: AS12715 87.216.0.0/16 X-Envelope-From: pablo@netfilter.org Received: from unknown (HELO antivirus2) (127.0.0.1) by us.es with SMTP; 14 Jan 2015 20:32:03 -0000 Received: from 192.168.1.13 (192.168.1.13) by antivirus2 (F-Secure/fsigk_smtp/412/antivirus2); Wed, 14 Jan 2015 21:32:03 +0100 (CET) X-Virus-Status: clean(F-Secure/fsigk_smtp/412/antivirus2) Received: (qmail 12883 invoked from network); 14 Jan 2015 21:32:02 +0100 Received: from 129.166.216.87.static.jazztel.es (HELO salvia.here) (pneira@us.es@87.216.166.129) by mail.us.es with SMTP; 14 Jan 2015 21:32:02 +0100 From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Cc: davem@davemloft.net, netdev@vger.kernel.org Subject: [PATCH 7/8] netfilter: conntrack: Flush connections with a given mark Date: Wed, 14 Jan 2015 21:34:48 +0100 Message-Id: <1421267689-24894-8-git-send-email-pablo@netfilter.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1421267689-24894-1-git-send-email-pablo@netfilter.org> References: <1421267689-24894-1-git-send-email-pablo@netfilter.org> Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: Kristian Evensen 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 Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 89 ++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 1bd9ed9..d1c2394 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -749,13 +749,47 @@ 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; +#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 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; 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 +828,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_match(ct, cb->data)) continue; - } -#endif + rcu_read_lock(); res = 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 }, }; +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 ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, @@ -1024,11 +1070,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 +1120,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); }