diff options
-rw-r--r-- | include/linux/netfilter/xt_u32.h | 40 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 13 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/xt_u32.c | 135 |
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 | |||
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 */ | ||
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 | ||
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 | config NETFILTER_XT_MATCH_HASHLIMIT | 651 | config 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 | |||
72 | obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o | 72 | obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o |
73 | obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o | 73 | obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o |
74 | obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o | 74 | obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o |
75 | obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o | ||
75 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o | 76 | obj-$(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 | |||
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"); | ||