[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <AANLkTil2EgQbzUqYNHAYpIWJvyyE6AWq1TpvxrqVsD7k@mail.gmail.com>
Date: Tue, 13 Jul 2010 14:18:26 +0800
From: Changli Gao <xiaosuo@...il.com>
To: Samuel Ortiz <sameo@...ux.intel.com>
Cc: Patrick McHardy <kaber@...sh.net>,
"David S. Miller" <davem@...emloft.net>, netdev@...r.kernel.org,
netfilter-devel@...r.kernel.org,
Luciano Coelho <luciano.coelho@...ia.com>
Subject: Re: [PATCH] netfilter: xtables: userspace notification target
On Tue, Jul 13, 2010 at 8:11 AM, Samuel Ortiz <sameo@...ux.intel.com> wrote:
>
> The userspace notification Xtables target sends a netlink notification
> whenever a packet hits the target. Notifications have a label attribute
> for userspace to match it against a previously set rule. The rules also
> take a --all option to switch between sending a notification for all
> packets or for the first one only.
> Userspace can also send a netlink message to toggle this switch while the
> target is in place. This target uses the nefilter netlink framework.
>
> This target combined with various matches (quota, rateest, etc..) allows
> userspace to make decisions on interfaces handling. One could for example
> decide to switch between power saving modes depending on estimated rate
> thresholds.
>
It much like the following iptables rules.
iptables -N log_and_drop
iptables -A log_and_drop -j NFLOG --nflog-group 1 --nflog-prefix "log_and_drop"
iptables -A log_and_drop -j DROP
...
iptables ... -m quota --quota-bytes 20000 -j log_and_drop
...
> include/linux/netfilter/Kbuild | 1 +
> include/linux/netfilter/nfnetlink.h | 5 +-
> include/linux/netfilter/nfnetlink_compat.h | 1 +
> include/linux/netfilter/xt_NFNOTIF.h | 55 +++++
> net/netfilter/Kconfig | 17 ++
> net/netfilter/Makefile | 1 +
> net/netfilter/xt_NFNOTIF.c | 300 ++++++++++++++++++++++++++++
> 7 files changed, 379 insertions(+), 1 deletions(-)
> create mode 100644 include/linux/netfilter/xt_NFNOTIF.h
> create mode 100644 net/netfilter/xt_NFNOTIF.c
>
> diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
> index bb103f4..1b80b27 100644
> --- a/include/linux/netfilter/Kbuild
> +++ b/include/linux/netfilter/Kbuild
> @@ -12,6 +12,7 @@ header-y += xt_IDLETIMER.h
> header-y += xt_LED.h
> header-y += xt_MARK.h
> header-y += xt_NFLOG.h
> +header-y += xt_NFNOTIF.h
> header-y += xt_NFQUEUE.h
> header-y += xt_RATEEST.h
> header-y += xt_SECMARK.h
> diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
> index 361d6b5..e336f03 100644
> --- a/include/linux/netfilter/nfnetlink.h
> +++ b/include/linux/netfilter/nfnetlink.h
> @@ -18,6 +18,8 @@ enum nfnetlink_groups {
> #define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE
> NFNLGRP_CONNTRACK_EXP_DESTROY,
> #define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
> + NFNLGRP_NFNOTIF,
> +#define NFNLGRP_NFNOTIF NFNLGRP_NFNOTIF
> __NFNLGRP_MAX,
> };
> #define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
> @@ -47,7 +49,8 @@ struct nfgenmsg {
> #define NFNL_SUBSYS_QUEUE 3
> #define NFNL_SUBSYS_ULOG 4
> #define NFNL_SUBSYS_OSF 5
> -#define NFNL_SUBSYS_COUNT 6
> +#define NFNL_SUBSYS_NFNOTIF 6
> +#define NFNL_SUBSYS_COUNT 7
>
> #ifdef __KERNEL__
>
> diff --git a/include/linux/netfilter/nfnetlink_compat.h b/include/linux/netfilter/nfnetlink_compat.h
> index ffb9503..dca8ab2 100644
> --- a/include/linux/netfilter/nfnetlink_compat.h
> +++ b/include/linux/netfilter/nfnetlink_compat.h
> @@ -13,6 +13,7 @@
> #define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008
> #define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010
> #define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020
> +#define NF_NETLINK_NFNOTIF 0x00000040
>
> /* Generic structure for encapsulation optional netfilter information.
> * It is reminiscent of sockaddr, but with sa_family replaced
> diff --git a/include/linux/netfilter/xt_NFNOTIF.h b/include/linux/netfilter/xt_NFNOTIF.h
> new file mode 100644
> index 0000000..8fae827
> --- /dev/null
> +++ b/include/linux/netfilter/xt_NFNOTIF.h
> @@ -0,0 +1,55 @@
> +/*
> + * linux/include/linux/netfilter/xt_NFNOTIF.h
> + *
> + * Header file for Xtables notification target module.
> + *
> + * Copyright (C) 2010 Intel Corporation
> + * Samuel Ortiz <samuel.ortiz@...el.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +
> +#ifndef _XT_NFNOTIF_H
> +#define _XT_NFNOTIF_H
> +
> +#include <linux/types.h>
> +
> +enum nfnotif_msg_type {
> + NFNOTIF_TG_MSG_PACKETS,
> +
> + NFNOTIF_TG_MSG_MAX
> +};
> +
> +enum nfnotif_attr_type {
> + NFNOTIF_TG_ATTR_UNSPEC,
> + NFNOTIF_TG_ATTR_LABEL,
> + NFNOTIF_TG_ATTR_SEND_NOTIF,
> +
> + __NFNOTIF_TG_ATTR_AFTER_LAST
> +};
> +#define NFNOTIF_TG_ATTR_MAX (__NFNOTIF_TG_ATTR_AFTER_LAST - 1)
> +
> +#define MAX_NFNOTIF_LABEL_SIZE 31
> +
> +struct nfnotif_tg_info {
> + __u8 all_packets;
> +
> + char label[MAX_NFNOTIF_LABEL_SIZE];
> +
> + /* for kernel module internal use only */
> + struct nfnotif_tg *notif __attribute((aligned(8)));
> +};
> +
> +#endif
> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
> index aa2f106..0e2de36 100644
> --- a/net/netfilter/Kconfig
> +++ b/net/netfilter/Kconfig
> @@ -469,6 +469,23 @@ config NETFILTER_XT_TARGET_NFQUEUE
>
> To compile it as a module, choose M here. If unsure, say N.
>
> +config NETFILTER_XT_TARGET_NFNOTIF
> + tristate '"NFNOTIF" target Support'
> + depends on NETFILTER_ADVANCED
> + select NETFILTER_NETLINK
> + help
> +
> + This option adds the `NFNOTIF' target, which allows to send
> + netfilter netlink messages when packets hit the target.
> +
> + This target comes with an option to specify if one wants all
> + packets hitting the target to trigger the netlink message
> + transmission, or only the first one.
> + It also listen on its netfilter netlink subsystem for messages
> + allowing to reset the above option.
> +
> + To compile it as a module, choose M here. If unsure, say N.
> +
> config NETFILTER_XT_TARGET_NOTRACK
> tristate '"NOTRACK" target support'
> depends on IP_NF_RAW || IP6_NF_RAW
> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
> index e28420a..5d9c9e9 100644
> --- a/net/netfilter/Makefile
> +++ b/net/netfilter/Makefile
> @@ -62,6 +62,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
> obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o
> obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
> obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o
> +obj-$(CONFIG_NETFILTER_XT_TARGET_NFNOTIF) += xt_NFNOTIF.o
>
> # matches
> obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
> diff --git a/net/netfilter/xt_NFNOTIF.c b/net/netfilter/xt_NFNOTIF.c
> new file mode 100644
> index 0000000..e6e906b
> --- /dev/null
> +++ b/net/netfilter/xt_NFNOTIF.c
> @@ -0,0 +1,300 @@
> +/*
> + * linux/net/netfilter/xt_NFNOTIF.c
> + *
> + * Copyright (C) 2010 Intel Corporation
> + * Samuel Ortiz <samuel.ortiz@...el.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + *
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/list.h>
> +#include <linux/mutex.h>
> +#include <linux/netfilter.h>
> +#include <linux/netfilter/x_tables.h>
> +#include <linux/netfilter/nfnetlink.h>
> +#include <linux/netfilter/xt_NFNOTIF.h>
> +
> +struct nfnotif_tg {
> + struct list_head entry;
> + struct work_struct work;
> +
> + char *label;
> + __u8 all_packets;
> + struct net *net;
> +
> + __u8 send_notif;
> +
> + unsigned int refcnt;
> +};
> +
> +static LIST_HEAD(nfnotif_tg_list);
> +static DEFINE_MUTEX(list_mutex);
> +
> +static int __nfnotif_tg_netlink_send(struct nfnotif_tg *nfnotif)
> +{
> + struct nlmsghdr *nlh;
> + struct nfgenmsg *nfmsg;
> + struct sk_buff *skb;
> + struct net *net = nfnotif->net;
> + unsigned int type;
> + int flags;
> +
> + type = NFNL_SUBSYS_NFNOTIF << 8;
> + flags = NLM_F_CREATE;
> +
> + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> + if (skb == NULL)
> + goto error_out;
> +
> + nlh = nlmsg_put(skb, 0, 0, type, sizeof(*nfmsg), flags);
> + if (nlh == NULL)
> + goto nlmsg_put_failure;
> +
> + nfmsg = nlmsg_data(nlh);
> + nfmsg->version = NFNETLINK_V0;
> + nfmsg->res_id = 0;
> +
> + NLA_PUT_STRING(skb, NFNOTIF_TG_ATTR_LABEL, nfnotif->label);
> +
> + nlmsg_end(skb, nlh);
> +
> + return nfnetlink_send(skb, net, 0, NFNLGRP_NFNOTIF, 0, GFP_KERNEL);
> +
> +nla_put_failure:
> + nlmsg_cancel(skb, nlh);
> +
> +nlmsg_put_failure:
> + kfree_skb(skb);
> +
> +error_out:
> + return nfnetlink_set_err(net, 0, 0, -ENOBUFS);
> +}
> +
> +static void nfnotif_tg_work(struct work_struct *work)
> +{
> + struct nfnotif_tg *notif = container_of(work, struct nfnotif_tg, work);
> +
> +
> + if (__nfnotif_tg_netlink_send(notif) < 0)
> + pr_debug("Could not send notification");
> +
> + if (!notif->all_packets)
> + notif->send_notif = 0;
> +}
> +
> +static struct nfnotif_tg *__nfnotif_tg_find_by_label(const char *label)
> +{
> + struct nfnotif_tg *entry;
> +
> + BUG_ON(!label);
> +
> + list_for_each_entry(entry, &nfnotif_tg_list, entry) {
> + if (!strcmp(label, entry->label))
> + return entry;
> + }
> +
> + return NULL;
> +}
> +
> +static int nfnotif_tg_create(struct nfnotif_tg_info *info)
> +{
> + info->notif = kmalloc(sizeof(*info->notif), GFP_KERNEL);
> + if (!info->notif) {
> + pr_debug("Couldn't allocate notification\n");
> + return -ENOMEM;
> + }
> +
> + info->notif->label = kstrdup(info->label, GFP_KERNEL);
> + if (!info->notif->label) {
> + pr_debug("Couldn't allocate label\n");
> + kfree(info->notif);
> + return -ENOMEM;
> + }
> +
> + info->notif->all_packets = info->all_packets;
> + info->notif->send_notif = 1;
> +
> + list_add(&info->notif->entry, &nfnotif_tg_list);
> +
> + info->notif->refcnt = 1;
> +
> + INIT_WORK(&info->notif->work, nfnotif_tg_work);
> +
> + return 0;
> +}
> +
> +static unsigned int nfnotif_tg_target(struct sk_buff *skb,
> + const struct xt_action_param *par)
> +{
> + const struct nfnotif_tg_info *info = par->targinfo;
> +
> + BUG_ON(!info->notif);
> +
> + if (!info->notif->send_notif)
> + return XT_CONTINUE;
> +
> + pr_debug("Sending notification for %s\n", info->label);
> +
> + schedule_work(&info->notif->work);
> +
Why do you use another kernel activity: kernel thread? netlink
messages can be sent in atomic context.
> + return XT_CONTINUE;
> +}
> +
> +static int nfnotif_tg_checkentry(const struct xt_tgchk_param *par)
> +{
> + struct nfnotif_tg_info *info = par->targinfo;
> + int ret;
> +
> + pr_debug("Checkentry targinfo %s\n", info->label);
> +
> + if (info->label[0] == '\0' ||
> + strnlen(info->label,
> + MAX_NFNOTIF_LABEL_SIZE) == MAX_NFNOTIF_LABEL_SIZE) {
> + pr_debug("Label is empty or not nul-terminated\n");
> + return -EINVAL;
> + }
> +
> + mutex_lock(&list_mutex);
> +
> + info->notif = __nfnotif_tg_find_by_label(info->label);
> + if (info->notif) {
> + info->notif->refcnt++;
> +
> + pr_debug("Increased refcnt for %s to %u\n",
> + info->label, info->notif->refcnt);
> + } else {
> + ret = nfnotif_tg_create(info);
> + if (ret < 0) {
> + pr_debug("Failed to create notification\n");
> + mutex_unlock(&list_mutex);
> + return ret;
> + }
> + }
> +
> + info->notif->net = par->net;
> +
> + mutex_unlock(&list_mutex);
> + return 0;
> +}
> +
> +static void nfnotif_tg_destroy(const struct xt_tgdtor_param *par)
> +{
> + const struct nfnotif_tg_info *info = par->targinfo;
> +
> + pr_debug("Destroy targinfo %s\n", info->label);
> +
> + mutex_lock(&list_mutex);
> +
> + if (--info->notif->refcnt == 0) {
> + pr_debug("Deleting notification %s\n", info->label);
> +
> + list_del(&info->notif->entry);
> + kfree(info->notif->label);
> + kfree(info->notif);
> + }
> +
> + mutex_unlock(&list_mutex);
> +}
> +
> +static struct xt_target nfnotif_tg __read_mostly = {
> + .name = "NFNOTIF",
> + .family = NFPROTO_UNSPEC,
> + .target = nfnotif_tg_target,
> + .targetsize = sizeof(struct nfnotif_tg_info),
> + .checkentry = nfnotif_tg_checkentry,
> + .destroy = nfnotif_tg_destroy,
> + .me = THIS_MODULE,
> +};
> +
> +static int nfnotif_msg_send_notif(struct sock *nfnl, struct sk_buff *skb,
> + const struct nlmsghdr *nlh,
> + const struct nlattr * const attrs[])
> +{
> + struct nfnotif_tg *notif;
> + char *label;
> + u8 send_notif;
> +
> + if (attrs[NFNOTIF_TG_ATTR_LABEL] == NULL ||
> + attrs[NFNOTIF_TG_ATTR_SEND_NOTIF] == NULL)
> + return -EINVAL;
> +
> + label = nla_data(attrs[NFNOTIF_TG_ATTR_LABEL]);
> + send_notif = nla_get_u8(attrs[NFNOTIF_TG_ATTR_SEND_NOTIF]);
> +
> + pr_debug("Label %s send %d\n", label, send_notif);
> +
> + notif = __nfnotif_tg_find_by_label(label);
> + if (notif == NULL)
> + return -EINVAL;
> +
> + notif->send_notif = send_notif;
> +
> + return 0;
> +}
> +
> +
> +static const struct nla_policy nfnotif_nla_policy[NFNOTIF_TG_ATTR_MAX + 1] = {
> + [NFNOTIF_TG_ATTR_LABEL] = { .type = NLA_NUL_STRING },
> + [NFNOTIF_TG_ATTR_SEND_NOTIF] = { .type = NLA_U8 },
> +};
> +
> +static const struct nfnl_callback nfnotif_cb[NFNOTIF_TG_MSG_MAX] = {
> + [NFNOTIF_TG_MSG_PACKETS] = { .call = nfnotif_msg_send_notif,
> + .attr_count = NFNOTIF_TG_ATTR_MAX,
> + .policy = nfnotif_nla_policy },
> +};
> +
> +static const struct nfnetlink_subsystem nfnotif_subsys = {
> + .name = "nfnotif",
> + .subsys_id = NFNL_SUBSYS_NFNOTIF,
> + .cb_count = NFNOTIF_TG_MSG_MAX,
> + .cb = nfnotif_cb,
> +};
> +
> +static int __init nfnotif_tg_init(void)
> +{
> + int ret;
> +
> + ret = nfnetlink_subsys_register(&nfnotif_subsys);
> + if (ret < 0) {
> + pr_err("%s: Cannot register with nfnetlink\n", __func__);
> + return ret;
> + }
> +
> + ret = xt_register_target(&nfnotif_tg);
> + if (ret < 0) {
> + pr_err("%s: Cannot register target\n", __func__);
> + nfnetlink_subsys_unregister(&nfnotif_subsys);
> + }
> +
> + return ret;
> +}
> +
> +static void __exit nfnotif_tg_exit(void)
> +{
> + nfnetlink_subsys_unregister(&nfnotif_subsys);
> + xt_unregister_target(&nfnotif_tg);
> +}
> +
> +module_init(nfnotif_tg_init);
> +module_exit(nfnotif_tg_exit);
> +
> +MODULE_AUTHOR("Samuel Ortiz <samuel.ortiz@...el.com>");
> +MODULE_DESCRIPTION("Xtables: userspace notification");
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.1
>
> --
> Intel Open Source Technology Centre
> http://oss.intel.com/
> --
> To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Regards,
Changli Gao(xiaosuo@...il.com)
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists