aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@gmx.de>2007-07-08 01:20:36 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-11 01:17:13 -0400
commit1b50b8a371e90a5e110f466e4ac02cf6b5f681de (patch)
treeedf2513fbfd707a089691487c007c142417ad3a1
parentf4a607bfae30d15aad46e75d2ed7a39f7ce7708b (diff)
[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>
-rw-r--r--include/linux/netfilter/xt_u32.h40
-rw-r--r--net/netfilter/Kconfig13
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/xt_u32.c135
4 files changed, 189 insertions, 0 deletions
diff --git a/include/linux/netfilter/xt_u32.h b/include/linux/netfilter/xt_u32.h
new file mode 100644
index 000000000000..9947f56cdbdd
--- /dev/null
+++ b/include/linux/netfilter/xt_u32.h
@@ -0,0 +1,40 @@
1#ifndef _XT_U32_H
2#define _XT_U32_H 1
3
4enum xt_u32_ops {
5 XT_U32_AND,
6 XT_U32_LEFTSH,
7 XT_U32_RIGHTSH,
8 XT_U32_AT,
9};
10
11struct xt_u32_location_element {
12 u_int32_t number;
13 u_int8_t nextop;
14};
15
16struct 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
27struct 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
34struct 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 */
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index a567dae8e5fd..aa567faa2a88 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -635,6 +635,19 @@ config NETFILTER_XT_MATCH_TCPMSS
635 635
636 To compile it as a module, choose M here. If unsure, say N. 636 To compile it as a module, choose M here. If unsure, say N.
637 637
638config 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
638config NETFILTER_XT_MATCH_HASHLIMIT 651config NETFILTER_XT_MATCH_HASHLIMIT
639 tristate '"hashlimit" match support' 652 tristate '"hashlimit" match support'
640 depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n) 653 depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index b2b5c7566b26..3cf5b9cd6fe1 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -72,4 +72,5 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
72obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o 72obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
73obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o 73obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
74obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o 74obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
75obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o
75obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o 76obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c
new file mode 100644
index 000000000000..07068751a35c
--- /dev/null
+++ b/net/netfilter/xt_u32.c
@@ -0,0 +1,135 @@
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
16static 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
89static 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
102static 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
119static int __init xt_u32_init(void)
120{
121 return xt_register_matches(u32_reg, ARRAY_SIZE(u32_reg));
122}
123
124static void __exit xt_u32_exit(void)
125{
126 xt_unregister_matches(u32_reg, ARRAY_SIZE(u32_reg));
127}
128
129module_init(xt_u32_init);
130module_exit(xt_u32_exit);
131MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
132MODULE_DESCRIPTION("netfilter u32 match module");
133MODULE_LICENSE("GPL");
134MODULE_ALIAS("ipt_u32");
135MODULE_ALIAS("ip6t_u32");