Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: sched: add ipset ematch

Can be used to match packets against netfilter ip sets created via ipset(8).
skb->sk_iif is used as 'incoming interface', skb->dev is 'outgoing interface'.

Since ipset is usually called from netfilter, the ematch
initializes a fake xt_action_param, pulls the ip header into the
linear area and also sets skb->data to the IP header (otherwise
matching Layer 4 set types doesn't work).

Tested-by: Mr Dash Four <mr.dash.four@googlemail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Florian Westphal and committed by
David S. Miller
6d4fa852 fa919833

+148 -1
+2 -1
include/linux/pkt_cls.h
··· 453 453 #define TCF_EM_TEXT 5 454 454 #define TCF_EM_VLAN 6 455 455 #define TCF_EM_CANID 7 456 - #define TCF_EM_MAX 7 456 + #define TCF_EM_IPSET 8 457 + #define TCF_EM_MAX 8 457 458 458 459 enum { 459 460 TCF_EM_PROG_TC
+10
net/sched/Kconfig
··· 517 517 To compile this code as a module, choose M here: the 518 518 module will be called em_canid. 519 519 520 + config NET_EMATCH_IPSET 521 + tristate "IPset" 522 + depends on NET_EMATCH && IP_SET 523 + ---help--- 524 + Say Y here if you want to be able to classify packets based on 525 + ipset membership. 526 + 527 + To compile this code as a module, choose M here: the 528 + module will be called em_ipset. 529 + 520 530 config NET_CLS_ACT 521 531 bool "Actions" 522 532 ---help---
+1
net/sched/Makefile
··· 56 56 obj-$(CONFIG_NET_EMATCH_META) += em_meta.o 57 57 obj-$(CONFIG_NET_EMATCH_TEXT) += em_text.o 58 58 obj-$(CONFIG_NET_EMATCH_CANID) += em_canid.o 59 + obj-$(CONFIG_NET_EMATCH_IPSET) += em_ipset.o
+135
net/sched/em_ipset.c
··· 1 + /* 2 + * net/sched/em_ipset.c ipset ematch 3 + * 4 + * Copyright (c) 2012 Florian Westphal <fw@strlen.de> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * version 2 as published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/gfp.h> 12 + #include <linux/module.h> 13 + #include <linux/types.h> 14 + #include <linux/kernel.h> 15 + #include <linux/string.h> 16 + #include <linux/skbuff.h> 17 + #include <linux/netfilter/xt_set.h> 18 + #include <linux/ipv6.h> 19 + #include <net/ip.h> 20 + #include <net/pkt_cls.h> 21 + 22 + static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len, 23 + struct tcf_ematch *em) 24 + { 25 + struct xt_set_info *set = data; 26 + ip_set_id_t index; 27 + 28 + if (data_len != sizeof(*set)) 29 + return -EINVAL; 30 + 31 + index = ip_set_nfnl_get_byindex(set->index); 32 + if (index == IPSET_INVALID_ID) 33 + return -ENOENT; 34 + 35 + em->datalen = sizeof(*set); 36 + em->data = (unsigned long)kmemdup(data, em->datalen, GFP_KERNEL); 37 + if (em->data) 38 + return 0; 39 + 40 + ip_set_nfnl_put(index); 41 + return -ENOMEM; 42 + } 43 + 44 + static void em_ipset_destroy(struct tcf_proto *p, struct tcf_ematch *em) 45 + { 46 + const struct xt_set_info *set = (const void *) em->data; 47 + if (set) { 48 + ip_set_nfnl_put(set->index); 49 + kfree((void *) em->data); 50 + } 51 + } 52 + 53 + static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em, 54 + struct tcf_pkt_info *info) 55 + { 56 + struct ip_set_adt_opt opt; 57 + struct xt_action_param acpar; 58 + const struct xt_set_info *set = (const void *) em->data; 59 + struct net_device *dev, *indev = NULL; 60 + int ret, network_offset; 61 + 62 + switch (skb->protocol) { 63 + case htons(ETH_P_IP): 64 + acpar.family = NFPROTO_IPV4; 65 + if (!pskb_network_may_pull(skb, sizeof(struct iphdr))) 66 + return 0; 67 + acpar.thoff = ip_hdrlen(skb); 68 + break; 69 + case htons(ETH_P_IPV6): 70 + acpar.family = NFPROTO_IPV6; 71 + if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) 72 + return 0; 73 + /* doesn't call ipv6_find_hdr() because ipset doesn't use thoff, yet */ 74 + acpar.thoff = sizeof(struct ipv6hdr); 75 + break; 76 + default: 77 + return 0; 78 + } 79 + 80 + acpar.hooknum = 0; 81 + 82 + opt.family = acpar.family; 83 + opt.dim = set->dim; 84 + opt.flags = set->flags; 85 + opt.cmdflags = 0; 86 + opt.timeout = ~0u; 87 + 88 + network_offset = skb_network_offset(skb); 89 + skb_pull(skb, network_offset); 90 + 91 + dev = skb->dev; 92 + 93 + rcu_read_lock(); 94 + 95 + if (dev && skb->skb_iif) 96 + indev = dev_get_by_index_rcu(dev_net(dev), skb->skb_iif); 97 + 98 + acpar.in = indev ? indev : dev; 99 + acpar.out = dev; 100 + 101 + ret = ip_set_test(set->index, skb, &acpar, &opt); 102 + 103 + rcu_read_unlock(); 104 + 105 + skb_push(skb, network_offset); 106 + return ret; 107 + } 108 + 109 + static struct tcf_ematch_ops em_ipset_ops = { 110 + .kind = TCF_EM_IPSET, 111 + .change = em_ipset_change, 112 + .destroy = em_ipset_destroy, 113 + .match = em_ipset_match, 114 + .owner = THIS_MODULE, 115 + .link = LIST_HEAD_INIT(em_ipset_ops.link) 116 + }; 117 + 118 + static int __init init_em_ipset(void) 119 + { 120 + return tcf_em_register(&em_ipset_ops); 121 + } 122 + 123 + static void __exit exit_em_ipset(void) 124 + { 125 + tcf_em_unregister(&em_ipset_ops); 126 + } 127 + 128 + MODULE_LICENSE("GPL"); 129 + MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); 130 + MODULE_DESCRIPTION("TC extended match for IP sets"); 131 + 132 + module_init(init_em_ipset); 133 + module_exit(exit_em_ipset); 134 + 135 + MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPSET);