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

[NETFILTER]: Add u32 match

Along comes... xt_u32, a revamped ipt_u32 from POM-NG,
Plus:

* 2007-06-02: added ipv6 support

* 2007-06-05: uses kmalloc for the big buffer

* 2007-06-05: added inversion

* 2007-06-20: use skb_copy_bits() and get rid of the big buffer
and lock (suggested by Pablo Neira Ayuso)

Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jan Engelhardt and committed by
David S. Miller
1b50b8a3 f4a607bf

+189
+40
include/linux/netfilter/xt_u32.h
··· 1 + #ifndef _XT_U32_H 2 + #define _XT_U32_H 1 3 + 4 + enum xt_u32_ops { 5 + XT_U32_AND, 6 + XT_U32_LEFTSH, 7 + XT_U32_RIGHTSH, 8 + XT_U32_AT, 9 + }; 10 + 11 + struct xt_u32_location_element { 12 + u_int32_t number; 13 + u_int8_t nextop; 14 + }; 15 + 16 + struct xt_u32_value_element { 17 + u_int32_t min; 18 + u_int32_t max; 19 + }; 20 + 21 + /* 22 + * Any way to allow for an arbitrary number of elements? 23 + * For now, I settle with a limit of 10 each. 24 + */ 25 + #define XT_U32_MAXSIZE 10 26 + 27 + struct xt_u32_test { 28 + struct xt_u32_location_element location[XT_U32_MAXSIZE+1]; 29 + struct xt_u32_value_element value[XT_U32_MAXSIZE+1]; 30 + u_int8_t nnums; 31 + u_int8_t nvalues; 32 + }; 33 + 34 + struct xt_u32 { 35 + struct xt_u32_test tests[XT_U32_MAXSIZE+1]; 36 + u_int8_t ntests; 37 + u_int8_t invert; 38 + }; 39 + 40 + #endif /* _XT_U32_H */
+13
net/netfilter/Kconfig
··· 635 635 636 636 To compile it as a module, choose M here. If unsure, say N. 637 637 638 + config NETFILTER_XT_MATCH_U32 639 + tristate '"u32" match support' 640 + depends on NETFILTER_XTABLES 641 + ---help--- 642 + u32 allows you to extract quantities of up to 4 bytes from a packet, 643 + AND them with specified masks, shift them by specified amounts and 644 + test whether the results are in any of a set of specified ranges. 645 + The specification of what to extract is general enough to skip over 646 + headers with lengths stored in the packet, as in IP or TCP header 647 + lengths. 648 + 649 + Details and examples are in the kernel module source. 650 + 638 651 config NETFILTER_XT_MATCH_HASHLIMIT 639 652 tristate '"hashlimit" match support' 640 653 depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
+1
net/netfilter/Makefile
··· 72 72 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o 73 73 obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o 74 74 obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o 75 + obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o 75 76 obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
+135
net/netfilter/xt_u32.c
··· 1 + /* 2 + * xt_u32 - kernel module to match u32 packet content 3 + * 4 + * Original author: Don Cohen <don@isis.cs3-inc.com> 5 + * © Jan Engelhardt <jengelh@gmx.de>, 2007 6 + */ 7 + 8 + #include <linux/module.h> 9 + #include <linux/moduleparam.h> 10 + #include <linux/spinlock.h> 11 + #include <linux/skbuff.h> 12 + #include <linux/types.h> 13 + #include <linux/netfilter/x_tables.h> 14 + #include <linux/netfilter/xt_u32.h> 15 + 16 + static bool u32_match_it(const struct xt_u32 *data, 17 + const struct sk_buff *skb) 18 + { 19 + const struct xt_u32_test *ct; 20 + unsigned int testind; 21 + unsigned int nnums; 22 + unsigned int nvals; 23 + unsigned int i; 24 + u_int32_t pos; 25 + u_int32_t val; 26 + u_int32_t at; 27 + int ret; 28 + 29 + /* 30 + * Small example: "0 >> 28 == 4 && 8 & 0xFF0000 >> 16 = 6, 17" 31 + * (=IPv4 and (TCP or UDP)). Outer loop runs over the "&&" operands. 32 + */ 33 + for (testind = 0; testind < data->ntests; ++testind) { 34 + ct = &data->tests[testind]; 35 + at = 0; 36 + pos = ct->location[0].number; 37 + 38 + if (skb->len < 4 || pos > skb->len - 4); 39 + return false; 40 + 41 + ret = skb_copy_bits(skb, pos, &val, sizeof(val)); 42 + BUG_ON(ret < 0); 43 + val = ntohl(val); 44 + nnums = ct->nnums; 45 + 46 + /* Inner loop runs over "&", "<<", ">>" and "@" operands */ 47 + for (i = 1; i < nnums; ++i) { 48 + u_int32_t number = ct->location[i].number; 49 + switch (ct->location[i].nextop) { 50 + case XT_U32_AND: 51 + val &= number; 52 + break; 53 + case XT_U32_LEFTSH: 54 + val <<= number; 55 + break; 56 + case XT_U32_RIGHTSH: 57 + val >>= number; 58 + break; 59 + case XT_U32_AT: 60 + if (at + val < at) 61 + return false; 62 + at += val; 63 + pos = number; 64 + if (at + 4 < at || skb->len < at + 4 || 65 + pos > skb->len - at - 4) 66 + return false; 67 + 68 + ret = skb_copy_bits(skb, at + pos, &val, 69 + sizeof(val)); 70 + BUG_ON(ret < 0); 71 + val = ntohl(val); 72 + break; 73 + } 74 + } 75 + 76 + /* Run over the "," and ":" operands */ 77 + nvals = ct->nvalues; 78 + for (i = 0; i < nvals; ++i) 79 + if (ct->value[i].min <= val && val <= ct->value[i].max) 80 + break; 81 + 82 + if (i >= ct->nvalues) 83 + return false; 84 + } 85 + 86 + return true; 87 + } 88 + 89 + static bool u32_match(const struct sk_buff *skb, 90 + const struct net_device *in, 91 + const struct net_device *out, 92 + const struct xt_match *match, const void *matchinfo, 93 + int offset, unsigned int protoff, bool *hotdrop) 94 + { 95 + const struct xt_u32 *data = matchinfo; 96 + bool ret; 97 + 98 + ret = u32_match_it(data, skb); 99 + return ret ^ data->invert; 100 + } 101 + 102 + static struct xt_match u32_reg[] = { 103 + { 104 + .name = "u32", 105 + .family = AF_INET, 106 + .match = u32_match, 107 + .matchsize = sizeof(struct xt_u32), 108 + .me = THIS_MODULE, 109 + }, 110 + { 111 + .name = "u32", 112 + .family = AF_INET6, 113 + .match = u32_match, 114 + .matchsize = sizeof(struct xt_u32), 115 + .me = THIS_MODULE, 116 + }, 117 + }; 118 + 119 + static int __init xt_u32_init(void) 120 + { 121 + return xt_register_matches(u32_reg, ARRAY_SIZE(u32_reg)); 122 + } 123 + 124 + static void __exit xt_u32_exit(void) 125 + { 126 + xt_unregister_matches(u32_reg, ARRAY_SIZE(u32_reg)); 127 + } 128 + 129 + module_init(xt_u32_init); 130 + module_exit(xt_u32_exit); 131 + MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>"); 132 + MODULE_DESCRIPTION("netfilter u32 match module"); 133 + MODULE_LICENSE("GPL"); 134 + MODULE_ALIAS("ipt_u32"); 135 + MODULE_ALIAS("ip6t_u32");