Re: [PATCH] netfilter: xtables: userspace notification target

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Jul 13, 2010 at 8:11 AM, Samuel Ortiz <sameo@xxxxxxxxxxxxxxx> 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@xxxxxxxxx>
> + *
> + * 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@xxxxxxxxx>
> + *
> + * 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@xxxxxxxxx>");
> +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@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Regards,
Changli Gao(xiaosuo@xxxxxxxxx)
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux