diff options
author | Harald Welte <laforge@netfilter.org> | 2006-01-12 16:30:04 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-01-12 17:06:43 -0500 |
commit | 2e4e6a17af35be359cc8f1c924f8f198fbd478cc (patch) | |
tree | cb4b5438dcf9ff9d57518a26124308bcbfffd214 /net/netfilter | |
parent | 880b005f294454d989783d0984dc554dfe3c8214 (diff) |
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter')
27 files changed, 4316 insertions, 5 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 7d55f9cbd853..99c0a0fa4a97 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -103,3 +103,261 @@ config NF_CT_NETLINK | |||
103 | This option enables support for a netlink-based userspace interface | 103 | This option enables support for a netlink-based userspace interface |
104 | 104 | ||
105 | endmenu | 105 | endmenu |
106 | |||
107 | config NETFILTER_XTABLES | ||
108 | tristate "Netfilter Xtables support (required for ip_tables)" | ||
109 | help | ||
110 | This is required if you intend to use any of ip_tables, | ||
111 | ip6_tables or arp_tables. | ||
112 | |||
113 | # alphabetically ordered list of targets | ||
114 | |||
115 | config NETFILTER_XT_TARGET_CLASSIFY | ||
116 | tristate '"CLASSIFY" target support' | ||
117 | depends on NETFILTER_XTABLES | ||
118 | help | ||
119 | This option adds a `CLASSIFY' target, which enables the user to set | ||
120 | the priority of a packet. Some qdiscs can use this value for | ||
121 | classification, among these are: | ||
122 | |||
123 | atm, cbq, dsmark, pfifo_fast, htb, prio | ||
124 | |||
125 | To compile it as a module, choose M here. If unsure, say N. | ||
126 | |||
127 | config NETFILTER_XT_TARGET_CONNMARK | ||
128 | tristate '"CONNMARK" target support' | ||
129 | depends on NETFILTER_XTABLES | ||
130 | depends on IP_NF_MANGLE || IP6_NF_MANGLE | ||
131 | depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4) | ||
132 | help | ||
133 | This option adds a `CONNMARK' target, which allows one to manipulate | ||
134 | the connection mark value. Similar to the MARK target, but | ||
135 | affects the connection mark value rather than the packet mark value. | ||
136 | |||
137 | If you want to compile it as a module, say M here and read | ||
138 | <file:Documentation/modules.txt>. The module will be called | ||
139 | ipt_CONNMARK.o. If unsure, say `N'. | ||
140 | |||
141 | config NETFILTER_XT_TARGET_MARK | ||
142 | tristate '"MARK" target support' | ||
143 | depends on NETFILTER_XTABLES | ||
144 | help | ||
145 | This option adds a `MARK' target, which allows you to create rules | ||
146 | in the `mangle' table which alter the netfilter mark (nfmark) field | ||
147 | associated with the packet prior to routing. This can change | ||
148 | the routing method (see `Use netfilter MARK value as routing | ||
149 | key') and can also be used by other subsystems to change their | ||
150 | behavior. | ||
151 | |||
152 | To compile it as a module, choose M here. If unsure, say N. | ||
153 | |||
154 | config NETFILTER_XT_TARGET_NFQUEUE | ||
155 | tristate '"NFQUEUE" target Support' | ||
156 | depends on NETFILTER_XTABLES | ||
157 | help | ||
158 | This Target replaced the old obsolete QUEUE target. | ||
159 | |||
160 | As opposed to QUEUE, it supports 65535 different queues, | ||
161 | not just one. | ||
162 | |||
163 | To compile it as a module, choose M here. If unsure, say N. | ||
164 | |||
165 | config NETFILTER_XT_TARGET_NOTRACK | ||
166 | tristate '"NOTRACK" target support' | ||
167 | depends on NETFILTER_XTABLES | ||
168 | depends on IP_NF_RAW || IP6_NF_RAW | ||
169 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | ||
170 | help | ||
171 | The NOTRACK target allows a select rule to specify | ||
172 | which packets *not* to enter the conntrack/NAT | ||
173 | subsystem with all the consequences (no ICMP error tracking, | ||
174 | no protocol helpers for the selected packets). | ||
175 | |||
176 | If you want to compile it as a module, say M here and read | ||
177 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
178 | |||
179 | config NETFILTER_XT_MATCH_COMMENT | ||
180 | tristate '"comment" match support' | ||
181 | depends on NETFILTER_XTABLES | ||
182 | help | ||
183 | This option adds a `comment' dummy-match, which allows you to put | ||
184 | comments in your iptables ruleset. | ||
185 | |||
186 | If you want to compile it as a module, say M here and read | ||
187 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
188 | |||
189 | config NETFILTER_XT_MATCH_CONNBYTES | ||
190 | tristate '"connbytes" per-connection counter match support' | ||
191 | depends on NETFILTER_XTABLES | ||
192 | depends on (IP_NF_CONNTRACK && IP_NF_CT_ACCT) || NF_CT_ACCT | ||
193 | help | ||
194 | This option adds a `connbytes' match, which allows you to match the | ||
195 | number of bytes and/or packets for each direction within a connection. | ||
196 | |||
197 | If you want to compile it as a module, say M here and read | ||
198 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
199 | |||
200 | config NETFILTER_XT_MATCH_CONNMARK | ||
201 | tristate '"connmark" connection mark match support' | ||
202 | depends on NETFILTER_XTABLES | ||
203 | depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || NF_CONNTRACK_MARK | ||
204 | help | ||
205 | This option adds a `connmark' match, which allows you to match the | ||
206 | connection mark value previously set for the session by `CONNMARK'. | ||
207 | |||
208 | If you want to compile it as a module, say M here and read | ||
209 | <file:Documentation/modules.txt>. The module will be called | ||
210 | ipt_connmark.o. If unsure, say `N'. | ||
211 | |||
212 | config NETFILTER_XT_MATCH_CONNTRACK | ||
213 | tristate '"conntrack" connection tracking match support' | ||
214 | depends on NETFILTER_XTABLES | ||
215 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | ||
216 | help | ||
217 | This is a general conntrack match module, a superset of the state match. | ||
218 | |||
219 | It allows matching on additional conntrack information, which is | ||
220 | useful in complex configurations, such as NAT gateways with multiple | ||
221 | internet links or tunnels. | ||
222 | |||
223 | To compile it as a module, choose M here. If unsure, say N. | ||
224 | |||
225 | config NETFILTER_XT_MATCH_DCCP | ||
226 | tristate '"DCCP" protocol match support' | ||
227 | depends on NETFILTER_XTABLES | ||
228 | help | ||
229 | With this option enabled, you will be able to use the iptables | ||
230 | `dccp' match in order to match on DCCP source/destination ports | ||
231 | and DCCP flags. | ||
232 | |||
233 | If you want to compile it as a module, say M here and read | ||
234 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
235 | |||
236 | config NETFILTER_XT_MATCH_HELPER | ||
237 | tristate '"helper" match support' | ||
238 | depends on NETFILTER_XTABLES | ||
239 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | ||
240 | help | ||
241 | Helper matching allows you to match packets in dynamic connections | ||
242 | tracked by a conntrack-helper, ie. ip_conntrack_ftp | ||
243 | |||
244 | To compile it as a module, choose M here. If unsure, say Y. | ||
245 | |||
246 | config NETFILTER_XT_MATCH_LENGTH | ||
247 | tristate '"length" match support' | ||
248 | depends on NETFILTER_XTABLES | ||
249 | help | ||
250 | This option allows you to match the length of a packet against a | ||
251 | specific value or range of values. | ||
252 | |||
253 | To compile it as a module, choose M here. If unsure, say N. | ||
254 | |||
255 | config NETFILTER_XT_MATCH_LIMIT | ||
256 | tristate '"limit" match support' | ||
257 | depends on NETFILTER_XTABLES | ||
258 | help | ||
259 | limit matching allows you to control the rate at which a rule can be | ||
260 | matched: mainly useful in combination with the LOG target ("LOG | ||
261 | target support", below) and to avoid some Denial of Service attacks. | ||
262 | |||
263 | To compile it as a module, choose M here. If unsure, say N. | ||
264 | |||
265 | config NETFILTER_XT_MATCH_MAC | ||
266 | tristate '"mac" address match support' | ||
267 | depends on NETFILTER_XTABLES | ||
268 | help | ||
269 | MAC matching allows you to match packets based on the source | ||
270 | Ethernet address of the packet. | ||
271 | |||
272 | To compile it as a module, choose M here. If unsure, say N. | ||
273 | |||
274 | config NETFILTER_XT_MATCH_MARK | ||
275 | tristate '"mark" match support' | ||
276 | depends on NETFILTER_XTABLES | ||
277 | help | ||
278 | Netfilter mark matching allows you to match packets based on the | ||
279 | `nfmark' value in the packet. This can be set by the MARK target | ||
280 | (see below). | ||
281 | |||
282 | To compile it as a module, choose M here. If unsure, say N. | ||
283 | |||
284 | config NETFILTER_XT_MATCH_PHYSDEV | ||
285 | tristate '"physdev" match support' | ||
286 | depends on NETFILTER_XTABLES && BRIDGE_NETFILTER | ||
287 | help | ||
288 | Physdev packet matching matches against the physical bridge ports | ||
289 | the IP packet arrived on or will leave by. | ||
290 | |||
291 | To compile it as a module, choose M here. If unsure, say N. | ||
292 | |||
293 | config NETFILTER_XT_MATCH_PKTTYPE | ||
294 | tristate '"pkttype" packet type match support' | ||
295 | depends on NETFILTER_XTABLES | ||
296 | help | ||
297 | Packet type matching allows you to match a packet by | ||
298 | its "class", eg. BROADCAST, MULTICAST, ... | ||
299 | |||
300 | Typical usage: | ||
301 | iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG | ||
302 | |||
303 | To compile it as a module, choose M here. If unsure, say N. | ||
304 | |||
305 | config NETFILTER_XT_MATCH_REALM | ||
306 | tristate '"realm" match support' | ||
307 | depends on NETFILTER_XTABLES | ||
308 | select NET_CLS_ROUTE | ||
309 | help | ||
310 | This option adds a `realm' match, which allows you to use the realm | ||
311 | key from the routing subsystem inside iptables. | ||
312 | |||
313 | This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option | ||
314 | in tc world. | ||
315 | |||
316 | If you want to compile it as a module, say M here and read | ||
317 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
318 | |||
319 | config NETFILTER_XT_MATCH_SCTP | ||
320 | tristate '"sctp" protocol match support' | ||
321 | depends on NETFILTER_XTABLES | ||
322 | help | ||
323 | With this option enabled, you will be able to use the | ||
324 | `sctp' match in order to match on SCTP source/destination ports | ||
325 | and SCTP chunk types. | ||
326 | |||
327 | If you want to compile it as a module, say M here and read | ||
328 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
329 | |||
330 | config NETFILTER_XT_MATCH_STATE | ||
331 | tristate '"state" match support' | ||
332 | depends on NETFILTER_XTABLES | ||
333 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | ||
334 | help | ||
335 | Connection state matching allows you to match packets based on their | ||
336 | relationship to a tracked connection (ie. previous packets). This | ||
337 | is a powerful tool for packet classification. | ||
338 | |||
339 | To compile it as a module, choose M here. If unsure, say N. | ||
340 | |||
341 | config NETFILTER_XT_MATCH_STRING | ||
342 | tristate '"string" match support' | ||
343 | depends on NETFILTER_XTABLES | ||
344 | select TEXTSEARCH | ||
345 | select TEXTSEARCH_KMP | ||
346 | select TEXTSEARCH_BM | ||
347 | select TEXTSEARCH_FSM | ||
348 | help | ||
349 | This option adds a `string' match, which allows you to look for | ||
350 | pattern matchings in packets. | ||
351 | |||
352 | To compile it as a module, choose M here. If unsure, say N. | ||
353 | |||
354 | config NETFILTER_XT_MATCH_TCPMSS | ||
355 | tristate '"tcpmss" match support' | ||
356 | depends on NETFILTER_XTABLES | ||
357 | help | ||
358 | This option adds a `tcpmss' match, which allows you to examine the | ||
359 | MSS value of TCP SYN packets, which control the maximum packet size | ||
360 | for that connection. | ||
361 | |||
362 | To compile it as a module, choose M here. If unsure, say N. | ||
363 | |||
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index cb2183145c37..746172ebc91b 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o | 1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o |
2 | nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o | ||
2 | 3 | ||
3 | obj-$(CONFIG_NETFILTER) = netfilter.o | 4 | obj-$(CONFIG_NETFILTER) = netfilter.o |
4 | 5 | ||
@@ -6,13 +7,43 @@ obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o | |||
6 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o | 7 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o |
7 | obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o | 8 | obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o |
8 | 9 | ||
9 | nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o | 10 | # connection tracking |
10 | |||
11 | obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o | 11 | obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o |
12 | obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o | ||
13 | 12 | ||
14 | # SCTP protocol connection tracking | 13 | # SCTP protocol connection tracking |
15 | obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o | 14 | obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o |
16 | 15 | ||
17 | # netlink interface for nf_conntrack | 16 | # netlink interface for nf_conntrack |
18 | obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o | 17 | obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o |
18 | |||
19 | # connection tracking helpers | ||
20 | obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o | ||
21 | |||
22 | # generic X tables | ||
23 | obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o | ||
24 | |||
25 | # targets | ||
26 | obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o | ||
27 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o | ||
28 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o | ||
29 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o | ||
30 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o | ||
31 | |||
32 | # matches | ||
33 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o | ||
34 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o | ||
35 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o | ||
36 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o | ||
37 | obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o | ||
38 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o | ||
39 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o | ||
40 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o | ||
41 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o | ||
42 | obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o | ||
43 | obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o | ||
44 | obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o | ||
45 | obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o | ||
46 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o | ||
47 | obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o | ||
48 | obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o | ||
49 | obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o | ||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 3531d142f693..617599aeeead 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -821,7 +821,7 @@ module_exit(fini); | |||
821 | 821 | ||
822 | /* Some modules need us, but don't depend directly on any symbol. | 822 | /* Some modules need us, but don't depend directly on any symbol. |
823 | They should call this. */ | 823 | They should call this. */ |
824 | void need_nf_conntrack(void) | 824 | void need_conntrack(void) |
825 | { | 825 | { |
826 | } | 826 | } |
827 | 827 | ||
@@ -841,7 +841,7 @@ EXPORT_SYMBOL(nf_conntrack_protocol_unregister); | |||
841 | EXPORT_SYMBOL(nf_ct_invert_tuplepr); | 841 | EXPORT_SYMBOL(nf_ct_invert_tuplepr); |
842 | EXPORT_SYMBOL(nf_conntrack_alter_reply); | 842 | EXPORT_SYMBOL(nf_conntrack_alter_reply); |
843 | EXPORT_SYMBOL(nf_conntrack_destroyed); | 843 | EXPORT_SYMBOL(nf_conntrack_destroyed); |
844 | EXPORT_SYMBOL(need_nf_conntrack); | 844 | EXPORT_SYMBOL(need_conntrack); |
845 | EXPORT_SYMBOL(nf_conntrack_helper_register); | 845 | EXPORT_SYMBOL(nf_conntrack_helper_register); |
846 | EXPORT_SYMBOL(nf_conntrack_helper_unregister); | 846 | EXPORT_SYMBOL(nf_conntrack_helper_unregister); |
847 | EXPORT_SYMBOL(nf_ct_iterate_cleanup); | 847 | EXPORT_SYMBOL(nf_ct_iterate_cleanup); |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c new file mode 100644 index 000000000000..d7817afc6b96 --- /dev/null +++ b/net/netfilter/x_tables.c | |||
@@ -0,0 +1,624 @@ | |||
1 | /* | ||
2 | * x_tables core - Backend for {ip,ip6,arp}_tables | ||
3 | * | ||
4 | * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org> | ||
5 | * | ||
6 | * Based on existing ip_tables code which is | ||
7 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling | ||
8 | * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/socket.h> | ||
19 | #include <linux/net.h> | ||
20 | #include <linux/proc_fs.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/vmalloc.h> | ||
24 | |||
25 | #include <linux/netfilter/x_tables.h> | ||
26 | #include <linux/netfilter_arp.h> | ||
27 | |||
28 | MODULE_LICENSE("GPL"); | ||
29 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
30 | MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module"); | ||
31 | |||
32 | #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) | ||
33 | |||
34 | struct xt_af { | ||
35 | struct semaphore mutex; | ||
36 | struct list_head match; | ||
37 | struct list_head target; | ||
38 | struct list_head tables; | ||
39 | }; | ||
40 | |||
41 | static struct xt_af *xt; | ||
42 | |||
43 | #ifdef DEBUG_IP_FIREWALL_USER | ||
44 | #define duprintf(format, args...) printk(format , ## args) | ||
45 | #else | ||
46 | #define duprintf(format, args...) | ||
47 | #endif | ||
48 | |||
49 | enum { | ||
50 | TABLE, | ||
51 | TARGET, | ||
52 | MATCH, | ||
53 | }; | ||
54 | |||
55 | /* Registration hooks for targets. */ | ||
56 | int | ||
57 | xt_register_target(int af, struct xt_target *target) | ||
58 | { | ||
59 | int ret; | ||
60 | |||
61 | ret = down_interruptible(&xt[af].mutex); | ||
62 | if (ret != 0) | ||
63 | return ret; | ||
64 | list_add(&target->list, &xt[af].target); | ||
65 | up(&xt[af].mutex); | ||
66 | return ret; | ||
67 | } | ||
68 | EXPORT_SYMBOL(xt_register_target); | ||
69 | |||
70 | void | ||
71 | xt_unregister_target(int af, struct xt_target *target) | ||
72 | { | ||
73 | down(&xt[af].mutex); | ||
74 | LIST_DELETE(&xt[af].target, target); | ||
75 | up(&xt[af].mutex); | ||
76 | } | ||
77 | EXPORT_SYMBOL(xt_unregister_target); | ||
78 | |||
79 | int | ||
80 | xt_register_match(int af, struct xt_match *match) | ||
81 | { | ||
82 | int ret; | ||
83 | |||
84 | ret = down_interruptible(&xt[af].mutex); | ||
85 | if (ret != 0) | ||
86 | return ret; | ||
87 | |||
88 | list_add(&match->list, &xt[af].match); | ||
89 | up(&xt[af].mutex); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | EXPORT_SYMBOL(xt_register_match); | ||
94 | |||
95 | void | ||
96 | xt_unregister_match(int af, struct xt_match *match) | ||
97 | { | ||
98 | down(&xt[af].mutex); | ||
99 | LIST_DELETE(&xt[af].match, match); | ||
100 | up(&xt[af].mutex); | ||
101 | } | ||
102 | EXPORT_SYMBOL(xt_unregister_match); | ||
103 | |||
104 | |||
105 | /* | ||
106 | * These are weird, but module loading must not be done with mutex | ||
107 | * held (since they will register), and we have to have a single | ||
108 | * function to use try_then_request_module(). | ||
109 | */ | ||
110 | |||
111 | /* Find match, grabs ref. Returns ERR_PTR() on error. */ | ||
112 | struct xt_match *xt_find_match(int af, const char *name, u8 revision) | ||
113 | { | ||
114 | struct xt_match *m; | ||
115 | int err = 0; | ||
116 | |||
117 | if (down_interruptible(&xt[af].mutex) != 0) | ||
118 | return ERR_PTR(-EINTR); | ||
119 | |||
120 | list_for_each_entry(m, &xt[af].match, list) { | ||
121 | if (strcmp(m->name, name) == 0) { | ||
122 | if (m->revision == revision) { | ||
123 | if (try_module_get(m->me)) { | ||
124 | up(&xt[af].mutex); | ||
125 | return m; | ||
126 | } | ||
127 | } else | ||
128 | err = -EPROTOTYPE; /* Found something. */ | ||
129 | } | ||
130 | } | ||
131 | up(&xt[af].mutex); | ||
132 | return ERR_PTR(err); | ||
133 | } | ||
134 | EXPORT_SYMBOL(xt_find_match); | ||
135 | |||
136 | /* Find target, grabs ref. Returns ERR_PTR() on error. */ | ||
137 | struct xt_target *xt_find_target(int af, const char *name, u8 revision) | ||
138 | { | ||
139 | struct xt_target *t; | ||
140 | int err = 0; | ||
141 | |||
142 | if (down_interruptible(&xt[af].mutex) != 0) | ||
143 | return ERR_PTR(-EINTR); | ||
144 | |||
145 | list_for_each_entry(t, &xt[af].target, list) { | ||
146 | if (strcmp(t->name, name) == 0) { | ||
147 | if (t->revision == revision) { | ||
148 | if (try_module_get(t->me)) { | ||
149 | up(&xt[af].mutex); | ||
150 | return t; | ||
151 | } | ||
152 | } else | ||
153 | err = -EPROTOTYPE; /* Found something. */ | ||
154 | } | ||
155 | } | ||
156 | up(&xt[af].mutex); | ||
157 | return ERR_PTR(err); | ||
158 | } | ||
159 | EXPORT_SYMBOL(xt_find_target); | ||
160 | |||
161 | static const char *xt_prefix[NPROTO] = { | ||
162 | [AF_INET] = "ipt_%s", | ||
163 | [AF_INET6] = "ip6t_%s", | ||
164 | [NF_ARP] = "arpt_%s", | ||
165 | }; | ||
166 | |||
167 | struct xt_target *xt_request_find_target(int af, const char *name, u8 revision) | ||
168 | { | ||
169 | struct xt_target *target; | ||
170 | |||
171 | target = try_then_request_module(xt_find_target(af, name, revision), | ||
172 | xt_prefix[af], name); | ||
173 | if (IS_ERR(target) || !target) | ||
174 | return NULL; | ||
175 | return target; | ||
176 | } | ||
177 | EXPORT_SYMBOL_GPL(xt_request_find_target); | ||
178 | |||
179 | static int match_revfn(int af, const char *name, u8 revision, int *bestp) | ||
180 | { | ||
181 | struct xt_match *m; | ||
182 | int have_rev = 0; | ||
183 | |||
184 | list_for_each_entry(m, &xt[af].match, list) { | ||
185 | if (strcmp(m->name, name) == 0) { | ||
186 | if (m->revision > *bestp) | ||
187 | *bestp = m->revision; | ||
188 | if (m->revision == revision) | ||
189 | have_rev = 1; | ||
190 | } | ||
191 | } | ||
192 | return have_rev; | ||
193 | } | ||
194 | |||
195 | static int target_revfn(int af, const char *name, u8 revision, int *bestp) | ||
196 | { | ||
197 | struct xt_target *t; | ||
198 | int have_rev = 0; | ||
199 | |||
200 | list_for_each_entry(t, &xt[af].target, list) { | ||
201 | if (strcmp(t->name, name) == 0) { | ||
202 | if (t->revision > *bestp) | ||
203 | *bestp = t->revision; | ||
204 | if (t->revision == revision) | ||
205 | have_rev = 1; | ||
206 | } | ||
207 | } | ||
208 | return have_rev; | ||
209 | } | ||
210 | |||
211 | /* Returns true or false (if no such extension at all) */ | ||
212 | int xt_find_revision(int af, const char *name, u8 revision, int target, | ||
213 | int *err) | ||
214 | { | ||
215 | int have_rev, best = -1; | ||
216 | |||
217 | if (down_interruptible(&xt[af].mutex) != 0) { | ||
218 | *err = -EINTR; | ||
219 | return 1; | ||
220 | } | ||
221 | if (target == 1) | ||
222 | have_rev = target_revfn(af, name, revision, &best); | ||
223 | else | ||
224 | have_rev = match_revfn(af, name, revision, &best); | ||
225 | up(&xt[af].mutex); | ||
226 | |||
227 | /* Nothing at all? Return 0 to try loading module. */ | ||
228 | if (best == -1) { | ||
229 | *err = -ENOENT; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | *err = best; | ||
234 | if (!have_rev) | ||
235 | *err = -EPROTONOSUPPORT; | ||
236 | return 1; | ||
237 | } | ||
238 | EXPORT_SYMBOL_GPL(xt_find_revision); | ||
239 | |||
240 | struct xt_table_info *xt_alloc_table_info(unsigned int size) | ||
241 | { | ||
242 | struct xt_table_info *newinfo; | ||
243 | int cpu; | ||
244 | |||
245 | /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ | ||
246 | if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages) | ||
247 | return NULL; | ||
248 | |||
249 | newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL); | ||
250 | if (!newinfo) | ||
251 | return NULL; | ||
252 | |||
253 | newinfo->size = size; | ||
254 | |||
255 | for_each_cpu(cpu) { | ||
256 | if (size <= PAGE_SIZE) | ||
257 | newinfo->entries[cpu] = kmalloc_node(size, | ||
258 | GFP_KERNEL, | ||
259 | cpu_to_node(cpu)); | ||
260 | else | ||
261 | newinfo->entries[cpu] = vmalloc_node(size, | ||
262 | cpu_to_node(cpu)); | ||
263 | |||
264 | if (newinfo->entries[cpu] == NULL) { | ||
265 | xt_free_table_info(newinfo); | ||
266 | return NULL; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | return newinfo; | ||
271 | } | ||
272 | EXPORT_SYMBOL(xt_alloc_table_info); | ||
273 | |||
274 | void xt_free_table_info(struct xt_table_info *info) | ||
275 | { | ||
276 | int cpu; | ||
277 | |||
278 | for_each_cpu(cpu) { | ||
279 | if (info->size <= PAGE_SIZE) | ||
280 | kfree(info->entries[cpu]); | ||
281 | else | ||
282 | vfree(info->entries[cpu]); | ||
283 | } | ||
284 | kfree(info); | ||
285 | } | ||
286 | EXPORT_SYMBOL(xt_free_table_info); | ||
287 | |||
288 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ | ||
289 | struct xt_table *xt_find_table_lock(int af, const char *name) | ||
290 | { | ||
291 | struct xt_table *t; | ||
292 | |||
293 | if (down_interruptible(&xt[af].mutex) != 0) | ||
294 | return ERR_PTR(-EINTR); | ||
295 | |||
296 | list_for_each_entry(t, &xt[af].tables, list) | ||
297 | if (strcmp(t->name, name) == 0 && try_module_get(t->me)) | ||
298 | return t; | ||
299 | up(&xt[af].mutex); | ||
300 | return NULL; | ||
301 | } | ||
302 | EXPORT_SYMBOL_GPL(xt_find_table_lock); | ||
303 | |||
304 | void xt_table_unlock(struct xt_table *table) | ||
305 | { | ||
306 | up(&xt[table->af].mutex); | ||
307 | } | ||
308 | EXPORT_SYMBOL_GPL(xt_table_unlock); | ||
309 | |||
310 | |||
311 | struct xt_table_info * | ||
312 | xt_replace_table(struct xt_table *table, | ||
313 | unsigned int num_counters, | ||
314 | struct xt_table_info *newinfo, | ||
315 | int *error) | ||
316 | { | ||
317 | struct xt_table_info *oldinfo, *private; | ||
318 | |||
319 | /* Do the substitution. */ | ||
320 | write_lock_bh(&table->lock); | ||
321 | private = table->private; | ||
322 | /* Check inside lock: is the old number correct? */ | ||
323 | if (num_counters != private->number) { | ||
324 | duprintf("num_counters != table->private->number (%u/%u)\n", | ||
325 | num_counters, private->number); | ||
326 | write_unlock_bh(&table->lock); | ||
327 | *error = -EAGAIN; | ||
328 | return NULL; | ||
329 | } | ||
330 | oldinfo = private; | ||
331 | table->private = newinfo; | ||
332 | newinfo->initial_entries = oldinfo->initial_entries; | ||
333 | write_unlock_bh(&table->lock); | ||
334 | |||
335 | return oldinfo; | ||
336 | } | ||
337 | EXPORT_SYMBOL_GPL(xt_replace_table); | ||
338 | |||
339 | int xt_register_table(struct xt_table *table, | ||
340 | struct xt_table_info *bootstrap, | ||
341 | struct xt_table_info *newinfo) | ||
342 | { | ||
343 | int ret; | ||
344 | struct xt_table_info *private; | ||
345 | |||
346 | ret = down_interruptible(&xt[table->af].mutex); | ||
347 | if (ret != 0) | ||
348 | return ret; | ||
349 | |||
350 | /* Don't autoload: we'd eat our tail... */ | ||
351 | if (list_named_find(&xt[table->af].tables, table->name)) { | ||
352 | ret = -EEXIST; | ||
353 | goto unlock; | ||
354 | } | ||
355 | |||
356 | /* Simplifies replace_table code. */ | ||
357 | table->private = bootstrap; | ||
358 | if (!xt_replace_table(table, 0, newinfo, &ret)) | ||
359 | goto unlock; | ||
360 | |||
361 | private = table->private; | ||
362 | duprintf("table->private->number = %u\n", private->number); | ||
363 | |||
364 | /* save number of initial entries */ | ||
365 | private->initial_entries = private->number; | ||
366 | |||
367 | rwlock_init(&table->lock); | ||
368 | list_prepend(&xt[table->af].tables, table); | ||
369 | |||
370 | ret = 0; | ||
371 | unlock: | ||
372 | up(&xt[table->af].mutex); | ||
373 | return ret; | ||
374 | } | ||
375 | EXPORT_SYMBOL_GPL(xt_register_table); | ||
376 | |||
377 | void *xt_unregister_table(struct xt_table *table) | ||
378 | { | ||
379 | struct xt_table_info *private; | ||
380 | |||
381 | down(&xt[table->af].mutex); | ||
382 | private = table->private; | ||
383 | LIST_DELETE(&xt[table->af].tables, table); | ||
384 | up(&xt[table->af].mutex); | ||
385 | |||
386 | return private; | ||
387 | } | ||
388 | EXPORT_SYMBOL_GPL(xt_unregister_table); | ||
389 | |||
390 | #ifdef CONFIG_PROC_FS | ||
391 | static char *xt_proto_prefix[NPROTO] = { | ||
392 | [AF_INET] = "ip", | ||
393 | [AF_INET6] = "ip6", | ||
394 | [NF_ARP] = "arp", | ||
395 | }; | ||
396 | |||
397 | static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos) | ||
398 | { | ||
399 | struct list_head *head = list->next; | ||
400 | |||
401 | if (!head || list_empty(list)) | ||
402 | return NULL; | ||
403 | |||
404 | while (pos && (head = head->next)) { | ||
405 | if (head == list) | ||
406 | return NULL; | ||
407 | pos--; | ||
408 | } | ||
409 | return pos ? NULL : head; | ||
410 | } | ||
411 | |||
412 | static struct list_head *type2list(u_int16_t af, u_int16_t type) | ||
413 | { | ||
414 | struct list_head *list; | ||
415 | |||
416 | switch (type) { | ||
417 | case TARGET: | ||
418 | list = &xt[af].target; | ||
419 | break; | ||
420 | case MATCH: | ||
421 | list = &xt[af].match; | ||
422 | break; | ||
423 | case TABLE: | ||
424 | list = &xt[af].tables; | ||
425 | break; | ||
426 | default: | ||
427 | list = NULL; | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | return list; | ||
432 | } | ||
433 | |||
434 | static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos) | ||
435 | { | ||
436 | struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private; | ||
437 | u_int16_t af = (unsigned long)pde->data & 0xffff; | ||
438 | u_int16_t type = (unsigned long)pde->data >> 16; | ||
439 | struct list_head *list; | ||
440 | |||
441 | if (af >= NPROTO) | ||
442 | return NULL; | ||
443 | |||
444 | list = type2list(af, type); | ||
445 | if (!list) | ||
446 | return NULL; | ||
447 | |||
448 | if (down_interruptible(&xt[af].mutex) != 0) | ||
449 | return NULL; | ||
450 | |||
451 | return xt_get_idx(list, seq, *pos); | ||
452 | } | ||
453 | |||
454 | static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
455 | { | ||
456 | struct proc_dir_entry *pde = seq->private; | ||
457 | u_int16_t af = (unsigned long)pde->data & 0xffff; | ||
458 | u_int16_t type = (unsigned long)pde->data >> 16; | ||
459 | struct list_head *list; | ||
460 | |||
461 | if (af >= NPROTO) | ||
462 | return NULL; | ||
463 | |||
464 | list = type2list(af, type); | ||
465 | if (!list) | ||
466 | return NULL; | ||
467 | |||
468 | (*pos)++; | ||
469 | return xt_get_idx(list, seq, *pos); | ||
470 | } | ||
471 | |||
472 | static void xt_tgt_seq_stop(struct seq_file *seq, void *v) | ||
473 | { | ||
474 | struct proc_dir_entry *pde = seq->private; | ||
475 | u_int16_t af = (unsigned long)pde->data & 0xffff; | ||
476 | |||
477 | up(&xt[af].mutex); | ||
478 | } | ||
479 | |||
480 | static int xt_name_seq_show(struct seq_file *seq, void *v) | ||
481 | { | ||
482 | char *name = (char *)v + sizeof(struct list_head); | ||
483 | |||
484 | if (strlen(name)) | ||
485 | return seq_printf(seq, "%s\n", name); | ||
486 | else | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static struct seq_operations xt_tgt_seq_ops = { | ||
491 | .start = xt_tgt_seq_start, | ||
492 | .next = xt_tgt_seq_next, | ||
493 | .stop = xt_tgt_seq_stop, | ||
494 | .show = xt_name_seq_show, | ||
495 | }; | ||
496 | |||
497 | static int xt_tgt_open(struct inode *inode, struct file *file) | ||
498 | { | ||
499 | int ret; | ||
500 | |||
501 | ret = seq_open(file, &xt_tgt_seq_ops); | ||
502 | if (!ret) { | ||
503 | struct seq_file *seq = file->private_data; | ||
504 | struct proc_dir_entry *pde = PDE(inode); | ||
505 | |||
506 | seq->private = pde; | ||
507 | } | ||
508 | |||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | static struct file_operations xt_file_ops = { | ||
513 | .owner = THIS_MODULE, | ||
514 | .open = xt_tgt_open, | ||
515 | .read = seq_read, | ||
516 | .llseek = seq_lseek, | ||
517 | .release = seq_release, | ||
518 | }; | ||
519 | |||
520 | #define FORMAT_TABLES "_tables_names" | ||
521 | #define FORMAT_MATCHES "_tables_matches" | ||
522 | #define FORMAT_TARGETS "_tables_targets" | ||
523 | |||
524 | #endif /* CONFIG_PROC_FS */ | ||
525 | |||
526 | int xt_proto_init(int af) | ||
527 | { | ||
528 | #ifdef CONFIG_PROC_FS | ||
529 | char buf[XT_FUNCTION_MAXNAMELEN]; | ||
530 | struct proc_dir_entry *proc; | ||
531 | #endif | ||
532 | |||
533 | if (af >= NPROTO) | ||
534 | return -EINVAL; | ||
535 | |||
536 | |||
537 | #ifdef CONFIG_PROC_FS | ||
538 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
539 | strlcat(buf, FORMAT_TABLES, sizeof(buf)); | ||
540 | proc = proc_net_fops_create(buf, 0440, &xt_file_ops); | ||
541 | if (!proc) | ||
542 | goto out; | ||
543 | proc->data = (void *) ((unsigned long) af | (TABLE << 16)); | ||
544 | |||
545 | |||
546 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
547 | strlcat(buf, FORMAT_MATCHES, sizeof(buf)); | ||
548 | proc = proc_net_fops_create(buf, 0440, &xt_file_ops); | ||
549 | if (!proc) | ||
550 | goto out_remove_tables; | ||
551 | proc->data = (void *) ((unsigned long) af | (MATCH << 16)); | ||
552 | |||
553 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
554 | strlcat(buf, FORMAT_TARGETS, sizeof(buf)); | ||
555 | proc = proc_net_fops_create(buf, 0440, &xt_file_ops); | ||
556 | if (!proc) | ||
557 | goto out_remove_matches; | ||
558 | proc->data = (void *) ((unsigned long) af | (TARGET << 16)); | ||
559 | #endif | ||
560 | |||
561 | return 0; | ||
562 | |||
563 | #ifdef CONFIG_PROC_FS | ||
564 | out_remove_matches: | ||
565 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
566 | strlcat(buf, FORMAT_MATCHES, sizeof(buf)); | ||
567 | proc_net_remove(buf); | ||
568 | |||
569 | out_remove_tables: | ||
570 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
571 | strlcat(buf, FORMAT_TABLES, sizeof(buf)); | ||
572 | proc_net_remove(buf); | ||
573 | out: | ||
574 | return -1; | ||
575 | #endif | ||
576 | } | ||
577 | EXPORT_SYMBOL_GPL(xt_proto_init); | ||
578 | |||
579 | void xt_proto_fini(int af) | ||
580 | { | ||
581 | #ifdef CONFIG_PROC_FS | ||
582 | char buf[XT_FUNCTION_MAXNAMELEN]; | ||
583 | |||
584 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
585 | strlcat(buf, FORMAT_TABLES, sizeof(buf)); | ||
586 | proc_net_remove(buf); | ||
587 | |||
588 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
589 | strlcat(buf, FORMAT_TARGETS, sizeof(buf)); | ||
590 | proc_net_remove(buf); | ||
591 | |||
592 | strlcpy(buf, xt_proto_prefix[af], sizeof(buf)); | ||
593 | strlcat(buf, FORMAT_MATCHES, sizeof(buf)); | ||
594 | proc_net_remove(buf); | ||
595 | #endif /*CONFIG_PROC_FS*/ | ||
596 | } | ||
597 | EXPORT_SYMBOL_GPL(xt_proto_fini); | ||
598 | |||
599 | |||
600 | static int __init xt_init(void) | ||
601 | { | ||
602 | int i; | ||
603 | |||
604 | xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL); | ||
605 | if (!xt) | ||
606 | return -ENOMEM; | ||
607 | |||
608 | for (i = 0; i < NPROTO; i++) { | ||
609 | init_MUTEX(&xt[i].mutex); | ||
610 | INIT_LIST_HEAD(&xt[i].target); | ||
611 | INIT_LIST_HEAD(&xt[i].match); | ||
612 | INIT_LIST_HEAD(&xt[i].tables); | ||
613 | } | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static void __exit xt_fini(void) | ||
618 | { | ||
619 | kfree(xt); | ||
620 | } | ||
621 | |||
622 | module_init(xt_init); | ||
623 | module_exit(xt_fini); | ||
624 | |||
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c new file mode 100644 index 000000000000..78ee266a12ee --- /dev/null +++ b/net/netfilter/xt_CLASSIFY.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * This is a module which is used for setting the skb->priority field | ||
3 | * of an skb for qdisc classification. | ||
4 | */ | ||
5 | |||
6 | /* (C) 2001-2002 Patrick McHardy <kaber@trash.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <net/checksum.h> | ||
17 | |||
18 | #include <linux/netfilter/x_tables.h> | ||
19 | #include <linux/netfilter/xt_CLASSIFY.h> | ||
20 | |||
21 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
22 | MODULE_LICENSE("GPL"); | ||
23 | MODULE_DESCRIPTION("iptables qdisc classification target module"); | ||
24 | MODULE_ALIAS("ipt_CLASSIFY"); | ||
25 | |||
26 | static unsigned int | ||
27 | target(struct sk_buff **pskb, | ||
28 | const struct net_device *in, | ||
29 | const struct net_device *out, | ||
30 | unsigned int hooknum, | ||
31 | const void *targinfo, | ||
32 | void *userinfo) | ||
33 | { | ||
34 | const struct xt_classify_target_info *clinfo = targinfo; | ||
35 | |||
36 | if ((*pskb)->priority != clinfo->priority) | ||
37 | (*pskb)->priority = clinfo->priority; | ||
38 | |||
39 | return XT_CONTINUE; | ||
40 | } | ||
41 | |||
42 | static int | ||
43 | checkentry(const char *tablename, | ||
44 | const void *e, | ||
45 | void *targinfo, | ||
46 | unsigned int targinfosize, | ||
47 | unsigned int hook_mask) | ||
48 | { | ||
49 | if (targinfosize != XT_ALIGN(sizeof(struct xt_classify_target_info))){ | ||
50 | printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n", | ||
51 | targinfosize, | ||
52 | XT_ALIGN(sizeof(struct xt_classify_target_info))); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | | ||
57 | (1 << NF_IP_POST_ROUTING))) { | ||
58 | printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD " | ||
59 | "and POST_ROUTING.\n"); | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | if (strcmp(tablename, "mangle") != 0) { | ||
64 | printk(KERN_ERR "CLASSIFY: can only be called from " | ||
65 | "\"mangle\" table, not \"%s\".\n", | ||
66 | tablename); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | static struct xt_target classify_reg = { | ||
74 | .name = "CLASSIFY", | ||
75 | .target = target, | ||
76 | .checkentry = checkentry, | ||
77 | .me = THIS_MODULE, | ||
78 | }; | ||
79 | static struct xt_target classify6_reg = { | ||
80 | .name = "CLASSIFY", | ||
81 | .target = target, | ||
82 | .checkentry = checkentry, | ||
83 | .me = THIS_MODULE, | ||
84 | }; | ||
85 | |||
86 | |||
87 | static int __init init(void) | ||
88 | { | ||
89 | int ret; | ||
90 | |||
91 | ret = xt_register_target(AF_INET, &classify_reg); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | ret = xt_register_target(AF_INET6, &classify6_reg); | ||
96 | if (ret) | ||
97 | xt_unregister_target(AF_INET, &classify_reg); | ||
98 | |||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static void __exit fini(void) | ||
103 | { | ||
104 | xt_unregister_target(AF_INET, &classify_reg); | ||
105 | xt_unregister_target(AF_INET6, &classify6_reg); | ||
106 | } | ||
107 | |||
108 | module_init(init); | ||
109 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c new file mode 100644 index 000000000000..22506e376be5 --- /dev/null +++ b/net/netfilter/xt_CONNMARK.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* This kernel module is used to modify the connection mark values, or | ||
2 | * to optionally restore the skb nfmark from the connection mark | ||
3 | * | ||
4 | * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> | ||
5 | * by Henrik Nordstrom <hno@marasystems.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/skbuff.h> | ||
23 | #include <linux/ip.h> | ||
24 | #include <net/checksum.h> | ||
25 | |||
26 | MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); | ||
27 | MODULE_DESCRIPTION("IP tables CONNMARK matching module"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | MODULE_ALIAS("ipt_CONNMARK"); | ||
30 | |||
31 | #include <linux/netfilter/x_tables.h> | ||
32 | #include <linux/netfilter/xt_CONNMARK.h> | ||
33 | #include <net/netfilter/nf_conntrack_compat.h> | ||
34 | |||
35 | static unsigned int | ||
36 | target(struct sk_buff **pskb, | ||
37 | const struct net_device *in, | ||
38 | const struct net_device *out, | ||
39 | unsigned int hooknum, | ||
40 | const void *targinfo, | ||
41 | void *userinfo) | ||
42 | { | ||
43 | const struct xt_connmark_target_info *markinfo = targinfo; | ||
44 | u_int32_t diff; | ||
45 | u_int32_t nfmark; | ||
46 | u_int32_t newmark; | ||
47 | u_int32_t ctinfo; | ||
48 | u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo); | ||
49 | |||
50 | if (ctmark) { | ||
51 | switch(markinfo->mode) { | ||
52 | case XT_CONNMARK_SET: | ||
53 | newmark = (*ctmark & ~markinfo->mask) | markinfo->mark; | ||
54 | if (newmark != *ctmark) | ||
55 | *ctmark = newmark; | ||
56 | break; | ||
57 | case XT_CONNMARK_SAVE: | ||
58 | newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); | ||
59 | if (*ctmark != newmark) | ||
60 | *ctmark = newmark; | ||
61 | break; | ||
62 | case XT_CONNMARK_RESTORE: | ||
63 | nfmark = (*pskb)->nfmark; | ||
64 | diff = (*ctmark ^ nfmark) & markinfo->mask; | ||
65 | if (diff != 0) | ||
66 | (*pskb)->nfmark = nfmark ^ diff; | ||
67 | break; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return XT_CONTINUE; | ||
72 | } | ||
73 | |||
74 | static int | ||
75 | checkentry(const char *tablename, | ||
76 | const void *entry, | ||
77 | void *targinfo, | ||
78 | unsigned int targinfosize, | ||
79 | unsigned int hook_mask) | ||
80 | { | ||
81 | struct xt_connmark_target_info *matchinfo = targinfo; | ||
82 | if (targinfosize != XT_ALIGN(sizeof(struct xt_connmark_target_info))) { | ||
83 | printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n", | ||
84 | targinfosize, | ||
85 | XT_ALIGN(sizeof(struct xt_connmark_target_info))); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | if (matchinfo->mode == XT_CONNMARK_RESTORE) { | ||
90 | if (strcmp(tablename, "mangle") != 0) { | ||
91 | printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
92 | return 0; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) { | ||
97 | printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n"); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | static struct xt_target connmark_reg = { | ||
105 | .name = "CONNMARK", | ||
106 | .target = &target, | ||
107 | .checkentry = &checkentry, | ||
108 | .me = THIS_MODULE | ||
109 | }; | ||
110 | static struct xt_target connmark6_reg = { | ||
111 | .name = "CONNMARK", | ||
112 | .target = &target, | ||
113 | .checkentry = &checkentry, | ||
114 | .me = THIS_MODULE | ||
115 | }; | ||
116 | |||
117 | static int __init init(void) | ||
118 | { | ||
119 | int ret; | ||
120 | |||
121 | need_conntrack(); | ||
122 | |||
123 | ret = xt_register_target(AF_INET, &connmark_reg); | ||
124 | if (ret) | ||
125 | return ret; | ||
126 | |||
127 | ret = xt_register_target(AF_INET6, &connmark6_reg); | ||
128 | if (ret) | ||
129 | xt_unregister_target(AF_INET, &connmark_reg); | ||
130 | |||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static void __exit fini(void) | ||
135 | { | ||
136 | xt_unregister_target(AF_INET, &connmark_reg); | ||
137 | xt_unregister_target(AF_INET6, &connmark6_reg); | ||
138 | } | ||
139 | |||
140 | module_init(init); | ||
141 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c new file mode 100644 index 000000000000..0c11ee9550f3 --- /dev/null +++ b/net/netfilter/xt_MARK.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* This is a module which is used for setting the NFMARK field of an skb. */ | ||
2 | |||
3 | /* (C) 1999-2001 Marc Boucher <marc@mbsi.ca> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | #include <linux/ip.h> | ||
13 | #include <net/checksum.h> | ||
14 | |||
15 | #include <linux/netfilter/x_tables.h> | ||
16 | #include <linux/netfilter/xt_MARK.h> | ||
17 | |||
18 | MODULE_LICENSE("GPL"); | ||
19 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | ||
20 | MODULE_DESCRIPTION("ip[6]tables MARK modification module"); | ||
21 | MODULE_ALIAS("ipt_MARK"); | ||
22 | MODULE_ALIAS("ip6t_MARK"); | ||
23 | |||
24 | static unsigned int | ||
25 | target_v0(struct sk_buff **pskb, | ||
26 | const struct net_device *in, | ||
27 | const struct net_device *out, | ||
28 | unsigned int hooknum, | ||
29 | const void *targinfo, | ||
30 | void *userinfo) | ||
31 | { | ||
32 | const struct xt_mark_target_info *markinfo = targinfo; | ||
33 | |||
34 | if((*pskb)->nfmark != markinfo->mark) | ||
35 | (*pskb)->nfmark = markinfo->mark; | ||
36 | |||
37 | return XT_CONTINUE; | ||
38 | } | ||
39 | |||
40 | static unsigned int | ||
41 | target_v1(struct sk_buff **pskb, | ||
42 | const struct net_device *in, | ||
43 | const struct net_device *out, | ||
44 | unsigned int hooknum, | ||
45 | const void *targinfo, | ||
46 | void *userinfo) | ||
47 | { | ||
48 | const struct xt_mark_target_info_v1 *markinfo = targinfo; | ||
49 | int mark = 0; | ||
50 | |||
51 | switch (markinfo->mode) { | ||
52 | case XT_MARK_SET: | ||
53 | mark = markinfo->mark; | ||
54 | break; | ||
55 | |||
56 | case XT_MARK_AND: | ||
57 | mark = (*pskb)->nfmark & markinfo->mark; | ||
58 | break; | ||
59 | |||
60 | case XT_MARK_OR: | ||
61 | mark = (*pskb)->nfmark | markinfo->mark; | ||
62 | break; | ||
63 | } | ||
64 | |||
65 | if((*pskb)->nfmark != mark) | ||
66 | (*pskb)->nfmark = mark; | ||
67 | |||
68 | return XT_CONTINUE; | ||
69 | } | ||
70 | |||
71 | |||
72 | static int | ||
73 | checkentry_v0(const char *tablename, | ||
74 | const void *entry, | ||
75 | void *targinfo, | ||
76 | unsigned int targinfosize, | ||
77 | unsigned int hook_mask) | ||
78 | { | ||
79 | struct xt_mark_target_info *markinfo = targinfo; | ||
80 | |||
81 | if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) { | ||
82 | printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n", | ||
83 | targinfosize, | ||
84 | XT_ALIGN(sizeof(struct xt_mark_target_info))); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | if (strcmp(tablename, "mangle") != 0) { | ||
89 | printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | if (markinfo->mark > 0xffffffff) { | ||
94 | printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | return 1; | ||
99 | } | ||
100 | |||
101 | static int | ||
102 | checkentry_v1(const char *tablename, | ||
103 | const void *entry, | ||
104 | void *targinfo, | ||
105 | unsigned int targinfosize, | ||
106 | unsigned int hook_mask) | ||
107 | { | ||
108 | struct xt_mark_target_info_v1 *markinfo = targinfo; | ||
109 | |||
110 | if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){ | ||
111 | printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n", | ||
112 | targinfosize, | ||
113 | XT_ALIGN(sizeof(struct xt_mark_target_info_v1))); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | if (strcmp(tablename, "mangle") != 0) { | ||
118 | printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | if (markinfo->mode != XT_MARK_SET | ||
123 | && markinfo->mode != XT_MARK_AND | ||
124 | && markinfo->mode != XT_MARK_OR) { | ||
125 | printk(KERN_WARNING "MARK: unknown mode %u\n", | ||
126 | markinfo->mode); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | if (markinfo->mark > 0xffffffff) { | ||
131 | printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | return 1; | ||
136 | } | ||
137 | |||
138 | static struct xt_target ipt_mark_reg_v0 = { | ||
139 | .name = "MARK", | ||
140 | .target = target_v0, | ||
141 | .checkentry = checkentry_v0, | ||
142 | .me = THIS_MODULE, | ||
143 | .revision = 0, | ||
144 | }; | ||
145 | |||
146 | static struct xt_target ipt_mark_reg_v1 = { | ||
147 | .name = "MARK", | ||
148 | .target = target_v1, | ||
149 | .checkentry = checkentry_v1, | ||
150 | .me = THIS_MODULE, | ||
151 | .revision = 1, | ||
152 | }; | ||
153 | |||
154 | static struct xt_target ip6t_mark_reg_v0 = { | ||
155 | .name = "MARK", | ||
156 | .target = target_v0, | ||
157 | .checkentry = checkentry_v0, | ||
158 | .me = THIS_MODULE, | ||
159 | .revision = 0, | ||
160 | }; | ||
161 | |||
162 | static int __init init(void) | ||
163 | { | ||
164 | int err; | ||
165 | |||
166 | err = xt_register_target(AF_INET, &ipt_mark_reg_v0); | ||
167 | if (err) | ||
168 | return err; | ||
169 | |||
170 | err = xt_register_target(AF_INET, &ipt_mark_reg_v1); | ||
171 | if (err) | ||
172 | xt_unregister_target(AF_INET, &ipt_mark_reg_v0); | ||
173 | |||
174 | err = xt_register_target(AF_INET6, &ip6t_mark_reg_v0); | ||
175 | if (err) { | ||
176 | xt_unregister_target(AF_INET, &ipt_mark_reg_v0); | ||
177 | xt_unregister_target(AF_INET, &ipt_mark_reg_v1); | ||
178 | } | ||
179 | |||
180 | return err; | ||
181 | } | ||
182 | |||
183 | static void __exit fini(void) | ||
184 | { | ||
185 | xt_unregister_target(AF_INET, &ipt_mark_reg_v0); | ||
186 | xt_unregister_target(AF_INET, &ipt_mark_reg_v1); | ||
187 | xt_unregister_target(AF_INET6, &ip6t_mark_reg_v0); | ||
188 | } | ||
189 | |||
190 | module_init(init); | ||
191 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c new file mode 100644 index 000000000000..8b76b6f8d1e4 --- /dev/null +++ b/net/netfilter/xt_NFQUEUE.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* iptables module for using new netfilter netlink queue | ||
2 | * | ||
3 | * (C) 2005 by Harald Welte <laforge@netfilter.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | |||
14 | #include <linux/netfilter.h> | ||
15 | #include <linux/netfilter_arp.h> | ||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | #include <linux/netfilter/xt_NFQUEUE.h> | ||
18 | |||
19 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
20 | MODULE_DESCRIPTION("[ip,ip6,arp]_tables NFQUEUE target"); | ||
21 | MODULE_LICENSE("GPL"); | ||
22 | MODULE_ALIAS("ipt_NFQUEUE"); | ||
23 | MODULE_ALIAS("ip6t_NFQUEUE"); | ||
24 | MODULE_ALIAS("arpt_NFQUEUE"); | ||
25 | |||
26 | static unsigned int | ||
27 | target(struct sk_buff **pskb, | ||
28 | const struct net_device *in, | ||
29 | const struct net_device *out, | ||
30 | unsigned int hooknum, | ||
31 | const void *targinfo, | ||
32 | void *userinfo) | ||
33 | { | ||
34 | const struct xt_NFQ_info *tinfo = targinfo; | ||
35 | |||
36 | return NF_QUEUE_NR(tinfo->queuenum); | ||
37 | } | ||
38 | |||
39 | static int | ||
40 | checkentry(const char *tablename, | ||
41 | const void *entry, | ||
42 | void *targinfo, | ||
43 | unsigned int targinfosize, | ||
44 | unsigned int hook_mask) | ||
45 | { | ||
46 | if (targinfosize != XT_ALIGN(sizeof(struct xt_NFQ_info))) { | ||
47 | printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n", | ||
48 | targinfosize, | ||
49 | XT_ALIGN(sizeof(struct xt_NFQ_info))); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | static struct xt_target ipt_NFQ_reg = { | ||
57 | .name = "NFQUEUE", | ||
58 | .target = target, | ||
59 | .checkentry = checkentry, | ||
60 | .me = THIS_MODULE, | ||
61 | }; | ||
62 | |||
63 | static struct xt_target ip6t_NFQ_reg = { | ||
64 | .name = "NFQUEUE", | ||
65 | .target = target, | ||
66 | .checkentry = checkentry, | ||
67 | .me = THIS_MODULE, | ||
68 | }; | ||
69 | |||
70 | static struct xt_target arpt_NFQ_reg = { | ||
71 | .name = "NFQUEUE", | ||
72 | .target = target, | ||
73 | .checkentry = checkentry, | ||
74 | .me = THIS_MODULE, | ||
75 | }; | ||
76 | |||
77 | static int __init init(void) | ||
78 | { | ||
79 | int ret; | ||
80 | ret = xt_register_target(AF_INET, &ipt_NFQ_reg); | ||
81 | if (ret) | ||
82 | return ret; | ||
83 | ret = xt_register_target(AF_INET6, &ip6t_NFQ_reg); | ||
84 | if (ret) | ||
85 | goto out_ip; | ||
86 | ret = xt_register_target(NF_ARP, &arpt_NFQ_reg); | ||
87 | if (ret) | ||
88 | goto out_ip6; | ||
89 | |||
90 | return ret; | ||
91 | out_ip6: | ||
92 | xt_unregister_target(AF_INET6, &ip6t_NFQ_reg); | ||
93 | out_ip: | ||
94 | xt_unregister_target(AF_INET, &ipt_NFQ_reg); | ||
95 | |||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static void __exit fini(void) | ||
100 | { | ||
101 | xt_unregister_target(NF_ARP, &arpt_NFQ_reg); | ||
102 | xt_unregister_target(AF_INET6, &ip6t_NFQ_reg); | ||
103 | xt_unregister_target(AF_INET, &ipt_NFQ_reg); | ||
104 | } | ||
105 | |||
106 | module_init(init); | ||
107 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c new file mode 100644 index 000000000000..24d477afa939 --- /dev/null +++ b/net/netfilter/xt_NOTRACK.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* This is a module which is used for setting up fake conntracks | ||
2 | * on packets so that they are not seen by the conntrack/NAT code. | ||
3 | */ | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/skbuff.h> | ||
6 | |||
7 | #include <linux/netfilter/x_tables.h> | ||
8 | #include <net/netfilter/nf_conntrack_compat.h> | ||
9 | |||
10 | MODULE_LICENSE("GPL"); | ||
11 | MODULE_ALIAS("ipt_NOTRACK"); | ||
12 | |||
13 | static unsigned int | ||
14 | target(struct sk_buff **pskb, | ||
15 | const struct net_device *in, | ||
16 | const struct net_device *out, | ||
17 | unsigned int hooknum, | ||
18 | const void *targinfo, | ||
19 | void *userinfo) | ||
20 | { | ||
21 | /* Previously seen (loopback)? Ignore. */ | ||
22 | if ((*pskb)->nfct != NULL) | ||
23 | return XT_CONTINUE; | ||
24 | |||
25 | /* Attach fake conntrack entry. | ||
26 | If there is a real ct entry correspondig to this packet, | ||
27 | it'll hang aroun till timing out. We don't deal with it | ||
28 | for performance reasons. JK */ | ||
29 | nf_ct_untrack(*pskb); | ||
30 | (*pskb)->nfctinfo = IP_CT_NEW; | ||
31 | nf_conntrack_get((*pskb)->nfct); | ||
32 | |||
33 | return XT_CONTINUE; | ||
34 | } | ||
35 | |||
36 | static int | ||
37 | checkentry(const char *tablename, | ||
38 | const void *entry, | ||
39 | void *targinfo, | ||
40 | unsigned int targinfosize, | ||
41 | unsigned int hook_mask) | ||
42 | { | ||
43 | if (targinfosize != 0) { | ||
44 | printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n", | ||
45 | targinfosize); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | if (strcmp(tablename, "raw") != 0) { | ||
50 | printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | return 1; | ||
55 | } | ||
56 | |||
57 | static struct xt_target notrack_reg = { | ||
58 | .name = "NOTRACK", | ||
59 | .target = target, | ||
60 | .checkentry = checkentry, | ||
61 | .me = THIS_MODULE, | ||
62 | }; | ||
63 | static struct xt_target notrack6_reg = { | ||
64 | .name = "NOTRACK", | ||
65 | .target = target, | ||
66 | .checkentry = checkentry, | ||
67 | .me = THIS_MODULE, | ||
68 | }; | ||
69 | |||
70 | static int __init init(void) | ||
71 | { | ||
72 | int ret; | ||
73 | |||
74 | ret = xt_register_target(AF_INET, ¬rack_reg); | ||
75 | if (ret) | ||
76 | return ret; | ||
77 | |||
78 | ret = xt_register_target(AF_INET6, ¬rack6_reg); | ||
79 | if (ret) | ||
80 | xt_unregister_target(AF_INET, ¬rack_reg); | ||
81 | |||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | static void __exit fini(void) | ||
86 | { | ||
87 | xt_unregister_target(AF_INET6, ¬rack6_reg); | ||
88 | xt_unregister_target(AF_INET, ¬rack_reg); | ||
89 | } | ||
90 | |||
91 | module_init(init); | ||
92 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c new file mode 100644 index 000000000000..4ba6fd65c6e9 --- /dev/null +++ b/net/netfilter/xt_comment.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Implements a dummy match to allow attaching comments to rules | ||
3 | * | ||
4 | * 2003-05-13 Brad Fisher (brad@info-link.net) | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/skbuff.h> | ||
9 | #include <linux/netfilter/x_tables.h> | ||
10 | #include <linux/netfilter/xt_comment.h> | ||
11 | |||
12 | MODULE_AUTHOR("Brad Fisher <brad@info-link.net>"); | ||
13 | MODULE_DESCRIPTION("iptables comment match module"); | ||
14 | MODULE_LICENSE("GPL"); | ||
15 | MODULE_ALIAS("ipt_comment"); | ||
16 | MODULE_ALIAS("ip6t_comment"); | ||
17 | |||
18 | static int | ||
19 | match(const struct sk_buff *skb, | ||
20 | const struct net_device *in, | ||
21 | const struct net_device *out, | ||
22 | const void *matchinfo, | ||
23 | int offset, | ||
24 | unsigned int protooff, | ||
25 | int *hotdrop) | ||
26 | { | ||
27 | /* We always match */ | ||
28 | return 1; | ||
29 | } | ||
30 | |||
31 | static int | ||
32 | checkentry(const char *tablename, | ||
33 | const void *ip, | ||
34 | void *matchinfo, | ||
35 | unsigned int matchsize, | ||
36 | unsigned int hook_mask) | ||
37 | { | ||
38 | /* Check the size */ | ||
39 | if (matchsize != XT_ALIGN(sizeof(struct xt_comment_info))) | ||
40 | return 0; | ||
41 | return 1; | ||
42 | } | ||
43 | |||
44 | static struct xt_match comment_match = { | ||
45 | .name = "comment", | ||
46 | .match = match, | ||
47 | .checkentry = checkentry, | ||
48 | .me = THIS_MODULE | ||
49 | }; | ||
50 | |||
51 | static struct xt_match comment6_match = { | ||
52 | .name = "comment", | ||
53 | .match = match, | ||
54 | .checkentry = checkentry, | ||
55 | .me = THIS_MODULE | ||
56 | }; | ||
57 | |||
58 | static int __init init(void) | ||
59 | { | ||
60 | int ret; | ||
61 | |||
62 | ret = xt_register_match(AF_INET, &comment_match); | ||
63 | if (ret) | ||
64 | return ret; | ||
65 | |||
66 | ret = xt_register_match(AF_INET6, &comment6_match); | ||
67 | if (ret) | ||
68 | xt_unregister_match(AF_INET, &comment_match); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | static void __exit fini(void) | ||
74 | { | ||
75 | xt_unregister_match(AF_INET, &comment_match); | ||
76 | xt_unregister_match(AF_INET6, &comment6_match); | ||
77 | } | ||
78 | |||
79 | module_init(init); | ||
80 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c new file mode 100644 index 000000000000..150d2a4b0f71 --- /dev/null +++ b/net/netfilter/xt_connbytes.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* Kernel module to match connection tracking byte counter. | ||
2 | * GPL (C) 2002 Martin Devera (devik@cdi.cz). | ||
3 | * | ||
4 | * 2004-07-20 Harald Welte <laforge@netfilter.org> | ||
5 | * - reimplemented to use per-connection accounting counters | ||
6 | * - add functionality to match number of packets | ||
7 | * - add functionality to match average packet size | ||
8 | * - add support to match directions seperately | ||
9 | * 2005-10-16 Harald Welte <laforge@netfilter.org> | ||
10 | * - Port to x_tables | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <net/netfilter/nf_conntrack_compat.h> | ||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | #include <linux/netfilter/xt_connbytes.h> | ||
18 | |||
19 | #include <asm/div64.h> | ||
20 | #include <asm/bitops.h> | ||
21 | |||
22 | MODULE_LICENSE("GPL"); | ||
23 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
24 | MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection"); | ||
25 | MODULE_ALIAS("ipt_connbytes"); | ||
26 | |||
27 | /* 64bit divisor, dividend and result. dynamic precision */ | ||
28 | static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor) | ||
29 | { | ||
30 | u_int32_t d = divisor; | ||
31 | |||
32 | if (divisor > 0xffffffffULL) { | ||
33 | unsigned int shift = fls(divisor >> 32); | ||
34 | |||
35 | d = divisor >> shift; | ||
36 | dividend >>= shift; | ||
37 | } | ||
38 | |||
39 | do_div(dividend, d); | ||
40 | return dividend; | ||
41 | } | ||
42 | |||
43 | static int | ||
44 | match(const struct sk_buff *skb, | ||
45 | const struct net_device *in, | ||
46 | const struct net_device *out, | ||
47 | const void *matchinfo, | ||
48 | int offset, | ||
49 | unsigned int protoff, | ||
50 | int *hotdrop) | ||
51 | { | ||
52 | const struct xt_connbytes_info *sinfo = matchinfo; | ||
53 | u_int64_t what = 0; /* initialize to make gcc happy */ | ||
54 | const struct ip_conntrack_counter *counters; | ||
55 | |||
56 | if (!(counters = nf_ct_get_counters(skb))) | ||
57 | return 0; /* no match */ | ||
58 | |||
59 | switch (sinfo->what) { | ||
60 | case XT_CONNBYTES_PKTS: | ||
61 | switch (sinfo->direction) { | ||
62 | case XT_CONNBYTES_DIR_ORIGINAL: | ||
63 | what = counters[IP_CT_DIR_ORIGINAL].packets; | ||
64 | break; | ||
65 | case XT_CONNBYTES_DIR_REPLY: | ||
66 | what = counters[IP_CT_DIR_REPLY].packets; | ||
67 | break; | ||
68 | case XT_CONNBYTES_DIR_BOTH: | ||
69 | what = counters[IP_CT_DIR_ORIGINAL].packets; | ||
70 | what += counters[IP_CT_DIR_REPLY].packets; | ||
71 | break; | ||
72 | } | ||
73 | break; | ||
74 | case XT_CONNBYTES_BYTES: | ||
75 | switch (sinfo->direction) { | ||
76 | case XT_CONNBYTES_DIR_ORIGINAL: | ||
77 | what = counters[IP_CT_DIR_ORIGINAL].bytes; | ||
78 | break; | ||
79 | case XT_CONNBYTES_DIR_REPLY: | ||
80 | what = counters[IP_CT_DIR_REPLY].bytes; | ||
81 | break; | ||
82 | case XT_CONNBYTES_DIR_BOTH: | ||
83 | what = counters[IP_CT_DIR_ORIGINAL].bytes; | ||
84 | what += counters[IP_CT_DIR_REPLY].bytes; | ||
85 | break; | ||
86 | } | ||
87 | break; | ||
88 | case XT_CONNBYTES_AVGPKT: | ||
89 | switch (sinfo->direction) { | ||
90 | case XT_CONNBYTES_DIR_ORIGINAL: | ||
91 | what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes, | ||
92 | counters[IP_CT_DIR_ORIGINAL].packets); | ||
93 | break; | ||
94 | case XT_CONNBYTES_DIR_REPLY: | ||
95 | what = div64_64(counters[IP_CT_DIR_REPLY].bytes, | ||
96 | counters[IP_CT_DIR_REPLY].packets); | ||
97 | break; | ||
98 | case XT_CONNBYTES_DIR_BOTH: | ||
99 | { | ||
100 | u_int64_t bytes; | ||
101 | u_int64_t pkts; | ||
102 | bytes = counters[IP_CT_DIR_ORIGINAL].bytes + | ||
103 | counters[IP_CT_DIR_REPLY].bytes; | ||
104 | pkts = counters[IP_CT_DIR_ORIGINAL].packets+ | ||
105 | counters[IP_CT_DIR_REPLY].packets; | ||
106 | |||
107 | /* FIXME_THEORETICAL: what to do if sum | ||
108 | * overflows ? */ | ||
109 | |||
110 | what = div64_64(bytes, pkts); | ||
111 | } | ||
112 | break; | ||
113 | } | ||
114 | break; | ||
115 | } | ||
116 | |||
117 | if (sinfo->count.to) | ||
118 | return (what <= sinfo->count.to && what >= sinfo->count.from); | ||
119 | else | ||
120 | return (what >= sinfo->count.from); | ||
121 | } | ||
122 | |||
123 | static int check(const char *tablename, | ||
124 | const void *ip, | ||
125 | void *matchinfo, | ||
126 | unsigned int matchsize, | ||
127 | unsigned int hook_mask) | ||
128 | { | ||
129 | const struct xt_connbytes_info *sinfo = matchinfo; | ||
130 | |||
131 | if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info))) | ||
132 | return 0; | ||
133 | |||
134 | if (sinfo->what != XT_CONNBYTES_PKTS && | ||
135 | sinfo->what != XT_CONNBYTES_BYTES && | ||
136 | sinfo->what != XT_CONNBYTES_AVGPKT) | ||
137 | return 0; | ||
138 | |||
139 | if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && | ||
140 | sinfo->direction != XT_CONNBYTES_DIR_REPLY && | ||
141 | sinfo->direction != XT_CONNBYTES_DIR_BOTH) | ||
142 | return 0; | ||
143 | |||
144 | return 1; | ||
145 | } | ||
146 | |||
147 | static struct xt_match connbytes_match = { | ||
148 | .name = "connbytes", | ||
149 | .match = &match, | ||
150 | .checkentry = &check, | ||
151 | .me = THIS_MODULE | ||
152 | }; | ||
153 | static struct xt_match connbytes6_match = { | ||
154 | .name = "connbytes", | ||
155 | .match = &match, | ||
156 | .checkentry = &check, | ||
157 | .me = THIS_MODULE | ||
158 | }; | ||
159 | |||
160 | static int __init init(void) | ||
161 | { | ||
162 | int ret; | ||
163 | ret = xt_register_match(AF_INET, &connbytes_match); | ||
164 | if (ret) | ||
165 | return ret; | ||
166 | |||
167 | ret = xt_register_match(AF_INET6, &connbytes6_match); | ||
168 | if (ret) | ||
169 | xt_unregister_match(AF_INET, &connbytes_match); | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static void __exit fini(void) | ||
174 | { | ||
175 | xt_unregister_match(AF_INET, &connbytes_match); | ||
176 | xt_unregister_match(AF_INET6, &connbytes6_match); | ||
177 | } | ||
178 | |||
179 | module_init(init); | ||
180 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c new file mode 100644 index 000000000000..d06e925032da --- /dev/null +++ b/net/netfilter/xt_connmark.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* This kernel module matches connection mark values set by the | ||
2 | * CONNMARK target | ||
3 | * | ||
4 | * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> | ||
5 | * by Henrik Nordstrom <hno@marasystems.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/skbuff.h> | ||
24 | |||
25 | MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); | ||
26 | MODULE_DESCRIPTION("IP tables connmark match module"); | ||
27 | MODULE_LICENSE("GPL"); | ||
28 | MODULE_ALIAS("ipt_connmark"); | ||
29 | |||
30 | #include <linux/netfilter/x_tables.h> | ||
31 | #include <linux/netfilter/xt_connmark.h> | ||
32 | #include <net/netfilter/nf_conntrack_compat.h> | ||
33 | |||
34 | static int | ||
35 | match(const struct sk_buff *skb, | ||
36 | const struct net_device *in, | ||
37 | const struct net_device *out, | ||
38 | const void *matchinfo, | ||
39 | int offset, | ||
40 | unsigned int protoff, | ||
41 | int *hotdrop) | ||
42 | { | ||
43 | const struct xt_connmark_info *info = matchinfo; | ||
44 | u_int32_t ctinfo; | ||
45 | const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo); | ||
46 | if (!ctmark) | ||
47 | return 0; | ||
48 | |||
49 | return (((*ctmark) & info->mask) == info->mark) ^ info->invert; | ||
50 | } | ||
51 | |||
52 | static int | ||
53 | checkentry(const char *tablename, | ||
54 | const void *ip, | ||
55 | void *matchinfo, | ||
56 | unsigned int matchsize, | ||
57 | unsigned int hook_mask) | ||
58 | { | ||
59 | struct xt_connmark_info *cm = | ||
60 | (struct xt_connmark_info *)matchinfo; | ||
61 | if (matchsize != XT_ALIGN(sizeof(struct xt_connmark_info))) | ||
62 | return 0; | ||
63 | |||
64 | if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) { | ||
65 | printk(KERN_WARNING "connmark: only support 32bit mark\n"); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | return 1; | ||
70 | } | ||
71 | |||
72 | static struct xt_match connmark_match = { | ||
73 | .name = "connmark", | ||
74 | .match = &match, | ||
75 | .checkentry = &checkentry, | ||
76 | .me = THIS_MODULE | ||
77 | }; | ||
78 | static struct xt_match connmark6_match = { | ||
79 | .name = "connmark", | ||
80 | .match = &match, | ||
81 | .checkentry = &checkentry, | ||
82 | .me = THIS_MODULE | ||
83 | }; | ||
84 | |||
85 | |||
86 | static int __init init(void) | ||
87 | { | ||
88 | int ret; | ||
89 | |||
90 | need_conntrack(); | ||
91 | |||
92 | ret = xt_register_match(AF_INET, &connmark_match); | ||
93 | if (ret) | ||
94 | return ret; | ||
95 | |||
96 | ret = xt_register_match(AF_INET6, &connmark6_match); | ||
97 | if (ret) | ||
98 | xt_unregister_match(AF_INET, &connmark_match); | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static void __exit fini(void) | ||
103 | { | ||
104 | xt_unregister_match(AF_INET6, &connmark6_match); | ||
105 | xt_unregister_match(AF_INET, &connmark_match); | ||
106 | } | ||
107 | |||
108 | module_init(init); | ||
109 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c new file mode 100644 index 000000000000..ffdebc95eb95 --- /dev/null +++ b/net/netfilter/xt_conntrack.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /* Kernel module to match connection tracking information. | ||
2 | * Superset of Rusty's minimalistic state match. | ||
3 | * | ||
4 | * (C) 2001 Marc Boucher (marc@mbsi.ca). | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | |||
14 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
15 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
16 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
17 | #else | ||
18 | #include <net/netfilter/nf_conntrack.h> | ||
19 | #endif | ||
20 | |||
21 | #include <linux/netfilter/x_tables.h> | ||
22 | #include <linux/netfilter/xt_conntrack.h> | ||
23 | |||
24 | MODULE_LICENSE("GPL"); | ||
25 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | ||
26 | MODULE_DESCRIPTION("iptables connection tracking match module"); | ||
27 | MODULE_ALIAS("ipt_conntrack"); | ||
28 | |||
29 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
30 | |||
31 | static int | ||
32 | match(const struct sk_buff *skb, | ||
33 | const struct net_device *in, | ||
34 | const struct net_device *out, | ||
35 | const void *matchinfo, | ||
36 | int offset, | ||
37 | unsigned int protoff, | ||
38 | int *hotdrop) | ||
39 | { | ||
40 | const struct xt_conntrack_info *sinfo = matchinfo; | ||
41 | struct ip_conntrack *ct; | ||
42 | enum ip_conntrack_info ctinfo; | ||
43 | unsigned int statebit; | ||
44 | |||
45 | ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | ||
46 | |||
47 | #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) | ||
48 | |||
49 | if (ct == &ip_conntrack_untracked) | ||
50 | statebit = XT_CONNTRACK_STATE_UNTRACKED; | ||
51 | else if (ct) | ||
52 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); | ||
53 | else | ||
54 | statebit = XT_CONNTRACK_STATE_INVALID; | ||
55 | |||
56 | if(sinfo->flags & XT_CONNTRACK_STATE) { | ||
57 | if (ct) { | ||
58 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != | ||
59 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) | ||
60 | statebit |= XT_CONNTRACK_STATE_SNAT; | ||
61 | |||
62 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != | ||
63 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) | ||
64 | statebit |= XT_CONNTRACK_STATE_DNAT; | ||
65 | } | ||
66 | |||
67 | if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | if(sinfo->flags & XT_CONNTRACK_PROTO) { | ||
72 | if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { | ||
77 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC)) | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | if(sinfo->flags & XT_CONNTRACK_ORIGDST) { | ||
82 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST)) | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | if(sinfo->flags & XT_CONNTRACK_REPLSRC) { | ||
87 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC)) | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | if(sinfo->flags & XT_CONNTRACK_REPLDST) { | ||
92 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST)) | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | if(sinfo->flags & XT_CONNTRACK_STATUS) { | ||
97 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | if(sinfo->flags & XT_CONNTRACK_EXPIRES) { | ||
102 | unsigned long expires; | ||
103 | |||
104 | if(!ct) | ||
105 | return 0; | ||
106 | |||
107 | expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; | ||
108 | |||
109 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
117 | static int | ||
118 | match(const struct sk_buff *skb, | ||
119 | const struct net_device *in, | ||
120 | const struct net_device *out, | ||
121 | const void *matchinfo, | ||
122 | int offset, | ||
123 | unsigned int protoff, | ||
124 | int *hotdrop) | ||
125 | { | ||
126 | const struct xt_conntrack_info *sinfo = matchinfo; | ||
127 | struct nf_conn *ct; | ||
128 | enum ip_conntrack_info ctinfo; | ||
129 | unsigned int statebit; | ||
130 | |||
131 | ct = nf_ct_get((struct sk_buff *)skb, &ctinfo); | ||
132 | |||
133 | #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) | ||
134 | |||
135 | if (ct == &nf_conntrack_untracked) | ||
136 | statebit = XT_CONNTRACK_STATE_UNTRACKED; | ||
137 | else if (ct) | ||
138 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); | ||
139 | else | ||
140 | statebit = XT_CONNTRACK_STATE_INVALID; | ||
141 | |||
142 | if(sinfo->flags & XT_CONNTRACK_STATE) { | ||
143 | if (ct) { | ||
144 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip != | ||
145 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) | ||
146 | statebit |= XT_CONNTRACK_STATE_SNAT; | ||
147 | |||
148 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip != | ||
149 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) | ||
150 | statebit |= XT_CONNTRACK_STATE_DNAT; | ||
151 | } | ||
152 | |||
153 | if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | if(sinfo->flags & XT_CONNTRACK_PROTO) { | ||
158 | if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { | ||
163 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC)) | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | if(sinfo->flags & XT_CONNTRACK_ORIGDST) { | ||
168 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST)) | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | if(sinfo->flags & XT_CONNTRACK_REPLSRC) { | ||
173 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC)) | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | if(sinfo->flags & XT_CONNTRACK_REPLDST) { | ||
178 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST)) | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | if(sinfo->flags & XT_CONNTRACK_STATUS) { | ||
183 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | if(sinfo->flags & XT_CONNTRACK_EXPIRES) { | ||
188 | unsigned long expires; | ||
189 | |||
190 | if(!ct) | ||
191 | return 0; | ||
192 | |||
193 | expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; | ||
194 | |||
195 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | #endif /* CONFIG_NF_IP_CONNTRACK */ | ||
203 | |||
204 | static int check(const char *tablename, | ||
205 | const void *ip, | ||
206 | void *matchinfo, | ||
207 | unsigned int matchsize, | ||
208 | unsigned int hook_mask) | ||
209 | { | ||
210 | if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info))) | ||
211 | return 0; | ||
212 | |||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | static struct xt_match conntrack_match = { | ||
217 | .name = "conntrack", | ||
218 | .match = &match, | ||
219 | .checkentry = &check, | ||
220 | .me = THIS_MODULE, | ||
221 | }; | ||
222 | |||
223 | static int __init init(void) | ||
224 | { | ||
225 | int ret; | ||
226 | need_conntrack(); | ||
227 | ret = xt_register_match(AF_INET, &conntrack_match); | ||
228 | |||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static void __exit fini(void) | ||
233 | { | ||
234 | xt_unregister_match(AF_INET, &conntrack_match); | ||
235 | } | ||
236 | |||
237 | module_init(init); | ||
238 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c new file mode 100644 index 000000000000..779f42fc9524 --- /dev/null +++ b/net/netfilter/xt_dccp.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * iptables module for DCCP protocol header matching | ||
3 | * | ||
4 | * (C) 2005 by Harald Welte <laforge@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <net/ip.h> | ||
15 | #include <linux/dccp.h> | ||
16 | |||
17 | #include <linux/netfilter/x_tables.h> | ||
18 | #include <linux/netfilter/xt_dccp.h> | ||
19 | |||
20 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
21 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
22 | |||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
25 | MODULE_DESCRIPTION("Match for DCCP protocol packets"); | ||
26 | MODULE_ALIAS("ipt_dccp"); | ||
27 | |||
28 | #define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ | ||
29 | || (!!((invflag) & (option)) ^ (cond))) | ||
30 | |||
31 | static unsigned char *dccp_optbuf; | ||
32 | static DEFINE_SPINLOCK(dccp_buflock); | ||
33 | |||
34 | static inline int | ||
35 | dccp_find_option(u_int8_t option, | ||
36 | const struct sk_buff *skb, | ||
37 | unsigned int protoff, | ||
38 | const struct dccp_hdr *dh, | ||
39 | int *hotdrop) | ||
40 | { | ||
41 | /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ | ||
42 | unsigned char *op; | ||
43 | unsigned int optoff = __dccp_hdr_len(dh); | ||
44 | unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh); | ||
45 | unsigned int i; | ||
46 | |||
47 | if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) { | ||
48 | *hotdrop = 1; | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | if (!optlen) | ||
53 | return 0; | ||
54 | |||
55 | spin_lock_bh(&dccp_buflock); | ||
56 | op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf); | ||
57 | if (op == NULL) { | ||
58 | /* If we don't have the whole header, drop packet. */ | ||
59 | spin_unlock_bh(&dccp_buflock); | ||
60 | *hotdrop = 1; | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | for (i = 0; i < optlen; ) { | ||
65 | if (op[i] == option) { | ||
66 | spin_unlock_bh(&dccp_buflock); | ||
67 | return 1; | ||
68 | } | ||
69 | |||
70 | if (op[i] < 2) | ||
71 | i++; | ||
72 | else | ||
73 | i += op[i+1]?:1; | ||
74 | } | ||
75 | |||
76 | spin_unlock_bh(&dccp_buflock); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | |||
81 | static inline int | ||
82 | match_types(const struct dccp_hdr *dh, u_int16_t typemask) | ||
83 | { | ||
84 | return (typemask & (1 << dh->dccph_type)); | ||
85 | } | ||
86 | |||
87 | static inline int | ||
88 | match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff, | ||
89 | const struct dccp_hdr *dh, int *hotdrop) | ||
90 | { | ||
91 | return dccp_find_option(option, skb, protoff, dh, hotdrop); | ||
92 | } | ||
93 | |||
94 | static int | ||
95 | match(const struct sk_buff *skb, | ||
96 | const struct net_device *in, | ||
97 | const struct net_device *out, | ||
98 | const void *matchinfo, | ||
99 | int offset, | ||
100 | unsigned int protoff, | ||
101 | int *hotdrop) | ||
102 | { | ||
103 | const struct xt_dccp_info *info = | ||
104 | (const struct xt_dccp_info *)matchinfo; | ||
105 | struct dccp_hdr _dh, *dh; | ||
106 | |||
107 | if (offset) | ||
108 | return 0; | ||
109 | |||
110 | dh = skb_header_pointer(skb, protoff, sizeof(_dh), &_dh); | ||
111 | if (dh == NULL) { | ||
112 | *hotdrop = 1; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | return DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0]) | ||
117 | && (ntohs(dh->dccph_sport) <= info->spts[1])), | ||
118 | XT_DCCP_SRC_PORTS, info->flags, info->invflags) | ||
119 | && DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0]) | ||
120 | && (ntohs(dh->dccph_dport) <= info->dpts[1])), | ||
121 | XT_DCCP_DEST_PORTS, info->flags, info->invflags) | ||
122 | && DCCHECK(match_types(dh, info->typemask), | ||
123 | XT_DCCP_TYPE, info->flags, info->invflags) | ||
124 | && DCCHECK(match_option(info->option, skb, protoff, dh, | ||
125 | hotdrop), | ||
126 | XT_DCCP_OPTION, info->flags, info->invflags); | ||
127 | } | ||
128 | |||
129 | static int | ||
130 | checkentry(const char *tablename, | ||
131 | const void *inf, | ||
132 | void *matchinfo, | ||
133 | unsigned int matchsize, | ||
134 | unsigned int hook_mask) | ||
135 | { | ||
136 | const struct ipt_ip *ip = inf; | ||
137 | const struct xt_dccp_info *info; | ||
138 | |||
139 | info = (const struct xt_dccp_info *)matchinfo; | ||
140 | |||
141 | return ip->proto == IPPROTO_DCCP | ||
142 | && !(ip->invflags & XT_INV_PROTO) | ||
143 | && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info)) | ||
144 | && !(info->flags & ~XT_DCCP_VALID_FLAGS) | ||
145 | && !(info->invflags & ~XT_DCCP_VALID_FLAGS) | ||
146 | && !(info->invflags & ~info->flags); | ||
147 | } | ||
148 | |||
149 | static int | ||
150 | checkentry6(const char *tablename, | ||
151 | const void *inf, | ||
152 | void *matchinfo, | ||
153 | unsigned int matchsize, | ||
154 | unsigned int hook_mask) | ||
155 | { | ||
156 | const struct ip6t_ip6 *ip = inf; | ||
157 | const struct xt_dccp_info *info; | ||
158 | |||
159 | info = (const struct xt_dccp_info *)matchinfo; | ||
160 | |||
161 | return ip->proto == IPPROTO_DCCP | ||
162 | && !(ip->invflags & XT_INV_PROTO) | ||
163 | && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info)) | ||
164 | && !(info->flags & ~XT_DCCP_VALID_FLAGS) | ||
165 | && !(info->invflags & ~XT_DCCP_VALID_FLAGS) | ||
166 | && !(info->invflags & ~info->flags); | ||
167 | } | ||
168 | |||
169 | |||
170 | static struct xt_match dccp_match = | ||
171 | { | ||
172 | .name = "dccp", | ||
173 | .match = &match, | ||
174 | .checkentry = &checkentry, | ||
175 | .me = THIS_MODULE, | ||
176 | }; | ||
177 | static struct xt_match dccp6_match = | ||
178 | { | ||
179 | .name = "dccp", | ||
180 | .match = &match, | ||
181 | .checkentry = &checkentry6, | ||
182 | .me = THIS_MODULE, | ||
183 | }; | ||
184 | |||
185 | |||
186 | static int __init init(void) | ||
187 | { | ||
188 | int ret; | ||
189 | |||
190 | /* doff is 8 bits, so the maximum option size is (4*256). Don't put | ||
191 | * this in BSS since DaveM is worried about locked TLB's for kernel | ||
192 | * BSS. */ | ||
193 | dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); | ||
194 | if (!dccp_optbuf) | ||
195 | return -ENOMEM; | ||
196 | ret = xt_register_match(AF_INET, &dccp_match); | ||
197 | if (ret) | ||
198 | goto out_kfree; | ||
199 | ret = xt_register_match(AF_INET6, &dccp6_match); | ||
200 | if (ret) | ||
201 | goto out_unreg; | ||
202 | |||
203 | return ret; | ||
204 | |||
205 | out_unreg: | ||
206 | xt_unregister_match(AF_INET, &dccp_match); | ||
207 | out_kfree: | ||
208 | kfree(dccp_optbuf); | ||
209 | |||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static void __exit fini(void) | ||
214 | { | ||
215 | xt_unregister_match(AF_INET6, &dccp6_match); | ||
216 | xt_unregister_match(AF_INET, &dccp_match); | ||
217 | kfree(dccp_optbuf); | ||
218 | } | ||
219 | |||
220 | module_init(init); | ||
221 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c new file mode 100644 index 000000000000..38b6715e1db4 --- /dev/null +++ b/net/netfilter/xt_helper.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* iptables module to match on related connections */ | ||
2 | /* | ||
3 | * (C) 2001 Martin Josefsson <gandalf@wlug.westbo.se> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * 19 Mar 2002 Harald Welte <laforge@gnumonks.org>: | ||
10 | * - Port to newnat infrastructure | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/netfilter.h> | ||
16 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
17 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
18 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
19 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
20 | #else | ||
21 | #include <net/netfilter/nf_conntrack.h> | ||
22 | #include <net/netfilter/nf_conntrack_core.h> | ||
23 | #include <net/netfilter/nf_conntrack_helper.h> | ||
24 | #endif | ||
25 | #include <linux/netfilter/x_tables.h> | ||
26 | #include <linux/netfilter/xt_helper.h> | ||
27 | |||
28 | MODULE_LICENSE("GPL"); | ||
29 | MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>"); | ||
30 | MODULE_DESCRIPTION("iptables helper match module"); | ||
31 | MODULE_ALIAS("ipt_helper"); | ||
32 | MODULE_ALIAS("ip6t_helper"); | ||
33 | |||
34 | #if 0 | ||
35 | #define DEBUGP printk | ||
36 | #else | ||
37 | #define DEBUGP(format, args...) | ||
38 | #endif | ||
39 | |||
40 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
41 | static int | ||
42 | match(const struct sk_buff *skb, | ||
43 | const struct net_device *in, | ||
44 | const struct net_device *out, | ||
45 | const void *matchinfo, | ||
46 | int offset, | ||
47 | unsigned int protoff, | ||
48 | int *hotdrop) | ||
49 | { | ||
50 | const struct xt_helper_info *info = matchinfo; | ||
51 | struct ip_conntrack *ct; | ||
52 | enum ip_conntrack_info ctinfo; | ||
53 | int ret = info->invert; | ||
54 | |||
55 | ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | ||
56 | if (!ct) { | ||
57 | DEBUGP("xt_helper: Eek! invalid conntrack?\n"); | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | if (!ct->master) { | ||
62 | DEBUGP("xt_helper: conntrack %p has no master\n", ct); | ||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | read_lock_bh(&ip_conntrack_lock); | ||
67 | if (!ct->master->helper) { | ||
68 | DEBUGP("xt_helper: master ct %p has no helper\n", | ||
69 | exp->expectant); | ||
70 | goto out_unlock; | ||
71 | } | ||
72 | |||
73 | DEBUGP("master's name = %s , info->name = %s\n", | ||
74 | ct->master->helper->name, info->name); | ||
75 | |||
76 | if (info->name[0] == '\0') | ||
77 | ret ^= 1; | ||
78 | else | ||
79 | ret ^= !strncmp(ct->master->helper->name, info->name, | ||
80 | strlen(ct->master->helper->name)); | ||
81 | out_unlock: | ||
82 | read_unlock_bh(&ip_conntrack_lock); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
87 | |||
88 | static int | ||
89 | match(const struct sk_buff *skb, | ||
90 | const struct net_device *in, | ||
91 | const struct net_device *out, | ||
92 | const void *matchinfo, | ||
93 | int offset, | ||
94 | unsigned int protoff, | ||
95 | int *hotdrop) | ||
96 | { | ||
97 | const struct xt_helper_info *info = matchinfo; | ||
98 | struct nf_conn *ct; | ||
99 | enum ip_conntrack_info ctinfo; | ||
100 | int ret = info->invert; | ||
101 | |||
102 | ct = nf_ct_get((struct sk_buff *)skb, &ctinfo); | ||
103 | if (!ct) { | ||
104 | DEBUGP("xt_helper: Eek! invalid conntrack?\n"); | ||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | if (!ct->master) { | ||
109 | DEBUGP("xt_helper: conntrack %p has no master\n", ct); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | read_lock_bh(&nf_conntrack_lock); | ||
114 | if (!ct->master->helper) { | ||
115 | DEBUGP("xt_helper: master ct %p has no helper\n", | ||
116 | exp->expectant); | ||
117 | goto out_unlock; | ||
118 | } | ||
119 | |||
120 | DEBUGP("master's name = %s , info->name = %s\n", | ||
121 | ct->master->helper->name, info->name); | ||
122 | |||
123 | if (info->name[0] == '\0') | ||
124 | ret ^= 1; | ||
125 | else | ||
126 | ret ^= !strncmp(ct->master->helper->name, info->name, | ||
127 | strlen(ct->master->helper->name)); | ||
128 | out_unlock: | ||
129 | read_unlock_bh(&nf_conntrack_lock); | ||
130 | return ret; | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | static int check(const char *tablename, | ||
135 | const void *inf, | ||
136 | void *matchinfo, | ||
137 | unsigned int matchsize, | ||
138 | unsigned int hook_mask) | ||
139 | { | ||
140 | struct xt_helper_info *info = matchinfo; | ||
141 | |||
142 | info->name[29] = '\0'; | ||
143 | |||
144 | /* verify size */ | ||
145 | if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info))) | ||
146 | return 0; | ||
147 | |||
148 | return 1; | ||
149 | } | ||
150 | |||
151 | static struct xt_match helper_match = { | ||
152 | .name = "helper", | ||
153 | .match = &match, | ||
154 | .checkentry = &check, | ||
155 | .me = THIS_MODULE, | ||
156 | }; | ||
157 | static struct xt_match helper6_match = { | ||
158 | .name = "helper", | ||
159 | .match = &match, | ||
160 | .checkentry = &check, | ||
161 | .me = THIS_MODULE, | ||
162 | }; | ||
163 | |||
164 | static int __init init(void) | ||
165 | { | ||
166 | int ret; | ||
167 | need_conntrack(); | ||
168 | |||
169 | ret = xt_register_match(AF_INET, &helper_match); | ||
170 | if (ret < 0) | ||
171 | return ret; | ||
172 | |||
173 | ret = xt_register_match(AF_INET6, &helper6_match); | ||
174 | if (ret < 0) | ||
175 | xt_unregister_match(AF_INET, &helper_match); | ||
176 | |||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static void __exit fini(void) | ||
181 | { | ||
182 | xt_unregister_match(AF_INET, &helper_match); | ||
183 | xt_unregister_match(AF_INET6, &helper6_match); | ||
184 | } | ||
185 | |||
186 | module_init(init); | ||
187 | module_exit(fini); | ||
188 | |||
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c new file mode 100644 index 000000000000..ab6c710cf88f --- /dev/null +++ b/net/netfilter/xt_length.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* Kernel module to match packet length. */ | ||
2 | /* (C) 1999-2001 James Morris <jmorros@intercode.com.au> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/skbuff.h> | ||
11 | #include <net/ip.h> | ||
12 | |||
13 | #include <linux/netfilter/xt_length.h> | ||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | |||
16 | MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); | ||
17 | MODULE_DESCRIPTION("IP tables packet length matching module"); | ||
18 | MODULE_LICENSE("GPL"); | ||
19 | MODULE_ALIAS("ipt_length"); | ||
20 | MODULE_ALIAS("ip6t_length"); | ||
21 | |||
22 | static int | ||
23 | match(const struct sk_buff *skb, | ||
24 | const struct net_device *in, | ||
25 | const struct net_device *out, | ||
26 | const void *matchinfo, | ||
27 | int offset, | ||
28 | unsigned int protoff, | ||
29 | int *hotdrop) | ||
30 | { | ||
31 | const struct xt_length_info *info = matchinfo; | ||
32 | u_int16_t pktlen = ntohs(skb->nh.iph->tot_len); | ||
33 | |||
34 | return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; | ||
35 | } | ||
36 | |||
37 | static int | ||
38 | match6(const struct sk_buff *skb, | ||
39 | const struct net_device *in, | ||
40 | const struct net_device *out, | ||
41 | const void *matchinfo, | ||
42 | int offset, | ||
43 | unsigned int protoff, | ||
44 | int *hotdrop) | ||
45 | { | ||
46 | const struct xt_length_info *info = matchinfo; | ||
47 | u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr); | ||
48 | |||
49 | return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; | ||
50 | } | ||
51 | |||
52 | static int | ||
53 | checkentry(const char *tablename, | ||
54 | const void *ip, | ||
55 | void *matchinfo, | ||
56 | unsigned int matchsize, | ||
57 | unsigned int hook_mask) | ||
58 | { | ||
59 | if (matchsize != XT_ALIGN(sizeof(struct xt_length_info))) | ||
60 | return 0; | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | static struct xt_match length_match = { | ||
66 | .name = "length", | ||
67 | .match = &match, | ||
68 | .checkentry = &checkentry, | ||
69 | .me = THIS_MODULE, | ||
70 | }; | ||
71 | static struct xt_match length6_match = { | ||
72 | .name = "length", | ||
73 | .match = &match6, | ||
74 | .checkentry = &checkentry, | ||
75 | .me = THIS_MODULE, | ||
76 | }; | ||
77 | |||
78 | static int __init init(void) | ||
79 | { | ||
80 | int ret; | ||
81 | ret = xt_register_match(AF_INET, &length_match); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | ret = xt_register_match(AF_INET6, &length6_match); | ||
85 | if (ret) | ||
86 | xt_unregister_match(AF_INET, &length_match); | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | static void __exit fini(void) | ||
92 | { | ||
93 | xt_unregister_match(AF_INET, &length_match); | ||
94 | xt_unregister_match(AF_INET6, &length6_match); | ||
95 | } | ||
96 | |||
97 | module_init(init); | ||
98 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c new file mode 100644 index 000000000000..15e40506bc3a --- /dev/null +++ b/net/netfilter/xt_limit.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* Kernel module to control the rate | ||
2 | * | ||
3 | * 2 September 1999: Changed from the target RATE to the match | ||
4 | * `limit', removed logging. Did I mention that | ||
5 | * Alexey is a fucking genius? | ||
6 | * Rusty Russell (rusty@rustcorp.com.au). */ | ||
7 | |||
8 | /* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> | ||
9 | * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | |||
21 | #include <linux/netfilter/x_tables.h> | ||
22 | #include <linux/netfilter/xt_limit.h> | ||
23 | |||
24 | MODULE_LICENSE("GPL"); | ||
25 | MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); | ||
26 | MODULE_DESCRIPTION("iptables rate limit match"); | ||
27 | MODULE_ALIAS("ipt_limit"); | ||
28 | MODULE_ALIAS("ip6t_limit"); | ||
29 | |||
30 | /* The algorithm used is the Simple Token Bucket Filter (TBF) | ||
31 | * see net/sched/sch_tbf.c in the linux source tree | ||
32 | */ | ||
33 | |||
34 | static DEFINE_SPINLOCK(limit_lock); | ||
35 | |||
36 | /* Rusty: This is my (non-mathematically-inclined) understanding of | ||
37 | this algorithm. The `average rate' in jiffies becomes your initial | ||
38 | amount of credit `credit' and the most credit you can ever have | ||
39 | `credit_cap'. The `peak rate' becomes the cost of passing the | ||
40 | test, `cost'. | ||
41 | |||
42 | `prev' tracks the last packet hit: you gain one credit per jiffy. | ||
43 | If you get credit balance more than this, the extra credit is | ||
44 | discarded. Every time the match passes, you lose `cost' credits; | ||
45 | if you don't have that many, the test fails. | ||
46 | |||
47 | See Alexey's formal explanation in net/sched/sch_tbf.c. | ||
48 | |||
49 | To get the maxmum range, we multiply by this factor (ie. you get N | ||
50 | credits per jiffy). We want to allow a rate as low as 1 per day | ||
51 | (slowest userspace tool allows), which means | ||
52 | CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */ | ||
53 | #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) | ||
54 | |||
55 | /* Repeated shift and or gives us all 1s, final shift and add 1 gives | ||
56 | * us the power of 2 below the theoretical max, so GCC simply does a | ||
57 | * shift. */ | ||
58 | #define _POW2_BELOW2(x) ((x)|((x)>>1)) | ||
59 | #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) | ||
60 | #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) | ||
61 | #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) | ||
62 | #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) | ||
63 | #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) | ||
64 | |||
65 | #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) | ||
66 | |||
67 | static int | ||
68 | ipt_limit_match(const struct sk_buff *skb, | ||
69 | const struct net_device *in, | ||
70 | const struct net_device *out, | ||
71 | const void *matchinfo, | ||
72 | int offset, | ||
73 | unsigned int protoff, | ||
74 | int *hotdrop) | ||
75 | { | ||
76 | struct xt_rateinfo *r = ((struct xt_rateinfo *)matchinfo)->master; | ||
77 | unsigned long now = jiffies; | ||
78 | |||
79 | spin_lock_bh(&limit_lock); | ||
80 | r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY; | ||
81 | if (r->credit > r->credit_cap) | ||
82 | r->credit = r->credit_cap; | ||
83 | |||
84 | if (r->credit >= r->cost) { | ||
85 | /* We're not limited. */ | ||
86 | r->credit -= r->cost; | ||
87 | spin_unlock_bh(&limit_lock); | ||
88 | return 1; | ||
89 | } | ||
90 | |||
91 | spin_unlock_bh(&limit_lock); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | /* Precision saver. */ | ||
96 | static u_int32_t | ||
97 | user2credits(u_int32_t user) | ||
98 | { | ||
99 | /* If multiplying would overflow... */ | ||
100 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) | ||
101 | /* Divide first. */ | ||
102 | return (user / XT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; | ||
103 | |||
104 | return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE; | ||
105 | } | ||
106 | |||
107 | static int | ||
108 | ipt_limit_checkentry(const char *tablename, | ||
109 | const void *inf, | ||
110 | void *matchinfo, | ||
111 | unsigned int matchsize, | ||
112 | unsigned int hook_mask) | ||
113 | { | ||
114 | struct xt_rateinfo *r = matchinfo; | ||
115 | |||
116 | if (matchsize != XT_ALIGN(sizeof(struct xt_rateinfo))) | ||
117 | return 0; | ||
118 | |||
119 | /* Check for overflow. */ | ||
120 | if (r->burst == 0 | ||
121 | || user2credits(r->avg * r->burst) < user2credits(r->avg)) { | ||
122 | printk("Overflow in xt_limit, try lower: %u/%u\n", | ||
123 | r->avg, r->burst); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * | ||
128 | 128. */ | ||
129 | r->prev = jiffies; | ||
130 | r->credit = user2credits(r->avg * r->burst); /* Credits full. */ | ||
131 | r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ | ||
132 | r->cost = user2credits(r->avg); | ||
133 | |||
134 | /* For SMP, we only want to use one set of counters. */ | ||
135 | r->master = r; | ||
136 | |||
137 | return 1; | ||
138 | } | ||
139 | |||
140 | static struct xt_match ipt_limit_reg = { | ||
141 | .name = "limit", | ||
142 | .match = ipt_limit_match, | ||
143 | .checkentry = ipt_limit_checkentry, | ||
144 | .me = THIS_MODULE, | ||
145 | }; | ||
146 | static struct xt_match limit6_reg = { | ||
147 | .name = "limit", | ||
148 | .match = ipt_limit_match, | ||
149 | .checkentry = ipt_limit_checkentry, | ||
150 | .me = THIS_MODULE, | ||
151 | }; | ||
152 | |||
153 | static int __init init(void) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | ret = xt_register_match(AF_INET, &ipt_limit_reg); | ||
158 | if (ret) | ||
159 | return ret; | ||
160 | |||
161 | ret = xt_register_match(AF_INET6, &limit6_reg); | ||
162 | if (ret) | ||
163 | xt_unregister_match(AF_INET, &ipt_limit_reg); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static void __exit fini(void) | ||
169 | { | ||
170 | xt_unregister_match(AF_INET, &ipt_limit_reg); | ||
171 | xt_unregister_match(AF_INET6, &limit6_reg); | ||
172 | } | ||
173 | |||
174 | module_init(init); | ||
175 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c new file mode 100644 index 000000000000..0461dcb5fc7a --- /dev/null +++ b/net/netfilter/xt_mac.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* Kernel module to match MAC address parameters. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/if_ether.h> | ||
14 | #include <linux/etherdevice.h> | ||
15 | |||
16 | #include <linux/netfilter_ipv4.h> | ||
17 | #include <linux/netfilter/xt_mac.h> | ||
18 | #include <linux/netfilter/x_tables.h> | ||
19 | |||
20 | MODULE_LICENSE("GPL"); | ||
21 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
22 | MODULE_DESCRIPTION("iptables mac matching module"); | ||
23 | MODULE_ALIAS("ipt_mac"); | ||
24 | MODULE_ALIAS("ip6t_mac"); | ||
25 | |||
26 | static int | ||
27 | match(const struct sk_buff *skb, | ||
28 | const struct net_device *in, | ||
29 | const struct net_device *out, | ||
30 | const void *matchinfo, | ||
31 | int offset, | ||
32 | unsigned int protoff, | ||
33 | int *hotdrop) | ||
34 | { | ||
35 | const struct xt_mac_info *info = matchinfo; | ||
36 | |||
37 | /* Is mac pointer valid? */ | ||
38 | return (skb->mac.raw >= skb->head | ||
39 | && (skb->mac.raw + ETH_HLEN) <= skb->data | ||
40 | /* If so, compare... */ | ||
41 | && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr)) | ||
42 | ^ info->invert)); | ||
43 | } | ||
44 | |||
45 | static int | ||
46 | ipt_mac_checkentry(const char *tablename, | ||
47 | const void *inf, | ||
48 | void *matchinfo, | ||
49 | unsigned int matchsize, | ||
50 | unsigned int hook_mask) | ||
51 | { | ||
52 | /* FORWARD isn't always valid, but it's nice to be able to do --RR */ | ||
53 | if (hook_mask | ||
54 | & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | ||
55 | | (1 << NF_IP_FORWARD))) { | ||
56 | printk("xt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n"); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | if (matchsize != XT_ALIGN(sizeof(struct xt_mac_info))) | ||
61 | return 0; | ||
62 | |||
63 | return 1; | ||
64 | } | ||
65 | |||
66 | static struct xt_match mac_match = { | ||
67 | .name = "mac", | ||
68 | .match = &match, | ||
69 | .checkentry = &ipt_mac_checkentry, | ||
70 | .me = THIS_MODULE, | ||
71 | }; | ||
72 | static struct xt_match mac6_match = { | ||
73 | .name = "mac", | ||
74 | .match = &match, | ||
75 | .checkentry = &ipt_mac_checkentry, | ||
76 | .me = THIS_MODULE, | ||
77 | }; | ||
78 | |||
79 | static int __init init(void) | ||
80 | { | ||
81 | int ret; | ||
82 | ret = xt_register_match(AF_INET, &mac_match); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | |||
86 | ret = xt_register_match(AF_INET6, &mac6_match); | ||
87 | if (ret) | ||
88 | xt_unregister_match(AF_INET, &mac_match); | ||
89 | |||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | static void __exit fini(void) | ||
94 | { | ||
95 | xt_unregister_match(AF_INET, &mac_match); | ||
96 | xt_unregister_match(AF_INET6, &mac6_match); | ||
97 | } | ||
98 | |||
99 | module_init(init); | ||
100 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c new file mode 100644 index 000000000000..2a0ac62b72c8 --- /dev/null +++ b/net/netfilter/xt_mark.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* Kernel module to match NFMARK values. */ | ||
2 | |||
3 | /* (C) 1999-2001 Marc Boucher <marc@mbsi.ca> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | |||
13 | #include <linux/netfilter/xt_mark.h> | ||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | |||
16 | MODULE_LICENSE("GPL"); | ||
17 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | ||
18 | MODULE_DESCRIPTION("iptables mark matching module"); | ||
19 | MODULE_ALIAS("ipt_mark"); | ||
20 | MODULE_ALIAS("ip6t_mark"); | ||
21 | |||
22 | static int | ||
23 | match(const struct sk_buff *skb, | ||
24 | const struct net_device *in, | ||
25 | const struct net_device *out, | ||
26 | const void *matchinfo, | ||
27 | int offset, | ||
28 | unsigned int protoff, | ||
29 | int *hotdrop) | ||
30 | { | ||
31 | const struct xt_mark_info *info = matchinfo; | ||
32 | |||
33 | return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; | ||
34 | } | ||
35 | |||
36 | static int | ||
37 | checkentry(const char *tablename, | ||
38 | const void *entry, | ||
39 | void *matchinfo, | ||
40 | unsigned int matchsize, | ||
41 | unsigned int hook_mask) | ||
42 | { | ||
43 | struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo; | ||
44 | |||
45 | if (matchsize != XT_ALIGN(sizeof(struct xt_mark_info))) | ||
46 | return 0; | ||
47 | |||
48 | if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) { | ||
49 | printk(KERN_WARNING "mark: only supports 32bit mark\n"); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | static struct xt_match mark_match = { | ||
57 | .name = "mark", | ||
58 | .match = &match, | ||
59 | .checkentry = &checkentry, | ||
60 | .me = THIS_MODULE, | ||
61 | }; | ||
62 | |||
63 | static struct xt_match mark6_match = { | ||
64 | .name = "mark", | ||
65 | .match = &match, | ||
66 | .checkentry = &checkentry, | ||
67 | .me = THIS_MODULE, | ||
68 | }; | ||
69 | |||
70 | static int __init init(void) | ||
71 | { | ||
72 | int ret; | ||
73 | ret = xt_register_match(AF_INET, &mark_match); | ||
74 | if (ret) | ||
75 | return ret; | ||
76 | |||
77 | ret = xt_register_match(AF_INET6, &mark6_match); | ||
78 | if (ret) | ||
79 | xt_unregister_match(AF_INET, &mark_match); | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | static void __exit fini(void) | ||
85 | { | ||
86 | xt_unregister_match(AF_INET, &mark_match); | ||
87 | xt_unregister_match(AF_INET6, &mark6_match); | ||
88 | } | ||
89 | |||
90 | module_init(init); | ||
91 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c new file mode 100644 index 000000000000..19bb57c14dfe --- /dev/null +++ b/net/netfilter/xt_physdev.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* Kernel module to match the bridge port in and | ||
2 | * out device for IP packets coming into contact with a bridge. */ | ||
3 | |||
4 | /* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/netfilter/xt_physdev.h> | ||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | #include <linux/netfilter_bridge.h> | ||
16 | #define MATCH 1 | ||
17 | #define NOMATCH 0 | ||
18 | |||
19 | MODULE_LICENSE("GPL"); | ||
20 | MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); | ||
21 | MODULE_DESCRIPTION("iptables bridge physical device match module"); | ||
22 | MODULE_ALIAS("ipt_physdev"); | ||
23 | MODULE_ALIAS("ip6t_physdev"); | ||
24 | |||
25 | static int | ||
26 | match(const struct sk_buff *skb, | ||
27 | const struct net_device *in, | ||
28 | const struct net_device *out, | ||
29 | const void *matchinfo, | ||
30 | int offset, | ||
31 | unsigned int protoff, | ||
32 | int *hotdrop) | ||
33 | { | ||
34 | int i; | ||
35 | static const char nulldevname[IFNAMSIZ]; | ||
36 | const struct xt_physdev_info *info = matchinfo; | ||
37 | unsigned int ret; | ||
38 | const char *indev, *outdev; | ||
39 | struct nf_bridge_info *nf_bridge; | ||
40 | |||
41 | /* Not a bridged IP packet or no info available yet: | ||
42 | * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if | ||
43 | * the destination device will be a bridge. */ | ||
44 | if (!(nf_bridge = skb->nf_bridge)) { | ||
45 | /* Return MATCH if the invert flags of the used options are on */ | ||
46 | if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && | ||
47 | !(info->invert & XT_PHYSDEV_OP_BRIDGED)) | ||
48 | return NOMATCH; | ||
49 | if ((info->bitmask & XT_PHYSDEV_OP_ISIN) && | ||
50 | !(info->invert & XT_PHYSDEV_OP_ISIN)) | ||
51 | return NOMATCH; | ||
52 | if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) && | ||
53 | !(info->invert & XT_PHYSDEV_OP_ISOUT)) | ||
54 | return NOMATCH; | ||
55 | if ((info->bitmask & XT_PHYSDEV_OP_IN) && | ||
56 | !(info->invert & XT_PHYSDEV_OP_IN)) | ||
57 | return NOMATCH; | ||
58 | if ((info->bitmask & XT_PHYSDEV_OP_OUT) && | ||
59 | !(info->invert & XT_PHYSDEV_OP_OUT)) | ||
60 | return NOMATCH; | ||
61 | return MATCH; | ||
62 | } | ||
63 | |||
64 | /* This only makes sense in the FORWARD and POSTROUTING chains */ | ||
65 | if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && | ||
66 | (!!(nf_bridge->mask & BRNF_BRIDGED) ^ | ||
67 | !(info->invert & XT_PHYSDEV_OP_BRIDGED))) | ||
68 | return NOMATCH; | ||
69 | |||
70 | if ((info->bitmask & XT_PHYSDEV_OP_ISIN && | ||
71 | (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) || | ||
72 | (info->bitmask & XT_PHYSDEV_OP_ISOUT && | ||
73 | (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT)))) | ||
74 | return NOMATCH; | ||
75 | |||
76 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) | ||
77 | goto match_outdev; | ||
78 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; | ||
79 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) { | ||
80 | ret |= (((const unsigned int *)indev)[i] | ||
81 | ^ ((const unsigned int *)info->physindev)[i]) | ||
82 | & ((const unsigned int *)info->in_mask)[i]; | ||
83 | } | ||
84 | |||
85 | if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN)) | ||
86 | return NOMATCH; | ||
87 | |||
88 | match_outdev: | ||
89 | if (!(info->bitmask & XT_PHYSDEV_OP_OUT)) | ||
90 | return MATCH; | ||
91 | outdev = nf_bridge->physoutdev ? | ||
92 | nf_bridge->physoutdev->name : nulldevname; | ||
93 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) { | ||
94 | ret |= (((const unsigned int *)outdev)[i] | ||
95 | ^ ((const unsigned int *)info->physoutdev)[i]) | ||
96 | & ((const unsigned int *)info->out_mask)[i]; | ||
97 | } | ||
98 | |||
99 | return (ret != 0) ^ !(info->invert & XT_PHYSDEV_OP_OUT); | ||
100 | } | ||
101 | |||
102 | static int | ||
103 | checkentry(const char *tablename, | ||
104 | const void *ip, | ||
105 | void *matchinfo, | ||
106 | unsigned int matchsize, | ||
107 | unsigned int hook_mask) | ||
108 | { | ||
109 | const struct xt_physdev_info *info = matchinfo; | ||
110 | |||
111 | if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info))) | ||
112 | return 0; | ||
113 | if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || | ||
114 | info->bitmask & ~XT_PHYSDEV_OP_MASK) | ||
115 | return 0; | ||
116 | return 1; | ||
117 | } | ||
118 | |||
119 | static struct xt_match physdev_match = { | ||
120 | .name = "physdev", | ||
121 | .match = &match, | ||
122 | .checkentry = &checkentry, | ||
123 | .me = THIS_MODULE, | ||
124 | }; | ||
125 | |||
126 | static struct xt_match physdev6_match = { | ||
127 | .name = "physdev", | ||
128 | .match = &match, | ||
129 | .checkentry = &checkentry, | ||
130 | .me = THIS_MODULE, | ||
131 | }; | ||
132 | |||
133 | static int __init init(void) | ||
134 | { | ||
135 | int ret; | ||
136 | |||
137 | ret = xt_register_match(AF_INET, &physdev_match); | ||
138 | if (ret < 0) | ||
139 | return ret; | ||
140 | |||
141 | ret = xt_register_match(AF_INET6, &physdev6_match); | ||
142 | if (ret < 0) | ||
143 | xt_unregister_match(AF_INET, &physdev_match); | ||
144 | |||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | static void __exit fini(void) | ||
149 | { | ||
150 | xt_unregister_match(AF_INET, &physdev_match); | ||
151 | xt_unregister_match(AF_INET6, &physdev6_match); | ||
152 | } | ||
153 | |||
154 | module_init(init); | ||
155 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c new file mode 100644 index 000000000000..ab1b2630f97d --- /dev/null +++ b/net/netfilter/xt_pkttype.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* (C) 1999-2001 Michal Ludvig <michal@logix.cz> | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/skbuff.h> | ||
10 | #include <linux/if_ether.h> | ||
11 | #include <linux/if_packet.h> | ||
12 | |||
13 | #include <linux/netfilter/xt_pkttype.h> | ||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | |||
16 | MODULE_LICENSE("GPL"); | ||
17 | MODULE_AUTHOR("Michal Ludvig <michal@logix.cz>"); | ||
18 | MODULE_DESCRIPTION("IP tables match to match on linklayer packet type"); | ||
19 | MODULE_ALIAS("ipt_pkttype"); | ||
20 | MODULE_ALIAS("ip6t_pkttype"); | ||
21 | |||
22 | static int match(const struct sk_buff *skb, | ||
23 | const struct net_device *in, | ||
24 | const struct net_device *out, | ||
25 | const void *matchinfo, | ||
26 | int offset, | ||
27 | unsigned int protoff, | ||
28 | int *hotdrop) | ||
29 | { | ||
30 | const struct xt_pkttype_info *info = matchinfo; | ||
31 | |||
32 | return (skb->pkt_type == info->pkttype) ^ info->invert; | ||
33 | } | ||
34 | |||
35 | static int checkentry(const char *tablename, | ||
36 | const void *ip, | ||
37 | void *matchinfo, | ||
38 | unsigned int matchsize, | ||
39 | unsigned int hook_mask) | ||
40 | { | ||
41 | if (matchsize != XT_ALIGN(sizeof(struct xt_pkttype_info))) | ||
42 | return 0; | ||
43 | |||
44 | return 1; | ||
45 | } | ||
46 | |||
47 | static struct xt_match pkttype_match = { | ||
48 | .name = "pkttype", | ||
49 | .match = &match, | ||
50 | .checkentry = &checkentry, | ||
51 | .me = THIS_MODULE, | ||
52 | }; | ||
53 | static struct xt_match pkttype6_match = { | ||
54 | .name = "pkttype", | ||
55 | .match = &match, | ||
56 | .checkentry = &checkentry, | ||
57 | .me = THIS_MODULE, | ||
58 | }; | ||
59 | |||
60 | |||
61 | static int __init init(void) | ||
62 | { | ||
63 | int ret; | ||
64 | ret = xt_register_match(AF_INET, &pkttype_match); | ||
65 | if (ret) | ||
66 | return ret; | ||
67 | |||
68 | ret = xt_register_match(AF_INET6, &pkttype6_match); | ||
69 | if (ret) | ||
70 | xt_unregister_match(AF_INET, &pkttype_match); | ||
71 | |||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static void __exit fini(void) | ||
76 | { | ||
77 | xt_unregister_match(AF_INET, &pkttype_match); | ||
78 | xt_unregister_match(AF_INET6, &pkttype6_match); | ||
79 | } | ||
80 | |||
81 | module_init(init); | ||
82 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c new file mode 100644 index 000000000000..2b7e1781d34d --- /dev/null +++ b/net/netfilter/xt_realm.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* IP tables module for matching the routing realm | ||
2 | * | ||
3 | * $Id: ipt_realm.c,v 1.3 2004/03/05 13:25:40 laforge Exp $ | ||
4 | * | ||
5 | * (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/netdevice.h> | ||
15 | #include <net/route.h> | ||
16 | |||
17 | #include <linux/netfilter_ipv4.h> | ||
18 | #include <linux/netfilter/xt_realm.h> | ||
19 | #include <linux/netfilter/x_tables.h> | ||
20 | |||
21 | MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>"); | ||
22 | MODULE_LICENSE("GPL"); | ||
23 | MODULE_DESCRIPTION("X_tables realm match"); | ||
24 | MODULE_ALIAS("ipt_realm"); | ||
25 | |||
26 | static int | ||
27 | match(const struct sk_buff *skb, | ||
28 | const struct net_device *in, | ||
29 | const struct net_device *out, | ||
30 | const void *matchinfo, | ||
31 | int offset, | ||
32 | unsigned int protoff, | ||
33 | int *hotdrop) | ||
34 | { | ||
35 | const struct xt_realm_info *info = matchinfo; | ||
36 | struct dst_entry *dst = skb->dst; | ||
37 | |||
38 | return (info->id == (dst->tclassid & info->mask)) ^ info->invert; | ||
39 | } | ||
40 | |||
41 | static int check(const char *tablename, | ||
42 | const void *ip, | ||
43 | void *matchinfo, | ||
44 | unsigned int matchsize, | ||
45 | unsigned int hook_mask) | ||
46 | { | ||
47 | if (hook_mask | ||
48 | & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) | | ||
49 | (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) { | ||
50 | printk("xt_realm: only valid for POST_ROUTING, LOCAL_OUT, " | ||
51 | "LOCAL_IN or FORWARD.\n"); | ||
52 | return 0; | ||
53 | } | ||
54 | if (matchsize != XT_ALIGN(sizeof(struct xt_realm_info))) { | ||
55 | printk("xt_realm: invalid matchsize.\n"); | ||
56 | return 0; | ||
57 | } | ||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | static struct xt_match realm_match = { | ||
62 | .name = "realm", | ||
63 | .match = match, | ||
64 | .checkentry = check, | ||
65 | .me = THIS_MODULE | ||
66 | }; | ||
67 | |||
68 | static int __init init(void) | ||
69 | { | ||
70 | return xt_register_match(AF_INET, &realm_match); | ||
71 | } | ||
72 | |||
73 | static void __exit fini(void) | ||
74 | { | ||
75 | xt_unregister_match(AF_INET, &realm_match); | ||
76 | } | ||
77 | |||
78 | module_init(init); | ||
79 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c new file mode 100644 index 000000000000..10fbfc5ba758 --- /dev/null +++ b/net/netfilter/xt_sctp.c | |||
@@ -0,0 +1,250 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/skbuff.h> | ||
3 | #include <net/ip.h> | ||
4 | #include <net/ipv6.h> | ||
5 | #include <linux/sctp.h> | ||
6 | |||
7 | #include <linux/netfilter/x_tables.h> | ||
8 | #include <linux/netfilter/xt_sctp.h> | ||
9 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
10 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
11 | |||
12 | MODULE_LICENSE("GPL"); | ||
13 | MODULE_AUTHOR("Kiran Kumar Immidi"); | ||
14 | MODULE_DESCRIPTION("Match for SCTP protocol packets"); | ||
15 | MODULE_ALIAS("ipt_sctp"); | ||
16 | |||
17 | #ifdef DEBUG_SCTP | ||
18 | #define duprintf(format, args...) printk(format , ## args) | ||
19 | #else | ||
20 | #define duprintf(format, args...) | ||
21 | #endif | ||
22 | |||
23 | #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ | ||
24 | || (!!((invflag) & (option)) ^ (cond))) | ||
25 | |||
26 | static int | ||
27 | match_flags(const struct xt_sctp_flag_info *flag_info, | ||
28 | const int flag_count, | ||
29 | u_int8_t chunktype, | ||
30 | u_int8_t chunkflags) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | for (i = 0; i < flag_count; i++) { | ||
35 | if (flag_info[i].chunktype == chunktype) { | ||
36 | return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | return 1; | ||
41 | } | ||
42 | |||
43 | static inline int | ||
44 | match_packet(const struct sk_buff *skb, | ||
45 | unsigned int offset, | ||
46 | const u_int32_t *chunkmap, | ||
47 | int chunk_match_type, | ||
48 | const struct xt_sctp_flag_info *flag_info, | ||
49 | const int flag_count, | ||
50 | int *hotdrop) | ||
51 | { | ||
52 | u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)]; | ||
53 | sctp_chunkhdr_t _sch, *sch; | ||
54 | |||
55 | #ifdef DEBUG_SCTP | ||
56 | int i = 0; | ||
57 | #endif | ||
58 | |||
59 | if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) { | ||
60 | SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap); | ||
61 | } | ||
62 | |||
63 | do { | ||
64 | sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch); | ||
65 | if (sch == NULL) { | ||
66 | duprintf("Dropping invalid SCTP packet.\n"); | ||
67 | *hotdrop = 1; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", | ||
72 | ++i, offset, sch->type, htons(sch->length), sch->flags); | ||
73 | |||
74 | offset += (htons(sch->length) + 3) & ~3; | ||
75 | |||
76 | duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); | ||
77 | |||
78 | if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) { | ||
79 | switch (chunk_match_type) { | ||
80 | case SCTP_CHUNK_MATCH_ANY: | ||
81 | if (match_flags(flag_info, flag_count, | ||
82 | sch->type, sch->flags)) { | ||
83 | return 1; | ||
84 | } | ||
85 | break; | ||
86 | |||
87 | case SCTP_CHUNK_MATCH_ALL: | ||
88 | if (match_flags(flag_info, flag_count, | ||
89 | sch->type, sch->flags)) { | ||
90 | SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type); | ||
91 | } | ||
92 | break; | ||
93 | |||
94 | case SCTP_CHUNK_MATCH_ONLY: | ||
95 | if (!match_flags(flag_info, flag_count, | ||
96 | sch->type, sch->flags)) { | ||
97 | return 0; | ||
98 | } | ||
99 | break; | ||
100 | } | ||
101 | } else { | ||
102 | switch (chunk_match_type) { | ||
103 | case SCTP_CHUNK_MATCH_ONLY: | ||
104 | return 0; | ||
105 | } | ||
106 | } | ||
107 | } while (offset < skb->len); | ||
108 | |||
109 | switch (chunk_match_type) { | ||
110 | case SCTP_CHUNK_MATCH_ALL: | ||
111 | return SCTP_CHUNKMAP_IS_CLEAR(chunkmap); | ||
112 | case SCTP_CHUNK_MATCH_ANY: | ||
113 | return 0; | ||
114 | case SCTP_CHUNK_MATCH_ONLY: | ||
115 | return 1; | ||
116 | } | ||
117 | |||
118 | /* This will never be reached, but required to stop compiler whine */ | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int | ||
123 | match(const struct sk_buff *skb, | ||
124 | const struct net_device *in, | ||
125 | const struct net_device *out, | ||
126 | const void *matchinfo, | ||
127 | int offset, | ||
128 | unsigned int protoff, | ||
129 | int *hotdrop) | ||
130 | { | ||
131 | const struct xt_sctp_info *info; | ||
132 | sctp_sctphdr_t _sh, *sh; | ||
133 | |||
134 | info = (const struct xt_sctp_info *)matchinfo; | ||
135 | |||
136 | if (offset) { | ||
137 | duprintf("Dropping non-first fragment.. FIXME\n"); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | sh = skb_header_pointer(skb, protoff, sizeof(_sh), &_sh); | ||
142 | if (sh == NULL) { | ||
143 | duprintf("Dropping evil TCP offset=0 tinygram.\n"); | ||
144 | *hotdrop = 1; | ||
145 | return 0; | ||
146 | } | ||
147 | duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest)); | ||
148 | |||
149 | return SCCHECK(((ntohs(sh->source) >= info->spts[0]) | ||
150 | && (ntohs(sh->source) <= info->spts[1])), | ||
151 | XT_SCTP_SRC_PORTS, info->flags, info->invflags) | ||
152 | && SCCHECK(((ntohs(sh->dest) >= info->dpts[0]) | ||
153 | && (ntohs(sh->dest) <= info->dpts[1])), | ||
154 | XT_SCTP_DEST_PORTS, info->flags, info->invflags) | ||
155 | && SCCHECK(match_packet(skb, protoff, | ||
156 | info->chunkmap, info->chunk_match_type, | ||
157 | info->flag_info, info->flag_count, | ||
158 | hotdrop), | ||
159 | XT_SCTP_CHUNK_TYPES, info->flags, info->invflags); | ||
160 | } | ||
161 | |||
162 | static int | ||
163 | checkentry(const char *tablename, | ||
164 | const void *inf, | ||
165 | void *matchinfo, | ||
166 | unsigned int matchsize, | ||
167 | unsigned int hook_mask) | ||
168 | { | ||
169 | const struct xt_sctp_info *info; | ||
170 | const struct ipt_ip *ip = inf; | ||
171 | |||
172 | info = (const struct xt_sctp_info *)matchinfo; | ||
173 | |||
174 | return ip->proto == IPPROTO_SCTP | ||
175 | && !(ip->invflags & XT_INV_PROTO) | ||
176 | && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info)) | ||
177 | && !(info->flags & ~XT_SCTP_VALID_FLAGS) | ||
178 | && !(info->invflags & ~XT_SCTP_VALID_FLAGS) | ||
179 | && !(info->invflags & ~info->flags) | ||
180 | && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || | ||
181 | (info->chunk_match_type & | ||
182 | (SCTP_CHUNK_MATCH_ALL | ||
183 | | SCTP_CHUNK_MATCH_ANY | ||
184 | | SCTP_CHUNK_MATCH_ONLY))); | ||
185 | } | ||
186 | |||
187 | static int | ||
188 | checkentry6(const char *tablename, | ||
189 | const void *inf, | ||
190 | void *matchinfo, | ||
191 | unsigned int matchsize, | ||
192 | unsigned int hook_mask) | ||
193 | { | ||
194 | const struct xt_sctp_info *info; | ||
195 | const struct ip6t_ip6 *ip = inf; | ||
196 | |||
197 | info = (const struct xt_sctp_info *)matchinfo; | ||
198 | |||
199 | return ip->proto == IPPROTO_SCTP | ||
200 | && !(ip->invflags & XT_INV_PROTO) | ||
201 | && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info)) | ||
202 | && !(info->flags & ~XT_SCTP_VALID_FLAGS) | ||
203 | && !(info->invflags & ~XT_SCTP_VALID_FLAGS) | ||
204 | && !(info->invflags & ~info->flags) | ||
205 | && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || | ||
206 | (info->chunk_match_type & | ||
207 | (SCTP_CHUNK_MATCH_ALL | ||
208 | | SCTP_CHUNK_MATCH_ANY | ||
209 | | SCTP_CHUNK_MATCH_ONLY))); | ||
210 | } | ||
211 | |||
212 | |||
213 | static struct xt_match sctp_match = | ||
214 | { | ||
215 | .name = "sctp", | ||
216 | .match = &match, | ||
217 | .checkentry = &checkentry, | ||
218 | .me = THIS_MODULE | ||
219 | }; | ||
220 | static struct xt_match sctp6_match = | ||
221 | { | ||
222 | .name = "sctp", | ||
223 | .match = &match, | ||
224 | .checkentry = &checkentry6, | ||
225 | .me = THIS_MODULE | ||
226 | }; | ||
227 | |||
228 | |||
229 | static int __init init(void) | ||
230 | { | ||
231 | int ret; | ||
232 | ret = xt_register_match(AF_INET, &sctp_match); | ||
233 | if (ret) | ||
234 | return ret; | ||
235 | |||
236 | ret = xt_register_match(AF_INET6, &sctp6_match); | ||
237 | if (ret) | ||
238 | xt_unregister_match(AF_INET, &sctp_match); | ||
239 | |||
240 | return ret; | ||
241 | } | ||
242 | |||
243 | static void __exit fini(void) | ||
244 | { | ||
245 | xt_unregister_match(AF_INET6, &sctp6_match); | ||
246 | xt_unregister_match(AF_INET, &sctp_match); | ||
247 | } | ||
248 | |||
249 | module_init(init); | ||
250 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c new file mode 100644 index 000000000000..39ce808d40ef --- /dev/null +++ b/net/netfilter/xt_state.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* Kernel module to match connection tracking information. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <net/netfilter/nf_conntrack_compat.h> | ||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | #include <linux/netfilter/xt_state.h> | ||
16 | |||
17 | MODULE_LICENSE("GPL"); | ||
18 | MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); | ||
19 | MODULE_DESCRIPTION("ip[6]_tables connection tracking state match module"); | ||
20 | MODULE_ALIAS("ipt_state"); | ||
21 | MODULE_ALIAS("ip6t_state"); | ||
22 | |||
23 | static int | ||
24 | match(const struct sk_buff *skb, | ||
25 | const struct net_device *in, | ||
26 | const struct net_device *out, | ||
27 | const void *matchinfo, | ||
28 | int offset, | ||
29 | unsigned int protoff, | ||
30 | int *hotdrop) | ||
31 | { | ||
32 | const struct xt_state_info *sinfo = matchinfo; | ||
33 | enum ip_conntrack_info ctinfo; | ||
34 | unsigned int statebit; | ||
35 | |||
36 | if (nf_ct_is_untracked(skb)) | ||
37 | statebit = XT_STATE_UNTRACKED; | ||
38 | else if (!nf_ct_get_ctinfo(skb, &ctinfo)) | ||
39 | statebit = XT_STATE_INVALID; | ||
40 | else | ||
41 | statebit = XT_STATE_BIT(ctinfo); | ||
42 | |||
43 | return (sinfo->statemask & statebit); | ||
44 | } | ||
45 | |||
46 | static int check(const char *tablename, | ||
47 | const void *ip, | ||
48 | void *matchinfo, | ||
49 | unsigned int matchsize, | ||
50 | unsigned int hook_mask) | ||
51 | { | ||
52 | if (matchsize != XT_ALIGN(sizeof(struct xt_state_info))) | ||
53 | return 0; | ||
54 | |||
55 | return 1; | ||
56 | } | ||
57 | |||
58 | static struct xt_match state_match = { | ||
59 | .name = "state", | ||
60 | .match = &match, | ||
61 | .checkentry = &check, | ||
62 | .me = THIS_MODULE, | ||
63 | }; | ||
64 | |||
65 | static struct xt_match state6_match = { | ||
66 | .name = "state", | ||
67 | .match = &match, | ||
68 | .checkentry = &check, | ||
69 | .me = THIS_MODULE, | ||
70 | }; | ||
71 | |||
72 | static int __init init(void) | ||
73 | { | ||
74 | int ret; | ||
75 | |||
76 | need_conntrack(); | ||
77 | |||
78 | ret = xt_register_match(AF_INET, &state_match); | ||
79 | if (ret < 0) | ||
80 | return ret; | ||
81 | |||
82 | ret = xt_register_match(AF_INET6, &state6_match); | ||
83 | if (ret < 0) | ||
84 | xt_unregister_match(AF_INET,&state_match); | ||
85 | |||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | static void __exit fini(void) | ||
90 | { | ||
91 | xt_unregister_match(AF_INET, &state_match); | ||
92 | xt_unregister_match(AF_INET6, &state6_match); | ||
93 | } | ||
94 | |||
95 | module_init(init); | ||
96 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c new file mode 100644 index 000000000000..7c7d5c8807d6 --- /dev/null +++ b/net/netfilter/xt_string.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* String matching match for iptables | ||
2 | * | ||
3 | * (C) 2005 Pablo Neira Ayuso <pablo@eurodev.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/netfilter/x_tables.h> | ||
15 | #include <linux/netfilter/xt_string.h> | ||
16 | #include <linux/textsearch.h> | ||
17 | |||
18 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@eurodev.net>"); | ||
19 | MODULE_DESCRIPTION("IP tables string match module"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | MODULE_ALIAS("ipt_string"); | ||
22 | MODULE_ALIAS("ip6t_string"); | ||
23 | |||
24 | static int match(const struct sk_buff *skb, | ||
25 | const struct net_device *in, | ||
26 | const struct net_device *out, | ||
27 | const void *matchinfo, | ||
28 | int offset, | ||
29 | unsigned int protoff, | ||
30 | int *hotdrop) | ||
31 | { | ||
32 | struct ts_state state; | ||
33 | struct xt_string_info *conf = (struct xt_string_info *) matchinfo; | ||
34 | |||
35 | memset(&state, 0, sizeof(struct ts_state)); | ||
36 | |||
37 | return (skb_find_text((struct sk_buff *)skb, conf->from_offset, | ||
38 | conf->to_offset, conf->config, &state) | ||
39 | != UINT_MAX) && !conf->invert; | ||
40 | } | ||
41 | |||
42 | #define STRING_TEXT_PRIV(m) ((struct xt_string_info *) m) | ||
43 | |||
44 | static int checkentry(const char *tablename, | ||
45 | const void *ip, | ||
46 | void *matchinfo, | ||
47 | unsigned int matchsize, | ||
48 | unsigned int hook_mask) | ||
49 | { | ||
50 | struct xt_string_info *conf = matchinfo; | ||
51 | struct ts_config *ts_conf; | ||
52 | |||
53 | if (matchsize != XT_ALIGN(sizeof(struct xt_string_info))) | ||
54 | return 0; | ||
55 | |||
56 | /* Damn, can't handle this case properly with iptables... */ | ||
57 | if (conf->from_offset > conf->to_offset) | ||
58 | return 0; | ||
59 | |||
60 | ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen, | ||
61 | GFP_KERNEL, TS_AUTOLOAD); | ||
62 | if (IS_ERR(ts_conf)) | ||
63 | return 0; | ||
64 | |||
65 | conf->config = ts_conf; | ||
66 | |||
67 | return 1; | ||
68 | } | ||
69 | |||
70 | static void destroy(void *matchinfo, unsigned int matchsize) | ||
71 | { | ||
72 | textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config); | ||
73 | } | ||
74 | |||
75 | static struct xt_match string_match = { | ||
76 | .name = "string", | ||
77 | .match = match, | ||
78 | .checkentry = checkentry, | ||
79 | .destroy = destroy, | ||
80 | .me = THIS_MODULE | ||
81 | }; | ||
82 | static struct xt_match string6_match = { | ||
83 | .name = "string", | ||
84 | .match = match, | ||
85 | .checkentry = checkentry, | ||
86 | .destroy = destroy, | ||
87 | .me = THIS_MODULE | ||
88 | }; | ||
89 | |||
90 | static int __init init(void) | ||
91 | { | ||
92 | int ret; | ||
93 | |||
94 | ret = xt_register_match(AF_INET, &string_match); | ||
95 | if (ret) | ||
96 | return ret; | ||
97 | ret = xt_register_match(AF_INET6, &string6_match); | ||
98 | if (ret) | ||
99 | xt_unregister_match(AF_INET, &string_match); | ||
100 | |||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static void __exit fini(void) | ||
105 | { | ||
106 | xt_unregister_match(AF_INET, &string_match); | ||
107 | xt_unregister_match(AF_INET6, &string6_match); | ||
108 | } | ||
109 | |||
110 | module_init(init); | ||
111 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c new file mode 100644 index 000000000000..acf7f533e9f1 --- /dev/null +++ b/net/netfilter/xt_tcpmss.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /* Kernel module to match TCP MSS values. */ | ||
2 | |||
3 | /* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca> | ||
4 | * Portions (C) 2005 by Harald Welte <laforge@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <net/tcp.h> | ||
14 | |||
15 | #include <linux/netfilter/xt_tcpmss.h> | ||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | |||
18 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
19 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
20 | |||
21 | #define TH_SYN 0x02 | ||
22 | |||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | ||
25 | MODULE_DESCRIPTION("iptables TCP MSS match module"); | ||
26 | MODULE_ALIAS("ipt_tcpmss"); | ||
27 | |||
28 | /* Returns 1 if the mss option is set and matched by the range, 0 otherwise */ | ||
29 | static inline int | ||
30 | mssoption_match(u_int16_t min, u_int16_t max, | ||
31 | const struct sk_buff *skb, | ||
32 | unsigned int protoff, | ||
33 | int invert, | ||
34 | int *hotdrop) | ||
35 | { | ||
36 | struct tcphdr _tcph, *th; | ||
37 | /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ | ||
38 | u8 _opt[15 * 4 - sizeof(_tcph)], *op; | ||
39 | unsigned int i, optlen; | ||
40 | |||
41 | /* If we don't have the whole header, drop packet. */ | ||
42 | th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); | ||
43 | if (th == NULL) | ||
44 | goto dropit; | ||
45 | |||
46 | /* Malformed. */ | ||
47 | if (th->doff*4 < sizeof(*th)) | ||
48 | goto dropit; | ||
49 | |||
50 | optlen = th->doff*4 - sizeof(*th); | ||
51 | if (!optlen) | ||
52 | goto out; | ||
53 | |||
54 | /* Truncated options. */ | ||
55 | op = skb_header_pointer(skb, protoff + sizeof(*th), optlen, _opt); | ||
56 | if (op == NULL) | ||
57 | goto dropit; | ||
58 | |||
59 | for (i = 0; i < optlen; ) { | ||
60 | if (op[i] == TCPOPT_MSS | ||
61 | && (optlen - i) >= TCPOLEN_MSS | ||
62 | && op[i+1] == TCPOLEN_MSS) { | ||
63 | u_int16_t mssval; | ||
64 | |||
65 | mssval = (op[i+2] << 8) | op[i+3]; | ||
66 | |||
67 | return (mssval >= min && mssval <= max) ^ invert; | ||
68 | } | ||
69 | if (op[i] < 2) i++; | ||
70 | else i += op[i+1]?:1; | ||
71 | } | ||
72 | out: | ||
73 | return invert; | ||
74 | |||
75 | dropit: | ||
76 | *hotdrop = 1; | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int | ||
81 | match(const struct sk_buff *skb, | ||
82 | const struct net_device *in, | ||
83 | const struct net_device *out, | ||
84 | const void *matchinfo, | ||
85 | int offset, | ||
86 | unsigned int protoff, | ||
87 | int *hotdrop) | ||
88 | { | ||
89 | const struct xt_tcpmss_match_info *info = matchinfo; | ||
90 | |||
91 | return mssoption_match(info->mss_min, info->mss_max, skb, protoff, | ||
92 | info->invert, hotdrop); | ||
93 | } | ||
94 | |||
95 | static int | ||
96 | checkentry(const char *tablename, | ||
97 | const void *ipinfo, | ||
98 | void *matchinfo, | ||
99 | unsigned int matchsize, | ||
100 | unsigned int hook_mask) | ||
101 | { | ||
102 | const struct ipt_ip *ip = ipinfo; | ||
103 | if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info))) | ||
104 | return 0; | ||
105 | |||
106 | /* Must specify -p tcp */ | ||
107 | if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) { | ||
108 | printk("tcpmss: Only works on TCP packets\n"); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | static int | ||
116 | checkentry6(const char *tablename, | ||
117 | const void *ipinfo, | ||
118 | void *matchinfo, | ||
119 | unsigned int matchsize, | ||
120 | unsigned int hook_mask) | ||
121 | { | ||
122 | const struct ip6t_ip6 *ip = ipinfo; | ||
123 | |||
124 | if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info))) | ||
125 | return 0; | ||
126 | |||
127 | /* Must specify -p tcp */ | ||
128 | if (ip->proto != IPPROTO_TCP || (ip->invflags & XT_INV_PROTO)) { | ||
129 | printk("tcpmss: Only works on TCP packets\n"); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | static struct xt_match tcpmss_match = { | ||
137 | .name = "tcpmss", | ||
138 | .match = &match, | ||
139 | .checkentry = &checkentry, | ||
140 | .me = THIS_MODULE, | ||
141 | }; | ||
142 | |||
143 | static struct xt_match tcpmss6_match = { | ||
144 | .name = "tcpmss", | ||
145 | .match = &match, | ||
146 | .checkentry = &checkentry6, | ||
147 | .me = THIS_MODULE, | ||
148 | }; | ||
149 | |||
150 | |||
151 | static int __init init(void) | ||
152 | { | ||
153 | int ret; | ||
154 | ret = xt_register_match(AF_INET, &tcpmss_match); | ||
155 | if (ret) | ||
156 | return ret; | ||
157 | |||
158 | ret = xt_register_match(AF_INET6, &tcpmss6_match); | ||
159 | if (ret) | ||
160 | xt_unregister_match(AF_INET, &tcpmss_match); | ||
161 | |||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static void __exit fini(void) | ||
166 | { | ||
167 | xt_unregister_match(AF_INET6, &tcpmss6_match); | ||
168 | xt_unregister_match(AF_INET, &tcpmss_match); | ||
169 | } | ||
170 | |||
171 | module_init(init); | ||
172 | module_exit(fini); | ||
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c new file mode 100644 index 000000000000..33f86fd6f3e6 --- /dev/null +++ b/net/netfilter/xt_tcpudp.c | |||
@@ -0,0 +1,333 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <net/ip.h> | ||
4 | #include <net/ipv6.h> | ||
5 | #include <net/tcp.h> | ||
6 | #include <net/udp.h> | ||
7 | #include <linux/netfilter/x_tables.h> | ||
8 | #include <linux/netfilter/xt_tcpudp.h> | ||
9 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
10 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
11 | |||
12 | MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6"); | ||
13 | MODULE_LICENSE("GPL"); | ||
14 | MODULE_ALIAS("xt_tcp"); | ||
15 | MODULE_ALIAS("xt_udp"); | ||
16 | MODULE_ALIAS("ipt_udp"); | ||
17 | MODULE_ALIAS("ipt_tcp"); | ||
18 | MODULE_ALIAS("ip6t_udp"); | ||
19 | MODULE_ALIAS("ip6t_tcp"); | ||
20 | |||
21 | #ifdef DEBUG_IP_FIREWALL_USER | ||
22 | #define duprintf(format, args...) printk(format , ## args) | ||
23 | #else | ||
24 | #define duprintf(format, args...) | ||
25 | #endif | ||
26 | |||
27 | |||
28 | /* Returns 1 if the port is matched by the range, 0 otherwise */ | ||
29 | static inline int | ||
30 | port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert) | ||
31 | { | ||
32 | int ret; | ||
33 | |||
34 | ret = (port >= min && port <= max) ^ invert; | ||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | tcp_find_option(u_int8_t option, | ||
40 | const struct sk_buff *skb, | ||
41 | unsigned int protoff, | ||
42 | unsigned int optlen, | ||
43 | int invert, | ||
44 | int *hotdrop) | ||
45 | { | ||
46 | /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ | ||
47 | u_int8_t _opt[60 - sizeof(struct tcphdr)], *op; | ||
48 | unsigned int i; | ||
49 | |||
50 | duprintf("tcp_match: finding option\n"); | ||
51 | |||
52 | if (!optlen) | ||
53 | return invert; | ||
54 | |||
55 | /* If we don't have the whole header, drop packet. */ | ||
56 | op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr), | ||
57 | optlen, _opt); | ||
58 | if (op == NULL) { | ||
59 | *hotdrop = 1; | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | for (i = 0; i < optlen; ) { | ||
64 | if (op[i] == option) return !invert; | ||
65 | if (op[i] < 2) i++; | ||
66 | else i += op[i+1]?:1; | ||
67 | } | ||
68 | |||
69 | return invert; | ||
70 | } | ||
71 | |||
72 | static int | ||
73 | tcp_match(const struct sk_buff *skb, | ||
74 | const struct net_device *in, | ||
75 | const struct net_device *out, | ||
76 | const void *matchinfo, | ||
77 | int offset, | ||
78 | unsigned int protoff, | ||
79 | int *hotdrop) | ||
80 | { | ||
81 | struct tcphdr _tcph, *th; | ||
82 | const struct xt_tcp *tcpinfo = matchinfo; | ||
83 | |||
84 | if (offset) { | ||
85 | /* To quote Alan: | ||
86 | |||
87 | Don't allow a fragment of TCP 8 bytes in. Nobody normal | ||
88 | causes this. Its a cracker trying to break in by doing a | ||
89 | flag overwrite to pass the direction checks. | ||
90 | */ | ||
91 | if (offset == 1) { | ||
92 | duprintf("Dropping evil TCP offset=1 frag.\n"); | ||
93 | *hotdrop = 1; | ||
94 | } | ||
95 | /* Must not be a fragment. */ | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) | ||
100 | |||
101 | th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); | ||
102 | if (th == NULL) { | ||
103 | /* We've been asked to examine this packet, and we | ||
104 | can't. Hence, no choice but to drop. */ | ||
105 | duprintf("Dropping evil TCP offset=0 tinygram.\n"); | ||
106 | *hotdrop = 1; | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], | ||
111 | ntohs(th->source), | ||
112 | !!(tcpinfo->invflags & XT_TCP_INV_SRCPT))) | ||
113 | return 0; | ||
114 | if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], | ||
115 | ntohs(th->dest), | ||
116 | !!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) | ||
117 | return 0; | ||
118 | if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) | ||
119 | == tcpinfo->flg_cmp, | ||
120 | XT_TCP_INV_FLAGS)) | ||
121 | return 0; | ||
122 | if (tcpinfo->option) { | ||
123 | if (th->doff * 4 < sizeof(_tcph)) { | ||
124 | *hotdrop = 1; | ||
125 | return 0; | ||
126 | } | ||
127 | if (!tcp_find_option(tcpinfo->option, skb, protoff, | ||
128 | th->doff*4 - sizeof(_tcph), | ||
129 | tcpinfo->invflags & XT_TCP_INV_OPTION, | ||
130 | hotdrop)) | ||
131 | return 0; | ||
132 | } | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | /* Called when user tries to insert an entry of this type. */ | ||
137 | static int | ||
138 | tcp_checkentry(const char *tablename, | ||
139 | const void *info, | ||
140 | void *matchinfo, | ||
141 | unsigned int matchsize, | ||
142 | unsigned int hook_mask) | ||
143 | { | ||
144 | const struct ipt_ip *ip = info; | ||
145 | const struct xt_tcp *tcpinfo = matchinfo; | ||
146 | |||
147 | /* Must specify proto == TCP, and no unknown invflags */ | ||
148 | return ip->proto == IPPROTO_TCP | ||
149 | && !(ip->invflags & XT_INV_PROTO) | ||
150 | && matchsize == XT_ALIGN(sizeof(struct xt_tcp)) | ||
151 | && !(tcpinfo->invflags & ~XT_TCP_INV_MASK); | ||
152 | } | ||
153 | |||
154 | /* Called when user tries to insert an entry of this type. */ | ||
155 | static int | ||
156 | tcp6_checkentry(const char *tablename, | ||
157 | const void *entry, | ||
158 | void *matchinfo, | ||
159 | unsigned int matchsize, | ||
160 | unsigned int hook_mask) | ||
161 | { | ||
162 | const struct ip6t_ip6 *ipv6 = entry; | ||
163 | const struct xt_tcp *tcpinfo = matchinfo; | ||
164 | |||
165 | /* Must specify proto == TCP, and no unknown invflags */ | ||
166 | return ipv6->proto == IPPROTO_TCP | ||
167 | && !(ipv6->invflags & XT_INV_PROTO) | ||
168 | && matchsize == XT_ALIGN(sizeof(struct xt_tcp)) | ||
169 | && !(tcpinfo->invflags & ~XT_TCP_INV_MASK); | ||
170 | } | ||
171 | |||
172 | |||
173 | static int | ||
174 | udp_match(const struct sk_buff *skb, | ||
175 | const struct net_device *in, | ||
176 | const struct net_device *out, | ||
177 | const void *matchinfo, | ||
178 | int offset, | ||
179 | unsigned int protoff, | ||
180 | int *hotdrop) | ||
181 | { | ||
182 | struct udphdr _udph, *uh; | ||
183 | const struct xt_udp *udpinfo = matchinfo; | ||
184 | |||
185 | /* Must not be a fragment. */ | ||
186 | if (offset) | ||
187 | return 0; | ||
188 | |||
189 | uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph); | ||
190 | if (uh == NULL) { | ||
191 | /* We've been asked to examine this packet, and we | ||
192 | can't. Hence, no choice but to drop. */ | ||
193 | duprintf("Dropping evil UDP tinygram.\n"); | ||
194 | *hotdrop = 1; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | return port_match(udpinfo->spts[0], udpinfo->spts[1], | ||
199 | ntohs(uh->source), | ||
200 | !!(udpinfo->invflags & XT_UDP_INV_SRCPT)) | ||
201 | && port_match(udpinfo->dpts[0], udpinfo->dpts[1], | ||
202 | ntohs(uh->dest), | ||
203 | !!(udpinfo->invflags & XT_UDP_INV_DSTPT)); | ||
204 | } | ||
205 | |||
206 | /* Called when user tries to insert an entry of this type. */ | ||
207 | static int | ||
208 | udp_checkentry(const char *tablename, | ||
209 | const void *info, | ||
210 | void *matchinfo, | ||
211 | unsigned int matchinfosize, | ||
212 | unsigned int hook_mask) | ||
213 | { | ||
214 | const struct ipt_ip *ip = info; | ||
215 | const struct xt_udp *udpinfo = matchinfo; | ||
216 | |||
217 | /* Must specify proto == UDP, and no unknown invflags */ | ||
218 | if (ip->proto != IPPROTO_UDP || (ip->invflags & XT_INV_PROTO)) { | ||
219 | duprintf("ipt_udp: Protocol %u != %u\n", ip->proto, | ||
220 | IPPROTO_UDP); | ||
221 | return 0; | ||
222 | } | ||
223 | if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) { | ||
224 | duprintf("ipt_udp: matchsize %u != %u\n", | ||
225 | matchinfosize, XT_ALIGN(sizeof(struct xt_udp))); | ||
226 | return 0; | ||
227 | } | ||
228 | if (udpinfo->invflags & ~XT_UDP_INV_MASK) { | ||
229 | duprintf("ipt_udp: unknown flags %X\n", | ||
230 | udpinfo->invflags); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | return 1; | ||
235 | } | ||
236 | |||
237 | /* Called when user tries to insert an entry of this type. */ | ||
238 | static int | ||
239 | udp6_checkentry(const char *tablename, | ||
240 | const void *entry, | ||
241 | void *matchinfo, | ||
242 | unsigned int matchinfosize, | ||
243 | unsigned int hook_mask) | ||
244 | { | ||
245 | const struct ip6t_ip6 *ipv6 = entry; | ||
246 | const struct xt_udp *udpinfo = matchinfo; | ||
247 | |||
248 | /* Must specify proto == UDP, and no unknown invflags */ | ||
249 | if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & XT_INV_PROTO)) { | ||
250 | duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto, | ||
251 | IPPROTO_UDP); | ||
252 | return 0; | ||
253 | } | ||
254 | if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) { | ||
255 | duprintf("ip6t_udp: matchsize %u != %u\n", | ||
256 | matchinfosize, XT_ALIGN(sizeof(struct xt_udp))); | ||
257 | return 0; | ||
258 | } | ||
259 | if (udpinfo->invflags & ~XT_UDP_INV_MASK) { | ||
260 | duprintf("ip6t_udp: unknown flags %X\n", | ||
261 | udpinfo->invflags); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | return 1; | ||
266 | } | ||
267 | |||
268 | static struct xt_match tcp_matchstruct = { | ||
269 | .name = "tcp", | ||
270 | .match = &tcp_match, | ||
271 | .checkentry = &tcp_checkentry, | ||
272 | .me = THIS_MODULE, | ||
273 | }; | ||
274 | static struct xt_match tcp6_matchstruct = { | ||
275 | .name = "tcp", | ||
276 | .match = &tcp_match, | ||
277 | .checkentry = &tcp6_checkentry, | ||
278 | .me = THIS_MODULE, | ||
279 | }; | ||
280 | |||
281 | static struct xt_match udp_matchstruct = { | ||
282 | .name = "udp", | ||
283 | .match = &udp_match, | ||
284 | .checkentry = &udp_checkentry, | ||
285 | .me = THIS_MODULE, | ||
286 | }; | ||
287 | static struct xt_match udp6_matchstruct = { | ||
288 | .name = "udp", | ||
289 | .match = &udp_match, | ||
290 | .checkentry = &udp6_checkentry, | ||
291 | .me = THIS_MODULE, | ||
292 | }; | ||
293 | |||
294 | static int __init init(void) | ||
295 | { | ||
296 | int ret; | ||
297 | ret = xt_register_match(AF_INET, &tcp_matchstruct); | ||
298 | if (ret) | ||
299 | return ret; | ||
300 | |||
301 | ret = xt_register_match(AF_INET6, &tcp6_matchstruct); | ||
302 | if (ret) | ||
303 | goto out_unreg_tcp; | ||
304 | |||
305 | ret = xt_register_match(AF_INET, &udp_matchstruct); | ||
306 | if (ret) | ||
307 | goto out_unreg_tcp6; | ||
308 | |||
309 | ret = xt_register_match(AF_INET6, &udp6_matchstruct); | ||
310 | if (ret) | ||
311 | goto out_unreg_udp; | ||
312 | |||
313 | return ret; | ||
314 | |||
315 | out_unreg_udp: | ||
316 | xt_unregister_match(AF_INET, &tcp_matchstruct); | ||
317 | out_unreg_tcp6: | ||
318 | xt_unregister_match(AF_INET6, &tcp6_matchstruct); | ||
319 | out_unreg_tcp: | ||
320 | xt_unregister_match(AF_INET, &tcp_matchstruct); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | static void __exit fini(void) | ||
325 | { | ||
326 | xt_unregister_match(AF_INET6, &udp6_matchstruct); | ||
327 | xt_unregister_match(AF_INET, &udp_matchstruct); | ||
328 | xt_unregister_match(AF_INET6, &tcp6_matchstruct); | ||
329 | xt_unregister_match(AF_INET, &tcp_matchstruct); | ||
330 | } | ||
331 | |||
332 | module_init(init); | ||
333 | module_exit(fini); | ||