From: Eyal Birger <e...@metanetworks.com> Allows classification based on the incoming IPSec policy used during decpsulation.
This allows similar matching capabilities to those provided by netfilter xt_policy module, and uses the same data strcuture - but from a tc entry point. Signed-off-by: Eyal Birger <e...@metanetworks.com> --- include/uapi/linux/pkt_cls.h | 3 +- net/sched/Kconfig | 10 ++++ net/sched/Makefile | 1 + net/sched/em_policy.c | 117 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 net/sched/em_policy.c diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 46c5066..963842c 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -555,7 +555,8 @@ enum { #define TCF_EM_VLAN 6 #define TCF_EM_CANID 7 #define TCF_EM_IPSET 8 -#define TCF_EM_MAX 8 +#define TCF_EM_POLICY 9 +#define TCF_EM_MAX 9 enum { TCF_EM_PROG_TC diff --git a/net/sched/Kconfig b/net/sched/Kconfig index c03d86a..0670f53 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -658,6 +658,16 @@ config NET_EMATCH_IPSET To compile this code as a module, choose M here: the module will be called em_ipset. +config NET_EMATCH_POLICY + tristate "Policy" + depends on NET_EMATCH && NETFILTER_XT_MATCH_POLICY + ---help--- + Say Y here if you want to be able to classify packets based on + IPsec policy that was used during decapsulation + + To compile this code as a module, choose M here: the + module will be called em_policy. + config NET_CLS_ACT bool "Actions" select NET_CLS diff --git a/net/sched/Makefile b/net/sched/Makefile index 5b63544..7ca02a1 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -75,3 +75,4 @@ obj-$(CONFIG_NET_EMATCH_META) += em_meta.o obj-$(CONFIG_NET_EMATCH_TEXT) += em_text.o obj-$(CONFIG_NET_EMATCH_CANID) += em_canid.o obj-$(CONFIG_NET_EMATCH_IPSET) += em_ipset.o +obj-$(CONFIG_NET_EMATCH_POLICY) += em_policy.o diff --git a/net/sched/em_policy.c b/net/sched/em_policy.c new file mode 100644 index 0000000..94ef318 --- /dev/null +++ b/net/sched/em_policy.c @@ -0,0 +1,117 @@ +/* + * net/sched/em_policy.c IPSec Policy Ematch + * + * (c) 2018 Eyal Birger <eyal.bir...@gmail.com> + * + * Parts taken from netfilter/xt_policy.h: + * Copyright (c) 2004,2005 Patrick McHardy, <ka...@trash.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/gfp.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/skbuff.h> +#include <linux/netfilter.h> +#include <linux/netfilter/xt_policy.h> +#include <net/pkt_cls.h> +#include <net/netfilter/xt_policy.h> + +static int em_policy_change(struct net *net, void *data, int data_len, + struct tcf_ematch *em) +{ + const struct xt_policy_info *info = (const void *)data; + __u16 dir_flags; + + if (data_len != sizeof(*info)) + return -EINVAL; + + if (info->len > XT_POLICY_MAX_ELEM) { + pr_info("too many policy elements\n"); + return -EINVAL; + } + + dir_flags = info->flags & (XT_POLICY_MATCH_IN | XT_POLICY_MATCH_OUT); + if (dir_flags != XT_POLICY_MATCH_IN) { + pr_info("Only incoming policy can be matched\n"); + return -EINVAL; + } + + em->datalen = sizeof(*info); + em->data = (unsigned long)kmemdup(data, em->datalen, GFP_KERNEL); + if (!em->data) + return -ENOMEM; + + return 0; +} + +static void em_policy_destroy(struct tcf_ematch *em) +{ + const struct xt_policy_info *info = (const void *)em->data; + + if (!info) + return; + + kfree((void *)em->data); +} + +static int em_policy_match(struct sk_buff *skb, struct tcf_ematch *em, + struct tcf_pkt_info *info) +{ + const struct xt_policy_info *pol = (const void *)em->data; + unsigned short pf; + int ret; + + switch (tc_skb_protocol(skb)) { + case htons(ETH_P_IP): + pf = NFPROTO_IPV4; + break; + case htons(ETH_P_IPV6): + pf = NFPROTO_IPV6; + break; + default: + return false; + } + + ret = xt_policy_match_policy_in(skb, pol, pf); + if (ret < 0) + ret = pol->flags & XT_POLICY_MATCH_NONE ? true : false; + else if (pol->flags & XT_POLICY_MATCH_NONE) + ret = false; + + return ret; +} + +static struct tcf_ematch_ops em_policy_ops = { + .kind = TCF_EM_POLICY, + .change = em_policy_change, + .destroy = em_policy_destroy, + .match = em_policy_match, + .owner = THIS_MODULE, + .link = LIST_HEAD_INIT(em_policy_ops.link) +}; + +static int __init init_em_policy(void) +{ + return tcf_em_register(&em_policy_ops); +} + +static void __exit exit_em_policy(void) +{ + tcf_em_unregister(&em_policy_ops); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eyal Birger <eyal.bir...@gmail.com>"); +MODULE_DESCRIPTION("TC extended match for IPSec policies"); + +module_init(init_em_policy); +module_exit(exit_em_policy); + +MODULE_ALIAS_TCF_EMATCH(TCF_EM_POLICY); -- 2.7.4