1 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h
2 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 00:00:00.000000000 +0000
3 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h 2004-03-05 07:40:01.000000000 +0000
5 +/* TTL modification module for IP tables
6 + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
17 +#define IPT_TTL_MAXMODE IPT_TTL_DEC
19 +struct ipt_TTL_info {
26 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h
27 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 00:00:00.000000000 +0000
28 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-03-05 07:40:04.000000000 +0000
30 +#ifndef _IPT_CONNLIMIT_H
31 +#define _IPT_CONNLIMIT_H
33 +struct ipt_connlimit_data;
35 +struct ipt_connlimit_info {
39 + struct ipt_connlimit_data *data;
41 +#endif /* _IPT_CONNLIMIT_H */
42 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h
43 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 00:00:00.000000000 +0000
44 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-03-05 07:40:06.000000000 +0000
46 +#ifndef _IPT_DSTLIMIT_H
47 +#define _IPT_DSTLIMIT_H
49 +/* timings are in milliseconds. */
50 +#define IPT_DSTLIMIT_SCALE 10000
51 +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
52 + seconds, or one every 59 hours. */
54 +/* details of this structure hidden by the implementation */
55 +struct ipt_dstlimit_htable;
57 +#define IPT_DSTLIMIT_HASH_DIP 0x0001
58 +#define IPT_DSTLIMIT_HASH_DPT 0x0002
59 +#define IPT_DSTLIMIT_HASH_SIP 0x0004
61 +struct dstlimit_cfg {
62 + u_int32_t mode; /* bitmask of IPT_DSTLIMIT_HASH_* */
63 + u_int32_t avg; /* Average secs between packets * scale */
64 + u_int32_t burst; /* Period multiplier for upper limit. */
66 + /* user specified */
67 + u_int32_t size; /* how many buckets */
68 + u_int32_t max; /* max number of entries */
69 + u_int32_t gc_interval; /* gc interval */
70 + u_int32_t expire; /* when do entries expire? */
73 +struct ipt_dstlimit_info {
74 + char name [IFNAMSIZ]; /* name */
75 + struct dstlimit_cfg cfg;
76 + struct ipt_dstlimit_htable *hinfo;
78 + /* Used internally by the kernel */
81 + struct ipt_dstlimit_info *master;
84 +#endif /*_IPT_DSTLIMIT_H*/
85 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h
86 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 00:00:00.000000000 +0000
87 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h 2004-03-05 07:40:08.000000000 +0000
92 +#include <linux/param.h>
93 +#include <linux/types.h>
95 +#define MAXFUZZYRATE 10000000
96 +#define MINFUZZYRATE 3
98 +struct ipt_fuzzy_info {
99 + u_int32_t minimum_rate;
100 + u_int32_t maximum_rate;
101 + u_int32_t packets_total;
102 + u_int32_t bytes_total;
103 + u_int32_t previous_time;
104 + u_int32_t present_time;
105 + u_int32_t mean_rate;
106 + u_int8_t acceptance_rate;
109 +#endif /*_IPT_FUZZY_H*/
110 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h
111 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 00:00:00.000000000 +0000
112 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-03-05 07:40:09.000000000 +0000
114 +#ifndef __ipt_ipv4options_h_included__
115 +#define __ipt_ipv4options_h_included__
117 +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */
118 +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */
119 +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */
120 +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */
121 +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10
122 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */
123 +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40
124 +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */
125 +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100
126 +#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */
127 +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */
129 +struct ipt_ipv4options_info {
134 +#endif /* __ipt_ipv4options_h_included__ */
135 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h
136 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 00:00:00.000000000 +0000
137 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h 2004-03-05 07:40:11.000000000 +0000
139 +#ifndef _IPT_MPORT_H
140 +#define _IPT_MPORT_H
141 +#include <linux/netfilter_ipv4/ip_tables.h>
143 +#define IPT_MPORT_SOURCE (1<<0)
144 +#define IPT_MPORT_DESTINATION (1<<1)
145 +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION)
147 +#define IPT_MULTI_PORTS 15
149 +/* Must fit inside union ipt_matchinfo: 32 bytes */
150 +/* every entry in ports[] except for the last one has one bit in pflags
151 + * associated with it. If this bit is set, the port is the first port of
152 + * a portrange, with the next entry being the last.
153 + * End of list is marked with pflags bit set and port=65535.
154 + * If 14 ports are used (last one does not have a pflag), the last port
155 + * is repeated to fill the last entry in ports[] */
158 + u_int8_t flags:2; /* Type of comparison */
159 + u_int16_t pflags:14; /* Port flags */
160 + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
162 +#endif /*_IPT_MPORT_H*/
163 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h
164 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 00:00:00.000000000 +0000
165 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h 2004-03-05 07:40:13.000000000 +0000
170 +#include <linux/param.h>
171 +#include <linux/types.h>
173 +#ifndef IPT_NTH_NUM_COUNTERS
174 +#define IPT_NTH_NUM_COUNTERS 16
177 +struct ipt_nth_info {
185 +#endif /*_IPT_NTH_H*/
186 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h
187 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 00:00:00.000000000 +0000
188 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h 2004-03-05 07:40:14.000000000 +0000
190 +#ifndef _IPT_QUOTA_H
191 +#define _IPT_QUOTA_H
193 +/* print debug info in both kernel/netfilter module & iptable library */
194 +//#define DEBUG_IPT_QUOTA
196 +struct ipt_quota_info {
200 +#endif /*_IPT_QUOTA_H*/
201 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h
202 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 00:00:00.000000000 +0000
203 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h 2004-03-05 07:40:22.000000000 +0000
205 +#ifndef _IPT_REALM_H
206 +#define _IPT_REALM_H
208 +struct ipt_realm_info {
213 +#endif /*_IPT_REALM_H*/
214 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h
215 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 00:00:00.000000000 +0000
216 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h 2004-03-05 07:40:24.000000000 +0000
218 +#ifndef _IPT_SCTP_H_
219 +#define _IPT_SCTP_H_
221 +#define IPT_SCTP_SRC_PORTS 0x01
222 +#define IPT_SCTP_DEST_PORTS 0x02
223 +#define IPT_SCTP_CHUNK_TYPES 0x04
225 +#define IPT_SCTP_VALID_FLAGS 0x07
227 +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
230 +struct ipt_sctp_flag_info {
231 + u_int8_t chunktype;
233 + u_int8_t flag_mask;
236 +#define IPT_NUM_SCTP_FLAGS 4
238 +struct ipt_sctp_info {
239 + u_int16_t dpts[2]; /* Min, Max */
240 + u_int16_t spts[2]; /* Min, Max */
242 + u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */
244 +#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */
245 +#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */
246 +#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */
248 + u_int32_t chunk_match_type;
249 + struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
253 + u_int32_t invflags;
256 +#define bytes(type) (sizeof(type) * 8)
258 +#define SCTP_CHUNKMAP_SET(chunkmap, type) \
260 + chunkmap[type / bytes(u_int32_t)] |= \
261 + 1 << (type % bytes(u_int32_t)); \
264 +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
266 + chunkmap[type / bytes(u_int32_t)] &= \
267 + ~(1 << (type % bytes(u_int32_t))); \
270 +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
272 + (chunkmap[type / bytes (u_int32_t)] & \
273 + (1 << (type % bytes (u_int32_t)))) ? 1: 0; \
276 +#define SCTP_CHUNKMAP_RESET(chunkmap) \
279 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
283 +#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
286 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
287 + chunkmap[i] = ~0; \
290 +#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
293 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
294 + destmap[i] = srcmap[i]; \
297 +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
301 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
302 + if (chunkmap[i]) { \
310 +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
314 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
315 + if (chunkmap[i] != ~0) { \
323 +#endif /* _IPT_SCTP_H_ */
325 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h
326 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 00:00:00.000000000 +0000
327 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h 2004-03-05 07:39:53.000000000 +0000
329 +/* Hop Limit modification module for ip6tables
330 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
331 + * Based on HW's TTL module */
333 +#ifndef _IP6T_HOPLIMIT_H
334 +#define _IP6T_HOPLIMIT_H
337 + IP6T_HOPLIMIT_SET = 0,
342 +#define IP6T_HOPLIMIT_MAXMODE IP6T_HOPLIMIT_DEC
344 +struct ip6t_HOPLIMIT_info {
346 + u_int8_t hop_limit;
351 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h
352 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-04 06:16:34.000000000 +0000
353 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-05 07:39:59.000000000 +0000
355 #define _IP6T_REJECT_H
357 enum ip6t_reject_with {
358 - IP6T_ICMP_NET_UNREACHABLE,
359 - IP6T_ICMP_HOST_UNREACHABLE,
360 - IP6T_ICMP_PROT_UNREACHABLE,
361 - IP6T_ICMP_PORT_UNREACHABLE,
362 - IP6T_ICMP_ECHOREPLY
363 + IP6T_ICMP6_NO_ROUTE,
364 + IP6T_ICMP6_ADM_PROHIBITED,
365 + IP6T_ICMP6_NOT_NEIGHBOUR,
366 + IP6T_ICMP6_ADDR_UNREACH,
367 + IP6T_ICMP6_PORT_UNREACH,
368 + IP6T_ICMP6_ECHOREPLY,
372 struct ip6t_reject_info {
373 enum ip6t_reject_with with; /* reject type */
376 -#endif /*_IPT_REJECT_H*/
377 +#endif /*_IP6T_REJECT_H*/
378 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h
379 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 00:00:00.000000000 +0000
380 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2004-03-05 07:40:08.000000000 +0000
382 +#ifndef _IP6T_FUZZY_H
383 +#define _IP6T_FUZZY_H
385 +#include <linux/param.h>
386 +#include <linux/types.h>
388 +#define MAXFUZZYRATE 10000000
389 +#define MINFUZZYRATE 3
391 +struct ip6t_fuzzy_info {
392 + u_int32_t minimum_rate;
393 + u_int32_t maximum_rate;
394 + u_int32_t packets_total;
395 + u_int32_t bytes_total;
396 + u_int32_t previous_time;
397 + u_int32_t present_time;
398 + u_int32_t mean_rate;
399 + u_int8_t acceptance_rate;
402 +#endif /*_IP6T_FUZZY_H*/
403 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h
404 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 00:00:00.000000000 +0000
405 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h 2004-03-05 07:40:13.000000000 +0000
410 +#include <linux/param.h>
411 +#include <linux/types.h>
413 +#ifndef IP6T_NTH_NUM_COUNTERS
414 +#define IP6T_NTH_NUM_COUNTERS 16
417 +struct ip6t_nth_info {
425 +#endif /*_IP6T_NTH_H*/
426 diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c linux-2.6.4-rc2/net/core/netfilter.c
427 --- linux-2.6.4-rc2.org/net/core/netfilter.c 2004-03-04 06:16:45.000000000 +0000
428 +++ linux-2.6.4-rc2/net/core/netfilter.c 2004-03-05 07:39:43.000000000 +0000
430 } queue_handler[NPROTO];
431 static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
434 + * nf_register_hook - Register with a netfilter hook
435 + * @reg: Hook operations to be registered
437 int nf_register_hook(struct nf_hook_ops *reg)
445 + * nf_unregister_hook - Unregister from a netfilter hook
446 + * @reg: hook operations to be unregistered
448 void nf_unregister_hook(struct nf_hook_ops *reg)
450 spin_lock_bh(&nf_hook_lock);
456 + * nf_register_queue_handler - Registere a queue handler with netfilter
457 + * @pf: protocol family
458 + * @outfn: function called by core to enqueue a packet
459 + * @data: opaque parameter, passed through
461 + * This function registers a queue handler with netfilter. There can only
462 + * be one queue handler for every protocol family.
464 + * A queue handler _must_ reinject every packet via nf_reinject, no
467 int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
474 -/* The caller must flush their queue before this */
476 + * nf_unregister_queue_handler - Unregister queue handler from netfilter
477 + * @pf: protocol family
479 + * The caller must flush their queue before unregistering
481 int nf_unregister_queue_handler(int pf)
483 write_lock_bh(&queue_handler_lock);
489 + * nf_reinject - Reinject a packet from a queue handler
490 + * @skb: the packet to be reinjected
491 + * @info: info which was passed to the outfn() of the queue handler
492 + * @verdict: verdict (NF_ACCEPT, ...) for this packet
494 + * This is the function called by a queue handler to reinject a
497 void nf_reinject(struct sk_buff *skb, struct nf_info *info,
498 unsigned int verdict)
500 diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c.orig linux-2.6.4-rc2/net/core/netfilter.c.orig
501 --- linux-2.6.4-rc2.org/net/core/netfilter.c.orig 1970-01-01 00:00:00.000000000 +0000
502 +++ linux-2.6.4-rc2/net/core/netfilter.c.orig 2004-03-04 06:16:45.000000000 +0000
504 +/* netfilter.c: look after the filters for various protocols.
505 + * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
507 + * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
510 + * Rusty Russell (C)2000 -- This code is GPL.
512 + * February 2000: Modified by James Morris to have 1 queue per protocol.
513 + * 15-Mar-2000: Added NF_REPEAT --RR.
515 +#include <linux/config.h>
516 +#include <linux/netfilter.h>
517 +#include <net/protocol.h>
518 +#include <linux/init.h>
519 +#include <linux/skbuff.h>
520 +#include <linux/wait.h>
521 +#include <linux/module.h>
522 +#include <linux/interrupt.h>
523 +#include <linux/if.h>
524 +#include <linux/netdevice.h>
525 +#include <linux/inetdevice.h>
526 +#include <linux/tcp.h>
527 +#include <linux/udp.h>
528 +#include <linux/icmp.h>
529 +#include <net/sock.h>
530 +#include <net/route.h>
531 +#include <linux/ip.h>
533 +/* In this code, we can be waiting indefinitely for userspace to
534 + * service a packet if a hook returns NF_QUEUE. We could keep a count
535 + * of skbuffs queued for userspace, and not deregister a hook unless
536 + * this is zero, but that sucks. Now, we simply check when the
537 + * packets come back: if the hook is gone, the packet is discarded. */
538 +#ifdef CONFIG_NETFILTER_DEBUG
539 +#define NFDEBUG(format, args...) printk(format , ## args)
541 +#define NFDEBUG(format, args...)
544 +/* Sockopts only registered and called from user context, so
545 + net locking would be overkill. Also, [gs]etsockopt calls may
547 +static DECLARE_MUTEX(nf_sockopt_mutex);
549 +struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
550 +static LIST_HEAD(nf_sockopts);
551 +static spinlock_t nf_hook_lock = SPIN_LOCK_UNLOCKED;
554 + * A queue handler may be registered for each protocol. Each is protected by
555 + * long term mutex. The handler must provide an an outfn() to accept packets
556 + * for queueing and must reinject all packets it receives, no matter what.
558 +static struct nf_queue_handler_t {
559 + nf_queue_outfn_t outfn;
561 +} queue_handler[NPROTO];
562 +static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
564 +int nf_register_hook(struct nf_hook_ops *reg)
566 + struct list_head *i;
568 + spin_lock_bh(&nf_hook_lock);
569 + list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
570 + if (reg->priority < ((struct nf_hook_ops *)i)->priority)
573 + list_add_rcu(®->list, i->prev);
574 + spin_unlock_bh(&nf_hook_lock);
580 +void nf_unregister_hook(struct nf_hook_ops *reg)
582 + spin_lock_bh(&nf_hook_lock);
583 + list_del_rcu(®->list);
584 + spin_unlock_bh(&nf_hook_lock);
589 +/* Do exclusive ranges overlap? */
590 +static inline int overlap(int min1, int max1, int min2, int max2)
592 + return max1 > min2 && min1 < max2;
595 +/* Functions to register sockopt ranges (exclusive). */
596 +int nf_register_sockopt(struct nf_sockopt_ops *reg)
598 + struct list_head *i;
601 + if (down_interruptible(&nf_sockopt_mutex) != 0)
604 + list_for_each(i, &nf_sockopts) {
605 + struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
606 + if (ops->pf == reg->pf
607 + && (overlap(ops->set_optmin, ops->set_optmax,
608 + reg->set_optmin, reg->set_optmax)
609 + || overlap(ops->get_optmin, ops->get_optmax,
610 + reg->get_optmin, reg->get_optmax))) {
611 + NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
612 + ops->set_optmin, ops->set_optmax,
613 + ops->get_optmin, ops->get_optmax,
614 + reg->set_optmin, reg->set_optmax,
615 + reg->get_optmin, reg->get_optmax);
621 + list_add(®->list, &nf_sockopts);
623 + up(&nf_sockopt_mutex);
627 +void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
629 + /* No point being interruptible: we're probably in cleanup_module() */
631 + down(&nf_sockopt_mutex);
632 + if (reg->use != 0) {
633 + /* To be woken by nf_sockopt call... */
634 + /* FIXME: Stuart Young's name appears gratuitously. */
635 + set_current_state(TASK_UNINTERRUPTIBLE);
636 + reg->cleanup_task = current;
637 + up(&nf_sockopt_mutex);
641 + list_del(®->list);
642 + up(&nf_sockopt_mutex);
645 +#ifdef CONFIG_NETFILTER_DEBUG
647 +#include <net/tcp.h>
648 +#include <linux/netfilter_ipv4.h>
650 +static void debug_print_hooks_ip(unsigned int nf_debug)
652 + if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
653 + printk("PRE_ROUTING ");
654 + nf_debug ^= (1 << NF_IP_PRE_ROUTING);
656 + if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
657 + printk("LOCAL_IN ");
658 + nf_debug ^= (1 << NF_IP_LOCAL_IN);
660 + if (nf_debug & (1 << NF_IP_FORWARD)) {
661 + printk("FORWARD ");
662 + nf_debug ^= (1 << NF_IP_FORWARD);
664 + if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
665 + printk("LOCAL_OUT ");
666 + nf_debug ^= (1 << NF_IP_LOCAL_OUT);
668 + if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
669 + printk("POST_ROUTING ");
670 + nf_debug ^= (1 << NF_IP_POST_ROUTING);
673 + printk("Crap bits: 0x%04X", nf_debug);
677 +void nf_dump_skb(int pf, struct sk_buff *skb)
679 + printk("skb: pf=%i %s dev=%s len=%u\n",
681 + skb->sk ? "(owned)" : "(unowned)",
682 + skb->dev ? skb->dev->name : "(no dev)",
686 + const struct iphdr *ip = skb->nh.iph;
687 + __u32 *opt = (__u32 *) (ip + 1);
689 + __u16 src_port = 0, dst_port = 0;
691 + if (ip->protocol == IPPROTO_TCP
692 + || ip->protocol == IPPROTO_UDP) {
693 + struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
694 + src_port = ntohs(tcp->source);
695 + dst_port = ntohs(tcp->dest);
698 + printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
699 + " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
700 + ip->protocol, NIPQUAD(ip->saddr),
701 + src_port, NIPQUAD(ip->daddr),
703 + ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
704 + ntohs(ip->frag_off), ip->ttl);
706 + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
707 + printk(" O=0x%8.8X", *opt++);
713 +void nf_debug_ip_local_deliver(struct sk_buff *skb)
715 + /* If it's a loopback packet, it must have come through
716 + * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and
717 + * NF_IP_LOCAL_IN. Otherwise, must have gone through
718 + * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */
720 + printk("ip_local_deliver: skb->dev is NULL.\n");
722 + else if (strcmp(skb->dev->name, "lo") == 0) {
723 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
724 + | (1 << NF_IP_POST_ROUTING)
725 + | (1 << NF_IP_PRE_ROUTING)
726 + | (1 << NF_IP_LOCAL_IN))) {
727 + printk("ip_local_deliver: bad loopback skb: ");
728 + debug_print_hooks_ip(skb->nf_debug);
729 + nf_dump_skb(PF_INET, skb);
733 + if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)
734 + | (1<<NF_IP_LOCAL_IN))) {
735 + printk("ip_local_deliver: bad non-lo skb: ");
736 + debug_print_hooks_ip(skb->nf_debug);
737 + nf_dump_skb(PF_INET, skb);
742 +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb)
744 + if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
745 + | (1 << NF_IP_POST_ROUTING))) {
746 + printk("ip_dev_loopback_xmit: bad owned skb = %p: ",
748 + debug_print_hooks_ip(newskb->nf_debug);
749 + nf_dump_skb(PF_INET, newskb);
751 + /* Clear to avoid confusing input check */
752 + newskb->nf_debug = 0;
755 +void nf_debug_ip_finish_output2(struct sk_buff *skb)
757 + /* If it's owned, it must have gone through the
758 + * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING.
759 + * Otherwise, must have gone through
760 + * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING.
763 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
764 + | (1 << NF_IP_POST_ROUTING))) {
765 + printk("ip_finish_output: bad owned skb = %p: ", skb);
766 + debug_print_hooks_ip(skb->nf_debug);
767 + nf_dump_skb(PF_INET, skb);
770 + if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING)
771 + | (1 << NF_IP_FORWARD)
772 + | (1 << NF_IP_POST_ROUTING))) {
773 + /* Fragments, entunnelled packets, TCP RSTs
774 + generated by ipt_REJECT will have no
775 + owners, but still may be local */
776 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
777 + | (1 << NF_IP_POST_ROUTING))){
778 + printk("ip_finish_output:"
779 + " bad unowned skb = %p: ",skb);
780 + debug_print_hooks_ip(skb->nf_debug);
781 + nf_dump_skb(PF_INET, skb);
786 +#endif /*CONFIG_NETFILTER_DEBUG*/
788 +/* Call get/setsockopt() */
789 +static int nf_sockopt(struct sock *sk, int pf, int val,
790 + char *opt, int *len, int get)
792 + struct list_head *i;
793 + struct nf_sockopt_ops *ops;
796 + if (down_interruptible(&nf_sockopt_mutex) != 0)
799 + list_for_each(i, &nf_sockopts) {
800 + ops = (struct nf_sockopt_ops *)i;
801 + if (ops->pf == pf) {
803 + if (val >= ops->get_optmin
804 + && val < ops->get_optmax) {
806 + up(&nf_sockopt_mutex);
807 + ret = ops->get(sk, val, opt, len);
811 + if (val >= ops->set_optmin
812 + && val < ops->set_optmax) {
814 + up(&nf_sockopt_mutex);
815 + ret = ops->set(sk, val, opt, *len);
821 + up(&nf_sockopt_mutex);
822 + return -ENOPROTOOPT;
825 + down(&nf_sockopt_mutex);
827 + if (ops->cleanup_task)
828 + wake_up_process(ops->cleanup_task);
829 + up(&nf_sockopt_mutex);
833 +int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
836 + return nf_sockopt(sk, pf, val, opt, &len, 0);
839 +int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
841 + return nf_sockopt(sk, pf, val, opt, len, 1);
844 +static unsigned int nf_iterate(struct list_head *head,
845 + struct sk_buff **skb,
847 + const struct net_device *indev,
848 + const struct net_device *outdev,
849 + struct list_head **i,
850 + int (*okfn)(struct sk_buff *),
854 + * The caller must not block between calls to this
855 + * function because of risk of continuing from deleted element.
857 + list_for_each_continue_rcu(*i, head) {
858 + struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
860 + if (hook_thresh > elem->priority)
863 + /* Optimization: we don't need to hold module
864 + reference here, since function can't sleep. --RR */
865 + switch (elem->hook(hook, skb, indev, outdev, okfn)) {
879 +#ifdef CONFIG_NETFILTER_DEBUG
884 + NFDEBUG("Evil return from %p(%u).\n",
892 +int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
896 + write_lock_bh(&queue_handler_lock);
897 + if (queue_handler[pf].outfn)
900 + queue_handler[pf].outfn = outfn;
901 + queue_handler[pf].data = data;
904 + write_unlock_bh(&queue_handler_lock);
909 +/* The caller must flush their queue before this */
910 +int nf_unregister_queue_handler(int pf)
912 + write_lock_bh(&queue_handler_lock);
913 + queue_handler[pf].outfn = NULL;
914 + queue_handler[pf].data = NULL;
915 + write_unlock_bh(&queue_handler_lock);
921 + * Any packet that leaves via this function must come back
922 + * through nf_reinject().
924 +static int nf_queue(struct sk_buff *skb,
925 + struct list_head *elem,
926 + int pf, unsigned int hook,
927 + struct net_device *indev,
928 + struct net_device *outdev,
929 + int (*okfn)(struct sk_buff *))
932 + struct nf_info *info;
933 +#ifdef CONFIG_BRIDGE_NETFILTER
934 + struct net_device *physindev = NULL;
935 + struct net_device *physoutdev = NULL;
938 + /* QUEUE == DROP if noone is waiting, to be safe. */
939 + read_lock(&queue_handler_lock);
940 + if (!queue_handler[pf].outfn) {
941 + read_unlock(&queue_handler_lock);
946 + info = kmalloc(sizeof(*info), GFP_ATOMIC);
948 + if (net_ratelimit())
949 + printk(KERN_ERR "OOM queueing packet %p\n",
951 + read_unlock(&queue_handler_lock);
956 + *info = (struct nf_info) {
957 + (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
959 + /* If it's going away, ignore hook. */
960 + if (!try_module_get(info->elem->owner)) {
961 + read_unlock(&queue_handler_lock);
966 + /* Bump dev refs so they don't vanish while packet is out */
967 + if (indev) dev_hold(indev);
968 + if (outdev) dev_hold(outdev);
970 +#ifdef CONFIG_BRIDGE_NETFILTER
971 + if (skb->nf_bridge) {
972 + physindev = skb->nf_bridge->physindev;
973 + if (physindev) dev_hold(physindev);
974 + physoutdev = skb->nf_bridge->physoutdev;
975 + if (physoutdev) dev_hold(physoutdev);
979 + status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
980 + read_unlock(&queue_handler_lock);
983 + /* James M doesn't say fuck enough. */
984 + if (indev) dev_put(indev);
985 + if (outdev) dev_put(outdev);
986 +#ifdef CONFIG_BRIDGE_NETFILTER
987 + if (physindev) dev_put(physindev);
988 + if (physoutdev) dev_put(physoutdev);
990 + module_put(info->elem->owner);
998 +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
999 + struct net_device *indev,
1000 + struct net_device *outdev,
1001 + int (*okfn)(struct sk_buff *),
1004 + struct list_head *elem;
1005 + unsigned int verdict;
1008 + if (skb->ip_summed == CHECKSUM_HW) {
1009 + if (outdev == NULL) {
1010 + skb->ip_summed = CHECKSUM_NONE;
1012 + skb_checksum_help(skb);
1016 + /* We may already have this, but read-locks nest anyway */
1019 +#ifdef CONFIG_NETFILTER_DEBUG
1020 + if (skb->nf_debug & (1 << hook)) {
1021 + printk("nf_hook: hook %i already set.\n", hook);
1022 + nf_dump_skb(pf, skb);
1024 + skb->nf_debug |= (1 << hook);
1027 + elem = &nf_hooks[pf][hook];
1029 + verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
1030 + outdev, &elem, okfn, hook_thresh);
1031 + if (verdict == NF_QUEUE) {
1032 + NFDEBUG("nf_hook: Verdict = QUEUE.\n");
1033 + if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn))
1037 + switch (verdict) {
1048 + rcu_read_unlock();
1052 +void nf_reinject(struct sk_buff *skb, struct nf_info *info,
1053 + unsigned int verdict)
1055 + struct list_head *elem = &info->elem->list;
1056 + struct list_head *i;
1060 + /* Release those devices we held, or Alexey will kill me. */
1061 + if (info->indev) dev_put(info->indev);
1062 + if (info->outdev) dev_put(info->outdev);
1063 +#ifdef CONFIG_BRIDGE_NETFILTER
1064 + if (skb->nf_bridge) {
1065 + if (skb->nf_bridge->physindev)
1066 + dev_put(skb->nf_bridge->physindev);
1067 + if (skb->nf_bridge->physoutdev)
1068 + dev_put(skb->nf_bridge->physoutdev);
1072 + /* Drop reference to owner of hook which queued us. */
1073 + module_put(info->elem->owner);
1075 + list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
1080 + if (elem == &nf_hooks[info->pf][info->hook]) {
1081 + /* The module which sent it to userspace is gone. */
1082 + NFDEBUG("%s: module disappeared, dropping packet.\n",
1084 + verdict = NF_DROP;
1087 + /* Continue traversal iff userspace said ok... */
1088 + if (verdict == NF_REPEAT) {
1089 + elem = elem->prev;
1090 + verdict = NF_ACCEPT;
1093 + if (verdict == NF_ACCEPT) {
1095 + verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
1097 + info->indev, info->outdev, &elem,
1098 + info->okfn, INT_MIN);
1101 + switch (verdict) {
1107 + if (!nf_queue(skb, elem, info->pf, info->hook,
1108 + info->indev, info->outdev, info->okfn))
1112 + rcu_read_unlock();
1114 + if (verdict == NF_DROP)
1122 +/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
1123 +int ip_route_me_harder(struct sk_buff **pskb)
1125 + struct iphdr *iph = (*pskb)->nh.iph;
1126 + struct rtable *rt;
1127 + struct flowi fl = {};
1128 + struct dst_entry *odst;
1129 + unsigned int hh_len;
1131 + /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
1132 + * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
1134 + if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
1135 + fl.nl_u.ip4_u.daddr = iph->daddr;
1136 + fl.nl_u.ip4_u.saddr = iph->saddr;
1137 + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
1138 + fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
1139 +#ifdef CONFIG_IP_ROUTE_FWMARK
1140 + fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
1142 + if (ip_route_output_key(&rt, &fl) != 0)
1145 + /* Drop old route. */
1146 + dst_release((*pskb)->dst);
1147 + (*pskb)->dst = &rt->u.dst;
1149 + /* non-local src, find valid iif to satisfy
1150 + * rp-filter when calling ip_route_input. */
1151 + fl.nl_u.ip4_u.daddr = iph->saddr;
1152 + if (ip_route_output_key(&rt, &fl) != 0)
1155 + odst = (*pskb)->dst;
1156 + if (ip_route_input(*pskb, iph->daddr, iph->saddr,
1157 + RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
1158 + dst_release(&rt->u.dst);
1161 + dst_release(&rt->u.dst);
1162 + dst_release(odst);
1165 + if ((*pskb)->dst->error)
1168 + /* Change in oif may mean change in hh_len. */
1169 + hh_len = (*pskb)->dst->dev->hard_header_len;
1170 + if (skb_headroom(*pskb) < hh_len) {
1171 + struct sk_buff *nskb;
1173 + nskb = skb_realloc_headroom(*pskb, hh_len);
1177 + skb_set_owner_w(nskb, (*pskb)->sk);
1185 +int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
1187 + struct sk_buff *nskb;
1188 + unsigned int iplen;
1190 + if (writable_len > (*pskb)->len)
1193 + /* Not exclusive use of packet? Must copy. */
1194 + if (skb_shared(*pskb) || skb_cloned(*pskb))
1197 + /* Alexey says IP hdr is always modifiable and linear, so ok. */
1198 + if (writable_len <= (*pskb)->nh.iph->ihl*4)
1201 + iplen = writable_len - (*pskb)->nh.iph->ihl*4;
1203 + /* DaveM says protocol headers are also modifiable. */
1204 + switch ((*pskb)->nh.iph->protocol) {
1205 + case IPPROTO_TCP: {
1206 + struct tcphdr hdr;
1207 + if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
1208 + &hdr, sizeof(hdr)) != 0)
1210 + if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
1215 + if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
1218 + case IPPROTO_ICMP:
1220 + <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
1223 + /* Insert other cases here as desired */
1227 + nskb = skb_copy(*pskb, GFP_ATOMIC);
1230 + BUG_ON(skb_is_nonlinear(nskb));
1232 + /* Rest of kernel will get very unhappy if we pass it a
1233 + suddenly-orphaned skbuff */
1235 + skb_set_owner_w(nskb, (*pskb)->sk);
1241 + return pskb_may_pull(*pskb, writable_len);
1243 +EXPORT_SYMBOL(skb_ip_make_writable);
1244 +#endif /*CONFIG_INET*/
1247 +/* This does not belong here, but ipt_REJECT needs it if connection
1248 + tracking in use: without this, connection may not be in hash table,
1249 + and hence manufactured ICMP or RST packets will not be associated
1251 +void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
1253 +void __init netfilter_init(void)
1257 + for (i = 0; i < NPROTO; i++) {
1258 + for (h = 0; h < NF_MAX_HOOKS; h++)
1259 + INIT_LIST_HEAD(&nf_hooks[i][h]);
1263 +EXPORT_SYMBOL(ip_ct_attach);
1264 +EXPORT_SYMBOL(ip_route_me_harder);
1265 +EXPORT_SYMBOL(nf_getsockopt);
1266 +EXPORT_SYMBOL(nf_hook_slow);
1267 +EXPORT_SYMBOL(nf_hooks);
1268 +EXPORT_SYMBOL(nf_register_hook);
1269 +EXPORT_SYMBOL(nf_register_queue_handler);
1270 +EXPORT_SYMBOL(nf_register_sockopt);
1271 +EXPORT_SYMBOL(nf_reinject);
1272 +EXPORT_SYMBOL(nf_setsockopt);
1273 +EXPORT_SYMBOL(nf_unregister_hook);
1274 +EXPORT_SYMBOL(nf_unregister_queue_handler);
1275 +EXPORT_SYMBOL(nf_unregister_sockopt);
1276 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig
1277 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig 2004-03-04 06:16:58.000000000 +0000
1278 +++ linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig 2004-03-05 07:40:24.000000000 +0000
1279 @@ -579,5 +579,60 @@
1281 To compile it as a module, choose M here. If unsure, say N.
1283 +config IP_NF_TARGET_IPV4OPTSSTRIP
1284 + tristate 'IPV4OPTSSTRIP target support'
1285 + depends on IP_NF_MANGLE
1288 +config IP_NF_TARGET_TTL
1289 + tristate 'TTL target support'
1290 + depends on IP_NF_MANGLE
1293 +config IP_NF_MATCH_CONNLIMIT
1294 + tristate 'Connections/IP limit match support'
1295 + depends on IP_NF_IPTABLES
1298 +config IP_NF_MATCH_DSTLIMIT
1299 + tristate 'dstlimit match support'
1300 + depends on IP_NF_IPTABLES
1303 +config IP_NF_MATCH_FUZZY
1304 + tristate 'fuzzy match support'
1305 + depends on IP_NF_IPTABLES
1308 +config IP_NF_MATCH_IPV4OPTIONS
1309 + tristate 'IPV4OPTIONS match support'
1310 + depends on IP_NF_IPTABLES
1313 +config IP_NF_MATCH_MPORT
1314 + tristate 'Multiple port with ranges match support'
1315 + depends on IP_NF_IPTABLES
1318 +config IP_NF_MATCH_NTH
1319 + tristate 'Nth match support'
1320 + depends on IP_NF_IPTABLES
1323 +config IP_NF_MATCH_QUOTA
1324 + tristate 'quota match support'
1325 + depends on IP_NF_IPTABLES
1328 +config IP_NF_MATCH_REALM
1329 + tristate 'realm match support'
1330 + depends on IP_NF_IPTABLES && NET_CLS_ROUTE
1333 +config IP_NF_MATCH_SCTP
1334 + tristate 'SCTP protocol match support'
1335 + depends on IP_NF_IPTABLES
1340 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.4-rc2/net/ipv4/netfilter/Makefile
1341 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile 2004-03-04 06:16:38.000000000 +0000
1342 +++ linux-2.6.4-rc2/net/ipv4/netfilter/Makefile 2004-03-05 07:40:24.000000000 +0000
1345 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
1346 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
1347 +obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
1348 +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
1349 +obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o
1350 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
1351 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
1352 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
1354 obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
1355 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
1357 +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
1359 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
1360 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
1362 +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
1364 +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
1367 +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
1369 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
1371 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
1374 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
1375 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
1376 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
1377 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
1378 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
1379 +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
1381 obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
1384 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
1385 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
1386 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
1387 +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
1388 +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
1389 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
1390 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
1392 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c
1393 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-04 06:16:34.000000000 +0000
1394 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-05 07:39:43.000000000 +0000
1396 * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
1397 * - add usage/reference counts to ip_conntrack_expect
1398 * - export ip_conntrack[_expect]_{find_get,put} functions
1399 + * 05 Aug 2002: Harald Welte <laforge@gnumonks.org>
1400 + * - added DocBook-style comments for public API
1403 #include <linux/config.h>
1409 + * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number
1410 + * @protocol: protocol number
1412 struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
1414 struct ip_conntrack_protocol *p;
1415 @@ -112,6 +118,11 @@
1416 static int ip_conntrack_hash_rnd_initted;
1417 static unsigned int ip_conntrack_hash_rnd;
1420 + * hash_conntrack - Calculate the position of an entry in the connection
1422 + * @tuple: conntrack tuple which we want to calculate the hash position
1425 hash_conntrack(const struct ip_conntrack_tuple *tuple)
1427 @@ -124,6 +135,19 @@
1428 ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
1432 + * get_tuple - set all the fields of a tuple which is passed as parameter
1433 + * given a network buffer.
1434 + * @iph:pointer an IP header.
1435 + * @skb:network buffer for which we want to generate the tuple
1436 + * @dataoff: FIXME: Deprecated?
1437 + * @tuple: tuple which will be generate. Used as return parameter.
1438 + * @protocol: structure which contains pointer to protocol specific functions.
1440 + * Note: This function doesn't allocate space for the tuple passed as
1441 + * parameter. The function pkt_to_packet which set all the protocol specific
1442 + * fields of a given tuple.
1445 get_tuple(const struct iphdr *iph,
1446 const struct sk_buff *skb,
1447 @@ -145,6 +169,15 @@
1448 return protocol->pkt_to_tuple(skb, dataoff, tuple);
1452 + * invert_tuple - Returns the inverse of a given tuple. It is used to
1453 + * calculate the tuple which represents the other sense of the flow
1454 + * of a connection.
1455 + * @inverse: the inverted tuple. Use as return value.
1456 + * @orig: the original tuple which will be inverted.
1457 + * @protocol: a pointer to the protocol structure which contains all the
1458 + * specifical functions available for this tuple.
1461 invert_tuple(struct ip_conntrack_tuple *inverse,
1462 const struct ip_conntrack_tuple *orig,
1463 @@ -160,7 +193,15 @@
1465 /* ip_conntrack_expect helper functions */
1467 -/* Compare tuple parts depending on mask. */
1469 + * expect_cmp - compare a tuple with a expectation depending on a mask
1470 + * @i: pointer to an expectation.
1471 + * @tuple: tuple which will be compared with the expectation tuple.
1473 + * Actually the tuple field of an expectation is compared with a tuple
1474 + * This function is used by LIST_FIND to find a expectation which match a te
1477 static inline int expect_cmp(const struct ip_conntrack_expect *i,
1478 const struct ip_conntrack_tuple *tuple)
1480 @@ -168,6 +209,10 @@
1481 return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1485 + * destroy_expect - Release all the resources allocated by an expectation.
1486 + * @exp: pointer to the expectation which we want to release.
1489 destroy_expect(struct ip_conntrack_expect *exp)
1491 @@ -178,7 +223,11 @@
1497 + * ip_conntrack_expect_put - it decrements the counter of use related
1498 + * associated to an expectation and it calls destroy_expect.
1499 + * @exp: pointer to the expectation which we want to release.
1501 inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
1504 @@ -198,7 +247,14 @@
1505 struct ip_conntrack_expect *, tuple);
1508 -/* Find a expectation corresponding to a tuple. */
1510 + * ip_conntrack_find_get - find conntrack according to tuple
1511 + * @tuple: conntrack tuple for which we search conntrack
1512 + * @ignored_conntrack: ignore this conntrack during search
1514 + * This function increments the reference count of the found
1515 + * conntrack (if any).
1517 struct ip_conntrack_expect *
1518 ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
1520 @@ -381,7 +437,14 @@
1524 -/* Find a connection corresponding to a tuple. */
1526 + * ip_conntrack_find_get - find conntrack according to tuple
1527 + * @tuple: conntrack tuple for which we search conntrack
1528 + * @ignored_conntrack: ignore this conntrack during search
1530 + * This function increments the reference count of the found
1531 + * conntrack (if any).
1533 struct ip_conntrack_tuple_hash *
1534 ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
1535 const struct ip_conntrack *ignored_conntrack)
1536 @@ -409,7 +472,14 @@
1540 -/* Return conntrack and conntrack_info given skb->nfct->master */
1542 + * ip_conntrack_get - Return conntrack and conntrack_info for given skb
1543 + * @skb: skb for which we want to find conntrack and conntrack_info
1544 + * @ctinfo: pointer to ctinfo, used as return value
1546 + * This function resolves the respective conntrack and conntrack_info
1547 + * structures for the connection this packet (skb) is part of.
1549 struct ip_conntrack *
1550 ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
1552 @@ -479,8 +549,14 @@
1556 -/* Returns true if a connection correspondings to the tuple (required
1559 + * ip_conntrack_tuple_taken - Find out if tuple is already in use
1560 + * @tuple: tuple to be used for this test
1561 + * @ignored_conntrack: conntrack which is excluded from result
1563 + * This function is called by the NAT code in order to find out if
1564 + * a particular tuple is already in use by some connection.
1567 ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
1568 const struct ip_conntrack *ignored_conntrack)
1569 @@ -606,7 +682,13 @@
1571 return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
1575 + * ip_ct_find_helper - Find application helper according to tuple
1576 + * @tuple: tuple for which helper needs to be found
1578 + * This function is used to determine if any registered conntrack helper
1579 + * is to be used for the given tuple.
1581 struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
1583 return LIST_FIND(&helpers, helper_cmp,
1584 @@ -691,42 +773,50 @@
1585 struct ip_conntrack_expect *, tuple);
1586 READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1588 - /* If master is not in hash table yet (ie. packet hasn't left
1589 - this machine yet), how can other end know about expected?
1590 - Hence these are not the droids you are looking for (if
1591 - master ct never got confirmed, we'd hold a reference to it
1592 - and weird things would happen to future packets). */
1593 - if (expected && !is_confirmed(expected->expectant))
1596 - /* Look up the conntrack helper for master connections only */
1598 - conntrack->helper = ip_ct_find_helper(&repl_tuple);
1600 - /* If the expectation is dying, then this is a loser. */
1602 - && expected->expectant->helper->timeout
1603 - && ! del_timer(&expected->timeout))
1607 - DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1608 - conntrack, expected);
1609 - /* Welcome, Mr. Bond. We've been expecting you... */
1610 - IP_NF_ASSERT(master_ct(conntrack));
1611 - __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1612 - conntrack->master = expected;
1613 - expected->sibling = conntrack;
1614 - LIST_DELETE(&ip_conntrack_expect_list, expected);
1615 - expected->expectant->expecting--;
1616 - nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1618 - atomic_inc(&ip_conntrack_count);
1619 + /* If master is not in hash table yet (ie. packet hasn't left
1620 + this machine yet), how can other end know about expected?
1621 + Hence these are not the droids you are looking for (if
1622 + master ct never got confirmed, we'd hold a reference to it
1623 + and weird things would happen to future packets). */
1624 + if (!is_confirmed(expected->expectant)) {
1626 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
1630 + /* Expectation is dying... */
1631 + if (expected->expectant->helper->timeout
1632 + && ! del_timer(&expected->timeout)) {
1636 + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1637 + conntrack, expected);
1638 + /* Welcome, Mr. Bond. We've been expecting you... */
1639 + IP_NF_ASSERT(master_ct(conntrack));
1640 + __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1641 + conntrack->master = expected;
1642 + expected->sibling = conntrack;
1643 + LIST_DELETE(&ip_conntrack_expect_list, expected);
1644 + expected->expectant->expecting--;
1645 + nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1647 + /* this is a braindead... --pablo */
1648 + atomic_inc(&ip_conntrack_count);
1649 + WRITE_UNLOCK(&ip_conntrack_lock);
1651 + if (expected->expectfn)
1652 + expected->expectfn(conntrack);
1656 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
1658 +end: atomic_inc(&ip_conntrack_count);
1659 WRITE_UNLOCK(&ip_conntrack_lock);
1661 - if (expected && expected->expectfn)
1662 - expected->expectfn(conntrack);
1663 - return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1664 +ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1667 /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
1668 @@ -900,6 +990,14 @@
1669 return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
1673 + * ip_conntrack_unexpect_related - Unexpect a related connection
1674 + * @expect: expecattin to be removed
1676 + * This function removes an existing expectation, that has not yet been
1677 + * confirmed (i.e. expectation was issued, but expected connection didn't
1680 inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
1682 WRITE_LOCK(&ip_conntrack_lock);
1683 @@ -917,7 +1015,20 @@
1684 WRITE_UNLOCK(&ip_conntrack_lock);
1687 -/* Add a related connection. */
1689 + * ip_conntrack_expect_related - Expect a related connection
1690 + * @related_to: master conntrack
1691 + * @expect: expectation with all values filled in
1693 + * This function is called by conntrack application helpers who
1694 + * have detected that the control (master) connection is just about
1695 + * to negotiate a related slave connection.
1697 + * Note: This function allocates it's own struct ip_conntrack_expect,
1698 + * copying the values from the 'expect' parameter. Thus, 'expect' can
1699 + * be allocated on the stack and does not need to be valid after this
1700 + * function returns.
1702 int ip_conntrack_expect_related(struct ip_conntrack *related_to,
1703 struct ip_conntrack_expect *expect)
1705 @@ -1047,7 +1158,15 @@
1709 -/* Change tuple in an existing expectation */
1711 + * ip_conntrack_change_expect - Change tuple in existing expectation
1712 + * @expect: expectation which is to be changed
1713 + * @newtuple: new tuple for expect
1715 + * This function is mostly called by NAT application helpers, who want to
1716 + * change an expectation issued by their respective conntrack application
1717 + * helper counterpart.
1719 int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
1720 struct ip_conntrack_tuple *newtuple)
1722 @@ -1088,8 +1207,15 @@
1726 -/* Alter reply tuple (maybe alter helper). If it's already taken,
1727 - return 0 and don't do alteration. */
1729 + * ip_conntrack_alter_reply - Alter reply tuple of conntrack
1730 + * @conntrack: conntrack whose reply tuple we want to alter
1731 + * @newreply: designated reply tuple for this conntrack
1733 + * This function alters the reply tuple of a conntrack to the given
1734 + * newreply tuple. If this newreply tuple is already taken, return 0
1735 + * and don't do alteration
1737 int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
1738 const struct ip_conntrack_tuple *newreply)
1740 @@ -1114,6 +1240,13 @@
1745 + * ip_conntrack_helper_register - Register a conntrack application helper
1746 + * @me: structure describing the helper
1748 + * This function is called by conntrack application helpers to register
1749 + * themselves with the conntrack core.
1751 int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
1753 WRITE_LOCK(&ip_conntrack_lock);
1754 @@ -1135,6 +1268,13 @@
1759 + * ip_conntrack_helper_unregister - Unregister a conntrack application helper
1760 + * @me: structure describing the helper
1762 + * This function is called by conntrack application helpers to unregister
1763 + * themselvers from the conntrack core.
1765 void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
1768 @@ -1153,7 +1293,14 @@
1772 -/* Refresh conntrack for this many jiffies. */
1774 + * ip_ct_refresh - Refresh conntrack timer for given conntrack
1775 + * @ct: conntrack which we want to refresh
1776 + * @extra_jiffies: number of jiffies to add
1778 + * This function is called by protocol helpers and application helpers in
1779 + * order to change the expiration timer of a conntrack entry.
1781 void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
1783 IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
1784 @@ -1172,7 +1319,16 @@
1785 WRITE_UNLOCK(&ip_conntrack_lock);
1788 -/* Returns new sk_buff, or NULL */
1791 + * ip_ct_gather_frags - Gather fragments of a particular skb
1792 + * @skb: pointer to sk_buff of fragmented IP packet
1794 + * This code is just a wrapper around the defragmentation code in the core IPv4
1795 + * stack. It also takes care of nonlinear skb's.
1797 + * Returns new sk_buff, or NULL
1800 ip_ct_gather_frags(struct sk_buff *skb)
1802 @@ -1256,6 +1412,16 @@
1807 + * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries
1808 + * @kill: callback function selecting which entries to delete
1809 + * @data: opaque data pointer, becomes 2nd argument for kill function
1811 + * This function can be used to selectively delete elements of the conntrack
1812 + * hashtable. The function iterates over the list of conntrack entries and
1813 + * calls the 'kill' function for every entry. If the return value is true,
1814 + * the connection is deleted (death_by_timeout).
1817 ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
1819 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig
1820 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 00:00:00.000000000 +0000
1821 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-03-05 07:39:41.000000000 +0000
1823 +/* Connection state tracking for netfilter. This is separated from,
1824 + but required by, the NAT layer; it can also be used by an iptables
1827 +/* (C) 1999-2001 Paul `Rusty' Russell
1828 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
1830 + * This program is free software; you can redistribute it and/or modify
1831 + * it under the terms of the GNU General Public License version 2 as
1832 + * published by the Free Software Foundation.
1834 + * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
1835 + * - new API and handling of conntrack/nat helpers
1836 + * - now capable of multiple expectations for one master
1837 + * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
1838 + * - add usage/reference counts to ip_conntrack_expect
1839 + * - export ip_conntrack[_expect]_{find_get,put} functions
1842 +#include <linux/config.h>
1843 +#include <linux/types.h>
1844 +#include <linux/icmp.h>
1845 +#include <linux/ip.h>
1846 +#include <linux/netfilter.h>
1847 +#include <linux/netfilter_ipv4.h>
1848 +#include <linux/module.h>
1849 +#include <linux/skbuff.h>
1850 +#include <linux/proc_fs.h>
1851 +#include <linux/vmalloc.h>
1852 +#include <net/checksum.h>
1853 +#include <linux/stddef.h>
1854 +#include <linux/sysctl.h>
1855 +#include <linux/slab.h>
1856 +#include <linux/random.h>
1857 +#include <linux/jhash.h>
1858 +/* For ERR_PTR(). Yeah, I know... --RR */
1859 +#include <linux/fs.h>
1861 +/* This rwlock protects the main hash table, protocol/helper/expected
1862 + registrations, conntrack timers*/
1863 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
1864 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
1866 +#include <linux/netfilter_ipv4/ip_conntrack.h>
1867 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
1868 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1869 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
1870 +#include <linux/netfilter_ipv4/listhelp.h>
1872 +#define IP_CONNTRACK_VERSION "2.1"
1875 +#define DEBUGP printk
1877 +#define DEBUGP(format, args...)
1880 +DECLARE_RWLOCK(ip_conntrack_lock);
1881 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
1883 +void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
1884 +LIST_HEAD(ip_conntrack_expect_list);
1885 +LIST_HEAD(protocol_list);
1886 +static LIST_HEAD(helpers);
1887 +unsigned int ip_conntrack_htable_size = 0;
1888 +int ip_conntrack_max;
1889 +static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
1890 +struct list_head *ip_conntrack_hash;
1891 +static kmem_cache_t *ip_conntrack_cachep;
1893 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
1895 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
1896 + u_int8_t protocol)
1898 + return protocol == curr->proto;
1901 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
1903 + struct ip_conntrack_protocol *p;
1905 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1906 + p = LIST_FIND(&protocol_list, proto_cmpfn,
1907 + struct ip_conntrack_protocol *, protocol);
1909 + p = &ip_conntrack_generic_protocol;
1914 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
1916 + struct ip_conntrack_protocol *p;
1918 + READ_LOCK(&ip_conntrack_lock);
1919 + p = __ip_ct_find_proto(protocol);
1920 + READ_UNLOCK(&ip_conntrack_lock);
1925 +ip_conntrack_put(struct ip_conntrack *ct)
1928 + IP_NF_ASSERT(ct->infos[0].master);
1929 + /* nf_conntrack_put wants to go via an info struct, so feed it
1931 + nf_conntrack_put(&ct->infos[0]);
1934 +static int ip_conntrack_hash_rnd_initted;
1935 +static unsigned int ip_conntrack_hash_rnd;
1938 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
1941 + dump_tuple(tuple);
1943 + return (jhash_3words(tuple->src.ip,
1944 + (tuple->dst.ip ^ tuple->dst.protonum),
1945 + (tuple->src.u.all | (tuple->dst.u.all << 16)),
1946 + ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
1950 +get_tuple(const struct iphdr *iph,
1951 + const struct sk_buff *skb,
1952 + unsigned int dataoff,
1953 + struct ip_conntrack_tuple *tuple,
1954 + const struct ip_conntrack_protocol *protocol)
1956 + /* Never happen */
1957 + if (iph->frag_off & htons(IP_OFFSET)) {
1958 + printk("ip_conntrack_core: Frag of proto %u.\n",
1963 + tuple->src.ip = iph->saddr;
1964 + tuple->dst.ip = iph->daddr;
1965 + tuple->dst.protonum = iph->protocol;
1967 + return protocol->pkt_to_tuple(skb, dataoff, tuple);
1971 +invert_tuple(struct ip_conntrack_tuple *inverse,
1972 + const struct ip_conntrack_tuple *orig,
1973 + const struct ip_conntrack_protocol *protocol)
1975 + inverse->src.ip = orig->dst.ip;
1976 + inverse->dst.ip = orig->src.ip;
1977 + inverse->dst.protonum = orig->dst.protonum;
1979 + return protocol->invert_tuple(inverse, orig);
1983 +/* ip_conntrack_expect helper functions */
1985 +/* Compare tuple parts depending on mask. */
1986 +static inline int expect_cmp(const struct ip_conntrack_expect *i,
1987 + const struct ip_conntrack_tuple *tuple)
1989 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1990 + return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1994 +destroy_expect(struct ip_conntrack_expect *exp)
1996 + DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
1997 + IP_NF_ASSERT(atomic_read(&exp->use));
1998 + IP_NF_ASSERT(!timer_pending(&exp->timeout));
2004 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
2006 + IP_NF_ASSERT(exp);
2008 + if (atomic_dec_and_test(&exp->use)) {
2009 + /* usage count dropped to zero */
2010 + destroy_expect(exp);
2014 +static inline struct ip_conntrack_expect *
2015 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
2017 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2018 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2019 + return LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
2020 + struct ip_conntrack_expect *, tuple);
2023 +/* Find a expectation corresponding to a tuple. */
2024 +struct ip_conntrack_expect *
2025 +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
2027 + struct ip_conntrack_expect *exp;
2029 + READ_LOCK(&ip_conntrack_lock);
2030 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
2031 + exp = __ip_ct_expect_find(tuple);
2033 + atomic_inc(&exp->use);
2034 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2035 + READ_UNLOCK(&ip_conntrack_lock);
2040 +/* remove one specific expectation from all lists and drop refcount,
2041 + * does _NOT_ delete the timer. */
2042 +static void __unexpect_related(struct ip_conntrack_expect *expect)
2044 + DEBUGP("unexpect_related(%p)\n", expect);
2045 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2047 + /* we're not allowed to unexpect a confirmed expectation! */
2048 + IP_NF_ASSERT(!expect->sibling);
2050 + /* delete from global and local lists */
2051 + list_del(&expect->list);
2052 + list_del(&expect->expected_list);
2054 + /* decrement expect-count of master conntrack */
2055 + if (expect->expectant)
2056 + expect->expectant->expecting--;
2058 + ip_conntrack_expect_put(expect);
2061 +/* remove one specific expecatation from all lists, drop refcount
2062 + * and expire timer.
2063 + * This function can _NOT_ be called for confirmed expects! */
2064 +static void unexpect_related(struct ip_conntrack_expect *expect)
2066 + IP_NF_ASSERT(expect->expectant);
2067 + IP_NF_ASSERT(expect->expectant->helper);
2068 + /* if we are supposed to have a timer, but we can't delete
2069 + * it: race condition. __unexpect_related will
2070 + * be calledd by timeout function */
2071 + if (expect->expectant->helper->timeout
2072 + && !del_timer(&expect->timeout))
2075 + __unexpect_related(expect);
2078 +/* delete all unconfirmed expectations for this conntrack */
2079 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
2081 + struct list_head *exp_entry, *next;
2082 + struct ip_conntrack_expect *exp;
2084 + DEBUGP("remove_expectations(%p)\n", ct);
2086 + list_for_each_safe(exp_entry, next, &ct->sibling_list) {
2087 + exp = list_entry(exp_entry, struct ip_conntrack_expect,
2090 + /* we skip established expectations, as we want to delete
2091 + * the un-established ones only */
2092 + if (exp->sibling) {
2093 + DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
2094 + if (drop_refcount) {
2095 + /* Indicate that this expectations parent is dead */
2096 + ip_conntrack_put(exp->expectant);
2097 + exp->expectant = NULL;
2102 + IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
2103 + IP_NF_ASSERT(exp->expectant == ct);
2105 + /* delete expectation from global and private lists */
2106 + unexpect_related(exp);
2111 +clean_from_lists(struct ip_conntrack *ct)
2113 + unsigned int ho, hr;
2115 + DEBUGP("clean_from_lists(%p)\n", ct);
2116 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2118 + ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
2119 + hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
2120 + LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
2121 + LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
2123 + /* Destroy all un-established, pending expectations */
2124 + remove_expectations(ct, 1);
2128 +destroy_conntrack(struct nf_conntrack *nfct)
2130 + struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
2131 + struct ip_conntrack_protocol *proto;
2133 + DEBUGP("destroy_conntrack(%p)\n", ct);
2134 + IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
2135 + IP_NF_ASSERT(!timer_pending(&ct->timeout));
2137 + /* To make sure we don't get any weird locking issues here:
2138 + * destroy_conntrack() MUST NOT be called with a write lock
2139 + * to ip_conntrack_lock!!! -HW */
2140 + proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
2141 + if (proto && proto->destroy)
2142 + proto->destroy(ct);
2144 + if (ip_conntrack_destroyed)
2145 + ip_conntrack_destroyed(ct);
2147 + WRITE_LOCK(&ip_conntrack_lock);
2148 + /* Delete us from our own list to prevent corruption later */
2149 + list_del(&ct->sibling_list);
2151 + /* Delete our master expectation */
2153 + if (ct->master->expectant) {
2154 + /* can't call __unexpect_related here,
2155 + * since it would screw up expect_list */
2156 + list_del(&ct->master->expected_list);
2157 + master = ct->master->expectant;
2159 + kfree(ct->master);
2161 + WRITE_UNLOCK(&ip_conntrack_lock);
2164 + ip_conntrack_put(master);
2166 + DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
2167 + kmem_cache_free(ip_conntrack_cachep, ct);
2168 + atomic_dec(&ip_conntrack_count);
2171 +static void death_by_timeout(unsigned long ul_conntrack)
2173 + struct ip_conntrack *ct = (void *)ul_conntrack;
2175 + WRITE_LOCK(&ip_conntrack_lock);
2176 + clean_from_lists(ct);
2177 + WRITE_UNLOCK(&ip_conntrack_lock);
2178 + ip_conntrack_put(ct);
2182 +conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
2183 + const struct ip_conntrack_tuple *tuple,
2184 + const struct ip_conntrack *ignored_conntrack)
2186 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2187 + return i->ctrack != ignored_conntrack
2188 + && ip_ct_tuple_equal(tuple, &i->tuple);
2191 +static struct ip_conntrack_tuple_hash *
2192 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
2193 + const struct ip_conntrack *ignored_conntrack)
2195 + struct ip_conntrack_tuple_hash *h;
2196 + unsigned int hash = hash_conntrack(tuple);
2198 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2199 + h = LIST_FIND(&ip_conntrack_hash[hash],
2200 + conntrack_tuple_cmp,
2201 + struct ip_conntrack_tuple_hash *,
2202 + tuple, ignored_conntrack);
2206 +/* Find a connection corresponding to a tuple. */
2207 +struct ip_conntrack_tuple_hash *
2208 +ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
2209 + const struct ip_conntrack *ignored_conntrack)
2211 + struct ip_conntrack_tuple_hash *h;
2213 + READ_LOCK(&ip_conntrack_lock);
2214 + h = __ip_conntrack_find(tuple, ignored_conntrack);
2216 + atomic_inc(&h->ctrack->ct_general.use);
2217 + READ_UNLOCK(&ip_conntrack_lock);
2222 +static inline struct ip_conntrack *
2223 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
2225 + struct ip_conntrack *ct
2226 + = (struct ip_conntrack *)nfct->master;
2228 + /* ctinfo is the index of the nfct inside the conntrack */
2229 + *ctinfo = nfct - ct->infos;
2230 + IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
2234 +/* Return conntrack and conntrack_info given skb->nfct->master */
2235 +struct ip_conntrack *
2236 +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
2239 + return __ip_conntrack_get(skb->nfct, ctinfo);
2243 +/* Confirm a connection given skb->nfct; places it in hash table */
2245 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
2247 + unsigned int hash, repl_hash;
2248 + struct ip_conntrack *ct;
2249 + enum ip_conntrack_info ctinfo;
2251 + ct = __ip_conntrack_get(nfct, &ctinfo);
2253 + /* ipt_REJECT uses ip_conntrack_attach to attach related
2254 + ICMP/TCP RST packets in other direction. Actual packet
2255 + which created connection will be IP_CT_NEW or for an
2256 + expected connection, IP_CT_RELATED. */
2257 + if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
2260 + hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
2261 + repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
2263 + /* We're not in hash table, and we refuse to set up related
2264 + connections for unconfirmed conns. But packet copies and
2265 + REJECT will give spurious warnings here. */
2266 + /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
2268 + /* No external references means noone else could have
2270 + IP_NF_ASSERT(!is_confirmed(ct));
2271 + DEBUGP("Confirming conntrack %p\n", ct);
2273 + WRITE_LOCK(&ip_conntrack_lock);
2274 + /* See if there's one in the list already, including reverse:
2275 + NAT could have grabbed it without realizing, since we're
2276 + not in the hash. If there is, we lost race. */
2277 + if (!LIST_FIND(&ip_conntrack_hash[hash],
2278 + conntrack_tuple_cmp,
2279 + struct ip_conntrack_tuple_hash *,
2280 + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
2281 + && !LIST_FIND(&ip_conntrack_hash[repl_hash],
2282 + conntrack_tuple_cmp,
2283 + struct ip_conntrack_tuple_hash *,
2284 + &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
2285 + list_prepend(&ip_conntrack_hash[hash],
2286 + &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
2287 + list_prepend(&ip_conntrack_hash[repl_hash],
2288 + &ct->tuplehash[IP_CT_DIR_REPLY]);
2289 + /* Timer relative to confirmation time, not original
2290 + setting time, otherwise we'd get timer wrap in
2291 + weird delay cases. */
2292 + ct->timeout.expires += jiffies;
2293 + add_timer(&ct->timeout);
2294 + atomic_inc(&ct->ct_general.use);
2295 + set_bit(IPS_CONFIRMED_BIT, &ct->status);
2296 + WRITE_UNLOCK(&ip_conntrack_lock);
2300 + WRITE_UNLOCK(&ip_conntrack_lock);
2304 +/* Returns true if a connection correspondings to the tuple (required
2307 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
2308 + const struct ip_conntrack *ignored_conntrack)
2310 + struct ip_conntrack_tuple_hash *h;
2312 + READ_LOCK(&ip_conntrack_lock);
2313 + h = __ip_conntrack_find(tuple, ignored_conntrack);
2314 + READ_UNLOCK(&ip_conntrack_lock);
2319 +/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
2320 +struct ip_conntrack *
2321 +icmp_error_track(struct sk_buff *skb,
2322 + enum ip_conntrack_info *ctinfo,
2323 + unsigned int hooknum)
2325 + struct ip_conntrack_tuple innertuple, origtuple;
2327 + struct icmphdr icmp;
2330 + struct ip_conntrack_protocol *innerproto;
2331 + struct ip_conntrack_tuple_hash *h;
2334 + IP_NF_ASSERT(skb->nfct == NULL);
2336 + /* Not enough header? */
2337 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
2340 + if (inside.icmp.type != ICMP_DEST_UNREACH
2341 + && inside.icmp.type != ICMP_SOURCE_QUENCH
2342 + && inside.icmp.type != ICMP_TIME_EXCEEDED
2343 + && inside.icmp.type != ICMP_PARAMETERPROB
2344 + && inside.icmp.type != ICMP_REDIRECT)
2347 + /* Ignore ICMP's containing fragments (shouldn't happen) */
2348 + if (inside.ip.frag_off & htons(IP_OFFSET)) {
2349 + DEBUGP("icmp_error_track: fragment of proto %u\n",
2350 + inside.ip.protocol);
2354 + innerproto = ip_ct_find_proto(inside.ip.protocol);
2355 + dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
2356 + /* Are they talking about one of our connections? */
2357 + if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
2358 + DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
2362 + /* Ordinarily, we'd expect the inverted tupleproto, but it's
2363 + been preserved inside the ICMP. */
2364 + if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
2365 + DEBUGP("icmp_error_track: Can't invert tuple\n");
2369 + *ctinfo = IP_CT_RELATED;
2371 + h = ip_conntrack_find_get(&innertuple, NULL);
2373 + /* Locally generated ICMPs will match inverted if they
2374 + haven't been SNAT'ed yet */
2375 + /* FIXME: NAT code has to handle half-done double NAT --RR */
2376 + if (hooknum == NF_IP_LOCAL_OUT)
2377 + h = ip_conntrack_find_get(&origtuple, NULL);
2380 + DEBUGP("icmp_error_track: no match\n");
2383 + /* Reverse direction from that found */
2384 + if (DIRECTION(h) != IP_CT_DIR_REPLY)
2385 + *ctinfo += IP_CT_IS_REPLY;
2387 + if (DIRECTION(h) == IP_CT_DIR_REPLY)
2388 + *ctinfo += IP_CT_IS_REPLY;
2391 + /* Update skb to refer to this connection */
2392 + skb->nfct = &h->ctrack->infos[*ctinfo];
2396 +/* There's a small race here where we may free a just-assured
2397 + connection. Too bad: we're in trouble anyway. */
2398 +static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
2400 + return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
2403 +static int early_drop(struct list_head *chain)
2405 + /* Traverse backwards: gives us oldest, which is roughly LRU */
2406 + struct ip_conntrack_tuple_hash *h;
2409 + READ_LOCK(&ip_conntrack_lock);
2410 + h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
2412 + atomic_inc(&h->ctrack->ct_general.use);
2413 + READ_UNLOCK(&ip_conntrack_lock);
2418 + if (del_timer(&h->ctrack->timeout)) {
2419 + death_by_timeout((unsigned long)h->ctrack);
2422 + ip_conntrack_put(h->ctrack);
2426 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
2427 + const struct ip_conntrack_tuple *rtuple)
2429 + return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
2432 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
2434 + return LIST_FIND(&helpers, helper_cmp,
2435 + struct ip_conntrack_helper *,
2439 +/* Allocate a new conntrack: we return -ENOMEM if classification
2440 + failed due to stress. Otherwise it really is unclassifiable. */
2441 +static struct ip_conntrack_tuple_hash *
2442 +init_conntrack(const struct ip_conntrack_tuple *tuple,
2443 + struct ip_conntrack_protocol *protocol,
2444 + struct sk_buff *skb)
2446 + struct ip_conntrack *conntrack;
2447 + struct ip_conntrack_tuple repl_tuple;
2449 + struct ip_conntrack_expect *expected;
2451 + static unsigned int drop_next;
2453 + if (!ip_conntrack_hash_rnd_initted) {
2454 + get_random_bytes(&ip_conntrack_hash_rnd, 4);
2455 + ip_conntrack_hash_rnd_initted = 1;
2458 + hash = hash_conntrack(tuple);
2460 + if (ip_conntrack_max &&
2461 + atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
2462 + /* Try dropping from random chain, or else from the
2463 + chain about to put into (in case they're trying to
2464 + bomb one hash chain). */
2465 + unsigned int next = (drop_next++)%ip_conntrack_htable_size;
2467 + if (!early_drop(&ip_conntrack_hash[next])
2468 + && !early_drop(&ip_conntrack_hash[hash])) {
2469 + if (net_ratelimit())
2470 + printk(KERN_WARNING
2471 + "ip_conntrack: table full, dropping"
2473 + return ERR_PTR(-ENOMEM);
2477 + if (!invert_tuple(&repl_tuple, tuple, protocol)) {
2478 + DEBUGP("Can't invert tuple.\n");
2482 + conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
2484 + DEBUGP("Can't allocate conntrack.\n");
2485 + return ERR_PTR(-ENOMEM);
2488 + memset(conntrack, 0, sizeof(*conntrack));
2489 + atomic_set(&conntrack->ct_general.use, 1);
2490 + conntrack->ct_general.destroy = destroy_conntrack;
2491 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
2492 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
2493 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
2494 + conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
2495 + for (i=0; i < IP_CT_NUMBER; i++)
2496 + conntrack->infos[i].master = &conntrack->ct_general;
2498 + if (!protocol->new(conntrack, skb)) {
2499 + kmem_cache_free(ip_conntrack_cachep, conntrack);
2502 + /* Don't set timer yet: wait for confirmation */
2503 + init_timer(&conntrack->timeout);
2504 + conntrack->timeout.data = (unsigned long)conntrack;
2505 + conntrack->timeout.function = death_by_timeout;
2507 + INIT_LIST_HEAD(&conntrack->sibling_list);
2509 + WRITE_LOCK(&ip_conntrack_lock);
2510 + /* Need finding and deleting of expected ONLY if we win race */
2511 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
2512 + expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
2513 + struct ip_conntrack_expect *, tuple);
2514 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2517 + /* If master is not in hash table yet (ie. packet hasn't left
2518 + this machine yet), how can other end know about expected?
2519 + Hence these are not the droids you are looking for (if
2520 + master ct never got confirmed, we'd hold a reference to it
2521 + and weird things would happen to future packets). */
2522 + if (!is_confirmed(expected->expectant)) {
2524 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
2528 + /* Expectation is dying... */
2529 + if (expected->expectant->helper->timeout
2530 + && ! del_timer(&expected->timeout)) {
2534 + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
2535 + conntrack, expected);
2536 + /* Welcome, Mr. Bond. We've been expecting you... */
2537 + IP_NF_ASSERT(master_ct(conntrack));
2538 + __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
2539 + conntrack->master = expected;
2540 + expected->sibling = conntrack;
2541 + LIST_DELETE(&ip_conntrack_expect_list, expected);
2542 + expected->expectant->expecting--;
2543 + nf_conntrack_get(&master_ct(conntrack)->infos[0]);
2545 + /* this is a braindead... --pablo */
2546 + atomic_inc(&ip_conntrack_count);
2547 + WRITE_UNLOCK(&ip_conntrack_lock);
2549 + if (expected->expectfn)
2550 + expected->expectfn(conntrack);
2554 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
2556 +end: atomic_inc(&ip_conntrack_count);
2557 + WRITE_UNLOCK(&ip_conntrack_lock);
2559 +ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
2562 +/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
2563 +static inline struct ip_conntrack *
2564 +resolve_normal_ct(struct sk_buff *skb,
2565 + struct ip_conntrack_protocol *proto,
2567 + unsigned int hooknum,
2568 + enum ip_conntrack_info *ctinfo)
2570 + struct ip_conntrack_tuple tuple;
2571 + struct ip_conntrack_tuple_hash *h;
2573 + IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
2575 + if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
2578 + /* look for tuple match */
2579 + h = ip_conntrack_find_get(&tuple, NULL);
2581 + h = init_conntrack(&tuple, proto, skb);
2588 + /* It exists; we have (non-exclusive) reference. */
2589 + if (DIRECTION(h) == IP_CT_DIR_REPLY) {
2590 + *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
2591 + /* Please set reply bit if this packet OK */
2594 + /* Once we've had two way comms, always ESTABLISHED. */
2595 + if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
2596 + DEBUGP("ip_conntrack_in: normal packet for %p\n",
2598 + *ctinfo = IP_CT_ESTABLISHED;
2599 + } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
2600 + DEBUGP("ip_conntrack_in: related packet for %p\n",
2602 + *ctinfo = IP_CT_RELATED;
2604 + DEBUGP("ip_conntrack_in: new packet for %p\n",
2606 + *ctinfo = IP_CT_NEW;
2610 + skb->nfct = &h->ctrack->infos[*ctinfo];
2614 +/* Netfilter hook itself. */
2615 +unsigned int ip_conntrack_in(unsigned int hooknum,
2616 + struct sk_buff **pskb,
2617 + const struct net_device *in,
2618 + const struct net_device *out,
2619 + int (*okfn)(struct sk_buff *))
2621 + struct ip_conntrack *ct;
2622 + enum ip_conntrack_info ctinfo;
2623 + struct ip_conntrack_protocol *proto;
2627 + /* FIXME: Do this right please. --RR */
2628 + (*pskb)->nfcache |= NFC_UNKNOWN;
2630 +/* Doesn't cover locally-generated broadcast, so not worth it. */
2632 + /* Ignore broadcast: no `connection'. */
2633 + if ((*pskb)->pkt_type == PACKET_BROADCAST) {
2634 + printk("Broadcast packet!\n");
2636 + } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
2637 + == htonl(0x000000FF)) {
2638 + printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
2639 + NIPQUAD((*pskb)->nh.iph->saddr),
2640 + NIPQUAD((*pskb)->nh.iph->daddr),
2641 + (*pskb)->sk, (*pskb)->pkt_type);
2645 + /* Previously seen (loopback)? Ignore. Do this before
2646 + fragment check. */
2647 + if ((*pskb)->nfct)
2650 + /* Gather fragments. */
2651 + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
2652 + *pskb = ip_ct_gather_frags(*pskb);
2657 + proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2659 + /* It may be an icmp error... */
2660 + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
2661 + && icmp_error_track(*pskb, &ctinfo, hooknum))
2664 + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
2665 + /* Not valid part of a connection */
2669 + /* Too stressed to deal. */
2672 + IP_NF_ASSERT((*pskb)->nfct);
2674 + ret = proto->packet(ct, *pskb, ctinfo);
2677 + nf_conntrack_put((*pskb)->nfct);
2678 + (*pskb)->nfct = NULL;
2682 + if (ret != NF_DROP && ct->helper) {
2683 + ret = ct->helper->help(*pskb, ct, ctinfo);
2686 + nf_conntrack_put((*pskb)->nfct);
2687 + (*pskb)->nfct = NULL;
2692 + set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
2697 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
2698 + const struct ip_conntrack_tuple *orig)
2700 + return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
2703 +static inline int resent_expect(const struct ip_conntrack_expect *i,
2704 + const struct ip_conntrack_tuple *tuple,
2705 + const struct ip_conntrack_tuple *mask)
2707 + DEBUGP("resent_expect\n");
2708 + DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
2709 + DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
2710 + DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
2711 + return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
2712 + || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
2713 + && ip_ct_tuple_equal(&i->mask, mask));
2716 +/* Would two expected things clash? */
2717 +static inline int expect_clash(const struct ip_conntrack_expect *i,
2718 + const struct ip_conntrack_tuple *tuple,
2719 + const struct ip_conntrack_tuple *mask)
2721 + /* Part covered by intersection of masks must be unequal,
2722 + otherwise they clash */
2723 + struct ip_conntrack_tuple intersect_mask
2724 + = { { i->mask.src.ip & mask->src.ip,
2725 + { i->mask.src.u.all & mask->src.u.all } },
2726 + { i->mask.dst.ip & mask->dst.ip,
2727 + { i->mask.dst.u.all & mask->dst.u.all },
2728 + i->mask.dst.protonum & mask->dst.protonum } };
2730 + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
2733 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
2735 + WRITE_LOCK(&ip_conntrack_lock);
2736 + unexpect_related(expect);
2737 + WRITE_UNLOCK(&ip_conntrack_lock);
2740 +static void expectation_timed_out(unsigned long ul_expect)
2742 + struct ip_conntrack_expect *expect = (void *) ul_expect;
2744 + DEBUGP("expectation %p timed out\n", expect);
2745 + WRITE_LOCK(&ip_conntrack_lock);
2746 + __unexpect_related(expect);
2747 + WRITE_UNLOCK(&ip_conntrack_lock);
2750 +/* Add a related connection. */
2751 +int ip_conntrack_expect_related(struct ip_conntrack *related_to,
2752 + struct ip_conntrack_expect *expect)
2754 + struct ip_conntrack_expect *old, *new;
2757 + WRITE_LOCK(&ip_conntrack_lock);
2758 + /* Because of the write lock, no reader can walk the lists,
2759 + * so there is no need to use the tuple lock too */
2761 + DEBUGP("ip_conntrack_expect_related %p\n", related_to);
2762 + DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
2763 + DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
2765 + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
2766 + struct ip_conntrack_expect *, &expect->tuple,
2769 + /* Helper private data may contain offsets but no pointers
2770 + pointing into the payload - otherwise we should have to copy
2771 + the data filled out by the helper over the old one */
2772 + DEBUGP("expect_related: resent packet\n");
2773 + if (related_to->helper->timeout) {
2774 + if (!del_timer(&old->timeout)) {
2775 + /* expectation is dying. Fall through */
2778 + old->timeout.expires = jiffies +
2779 + related_to->helper->timeout * HZ;
2780 + add_timer(&old->timeout);
2785 + WRITE_UNLOCK(&ip_conntrack_lock);
2788 + } else if (related_to->helper->max_expected &&
2789 + related_to->expecting >= related_to->helper->max_expected) {
2790 + struct list_head *cur_item;
2792 + if (!(related_to->helper->flags &
2793 + IP_CT_HELPER_F_REUSE_EXPECT)) {
2794 + WRITE_UNLOCK(&ip_conntrack_lock);
2795 + if (net_ratelimit())
2796 + printk(KERN_WARNING
2797 + "ip_conntrack: max number of expected "
2798 + "connections %i of %s reached for "
2799 + "%u.%u.%u.%u->%u.%u.%u.%u\n",
2800 + related_to->helper->max_expected,
2801 + related_to->helper->name,
2802 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
2803 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
2806 + DEBUGP("ip_conntrack: max number of expected "
2807 + "connections %i of %s reached for "
2808 + "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
2809 + related_to->helper->max_expected,
2810 + related_to->helper->name,
2811 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
2812 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
2814 + /* choose the the oldest expectation to evict */
2815 + list_for_each(cur_item, &related_to->sibling_list) {
2816 + struct ip_conntrack_expect *cur;
2818 + cur = list_entry(cur_item,
2819 + struct ip_conntrack_expect,
2821 + if (cur->sibling == NULL) {
2827 + /* (!old) cannot happen, since related_to->expecting is the
2828 + * number of unconfirmed expects */
2829 + IP_NF_ASSERT(old);
2831 + /* newnat14 does not reuse the real allocated memory
2832 + * structures but rather unexpects the old and
2833 + * allocates a new. unexpect_related will decrement
2834 + * related_to->expecting.
2836 + unexpect_related(old);
2838 + } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
2839 + struct ip_conntrack_expect *, &expect->tuple,
2841 + WRITE_UNLOCK(&ip_conntrack_lock);
2842 + DEBUGP("expect_related: busy!\n");
2846 + new = (struct ip_conntrack_expect *)
2847 + kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
2849 + WRITE_UNLOCK(&ip_conntrack_lock);
2850 + DEBUGP("expect_relaed: OOM allocating expect\n");
2854 + DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
2855 + memcpy(new, expect, sizeof(*expect));
2856 + new->expectant = related_to;
2857 + new->sibling = NULL;
2858 + atomic_set(&new->use, 1);
2860 + /* add to expected list for this connection */
2861 + list_add(&new->expected_list, &related_to->sibling_list);
2862 + /* add to global list of expectations */
2863 + list_prepend(&ip_conntrack_expect_list, &new->list);
2864 + /* add and start timer if required */
2865 + if (related_to->helper->timeout) {
2866 + init_timer(&new->timeout);
2867 + new->timeout.data = (unsigned long)new;
2868 + new->timeout.function = expectation_timed_out;
2869 + new->timeout.expires = jiffies +
2870 + related_to->helper->timeout * HZ;
2871 + add_timer(&new->timeout);
2873 + related_to->expecting++;
2875 + WRITE_UNLOCK(&ip_conntrack_lock);
2880 +/* Change tuple in an existing expectation */
2881 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
2882 + struct ip_conntrack_tuple *newtuple)
2886 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2887 + WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
2889 + DEBUGP("change_expect:\n");
2890 + DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
2891 + DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
2892 + DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
2893 + if (expect->ct_tuple.dst.protonum == 0) {
2894 + /* Never seen before */
2895 + DEBUGP("change expect: never seen before\n");
2896 + if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
2897 + && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
2898 + struct ip_conntrack_expect *, newtuple, &expect->mask)) {
2899 + /* Force NAT to find an unused tuple */
2902 + memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
2903 + memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
2907 + /* Resent packet */
2908 + DEBUGP("change expect: resent packet\n");
2909 + if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
2912 + /* Force NAT to choose again the same port */
2916 + WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
2921 +/* Alter reply tuple (maybe alter helper). If it's already taken,
2922 + return 0 and don't do alteration. */
2923 +int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
2924 + const struct ip_conntrack_tuple *newreply)
2926 + WRITE_LOCK(&ip_conntrack_lock);
2927 + if (__ip_conntrack_find(newreply, conntrack)) {
2928 + WRITE_UNLOCK(&ip_conntrack_lock);
2931 + /* Should be unconfirmed, so not in hash table yet */
2932 + IP_NF_ASSERT(!is_confirmed(conntrack));
2934 + DEBUGP("Altering reply tuple of %p to ", conntrack);
2935 + DUMP_TUPLE(newreply);
2937 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
2938 + if (!conntrack->master)
2939 + conntrack->helper = LIST_FIND(&helpers, helper_cmp,
2940 + struct ip_conntrack_helper *,
2942 + WRITE_UNLOCK(&ip_conntrack_lock);
2947 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
2949 + WRITE_LOCK(&ip_conntrack_lock);
2950 + list_prepend(&helpers, me);
2951 + WRITE_UNLOCK(&ip_conntrack_lock);
2956 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
2957 + const struct ip_conntrack_helper *me)
2959 + if (i->ctrack->helper == me) {
2960 + /* Get rid of any expected. */
2961 + remove_expectations(i->ctrack, 0);
2962 + /* And *then* set helper to NULL */
2963 + i->ctrack->helper = NULL;
2968 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
2972 + /* Need write lock here, to delete helper. */
2973 + WRITE_LOCK(&ip_conntrack_lock);
2974 + LIST_DELETE(&helpers, me);
2976 + /* Get rid of expecteds, set helpers to NULL. */
2977 + for (i = 0; i < ip_conntrack_htable_size; i++)
2978 + LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
2979 + struct ip_conntrack_tuple_hash *, me);
2980 + WRITE_UNLOCK(&ip_conntrack_lock);
2982 + /* Someone could be still looking at the helper in a bh. */
2983 + synchronize_net();
2986 +/* Refresh conntrack for this many jiffies. */
2987 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
2989 + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
2991 + WRITE_LOCK(&ip_conntrack_lock);
2992 + /* If not in hash table, timer will not be active yet */
2993 + if (!is_confirmed(ct))
2994 + ct->timeout.expires = extra_jiffies;
2996 + /* Need del_timer for race avoidance (may already be dying). */
2997 + if (del_timer(&ct->timeout)) {
2998 + ct->timeout.expires = jiffies + extra_jiffies;
2999 + add_timer(&ct->timeout);
3002 + WRITE_UNLOCK(&ip_conntrack_lock);
3005 +/* Returns new sk_buff, or NULL */
3007 +ip_ct_gather_frags(struct sk_buff *skb)
3009 + struct sock *sk = skb->sk;
3010 +#ifdef CONFIG_NETFILTER_DEBUG
3011 + unsigned int olddebug = skb->nf_debug;
3018 + local_bh_disable();
3019 + skb = ip_defrag(skb);
3020 + local_bh_enable();
3029 + skb_set_owner_w(skb, sk);
3033 + ip_send_check(skb->nh.iph);
3034 + skb->nfcache |= NFC_ALTERED;
3035 +#ifdef CONFIG_NETFILTER_DEBUG
3036 + /* Packet path as if nothing had happened. */
3037 + skb->nf_debug = olddebug;
3042 +/* Used by ipt_REJECT. */
3043 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
3045 + struct ip_conntrack *ct;
3046 + enum ip_conntrack_info ctinfo;
3048 + ct = __ip_conntrack_get(nfct, &ctinfo);
3050 + /* This ICMP is in reverse direction to the packet which
3052 + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
3053 + ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
3055 + ctinfo = IP_CT_RELATED;
3057 + /* Attach new skbuff, and increment count */
3058 + nskb->nfct = &ct->infos[ctinfo];
3059 + atomic_inc(&ct->ct_general.use);
3063 +do_kill(const struct ip_conntrack_tuple_hash *i,
3064 + int (*kill)(const struct ip_conntrack *i, void *data),
3067 + return kill(i->ctrack, data);
3070 +/* Bring out ya dead! */
3071 +static struct ip_conntrack_tuple_hash *
3072 +get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
3073 + void *data, unsigned int *bucket)
3075 + struct ip_conntrack_tuple_hash *h = NULL;
3077 + READ_LOCK(&ip_conntrack_lock);
3078 + for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
3079 + h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
3080 + struct ip_conntrack_tuple_hash *, kill, data);
3083 + atomic_inc(&h->ctrack->ct_general.use);
3084 + READ_UNLOCK(&ip_conntrack_lock);
3090 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
3093 + struct ip_conntrack_tuple_hash *h;
3094 + unsigned int bucket = 0;
3096 + while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
3097 + /* Time to push up daises... */
3098 + if (del_timer(&h->ctrack->timeout))
3099 + death_by_timeout((unsigned long)h->ctrack);
3100 + /* ... else the timer will get him soon. */
3102 + ip_conntrack_put(h->ctrack);
3106 +/* Fast function for those who don't want to parse /proc (and I don't
3108 +/* Reversing the socket's dst/src point of view gives us the reply
3111 +getorigdst(struct sock *sk, int optval, void *user, int *len)
3113 + struct inet_opt *inet = inet_sk(sk);
3114 + struct ip_conntrack_tuple_hash *h;
3115 + struct ip_conntrack_tuple tuple;
3117 + IP_CT_TUPLE_U_BLANK(&tuple);
3118 + tuple.src.ip = inet->rcv_saddr;
3119 + tuple.src.u.tcp.port = inet->sport;
3120 + tuple.dst.ip = inet->daddr;
3121 + tuple.dst.u.tcp.port = inet->dport;
3122 + tuple.dst.protonum = IPPROTO_TCP;
3124 + /* We only do TCP at the moment: is there a better way? */
3125 + if (strcmp(sk->sk_prot->name, "TCP")) {
3126 + DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
3127 + return -ENOPROTOOPT;
3130 + if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
3131 + DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
3132 + *len, sizeof(struct sockaddr_in));
3136 + h = ip_conntrack_find_get(&tuple, NULL);
3138 + struct sockaddr_in sin;
3140 + sin.sin_family = AF_INET;
3141 + sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3142 + .tuple.dst.u.tcp.port;
3143 + sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3146 + DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
3147 + NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
3148 + ip_conntrack_put(h->ctrack);
3149 + if (copy_to_user(user, &sin, sizeof(sin)) != 0)
3154 + DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
3155 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
3156 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
3160 +static struct nf_sockopt_ops so_getorigdst = {
3162 + .get_optmin = SO_ORIGINAL_DST,
3163 + .get_optmax = SO_ORIGINAL_DST+1,
3164 + .get = &getorigdst,
3167 +static int kill_all(const struct ip_conntrack *i, void *data)
3172 +/* Mishearing the voices in his head, our hero wonders how he's
3173 + supposed to kill the mall. */
3174 +void ip_conntrack_cleanup(void)
3176 + ip_ct_attach = NULL;
3177 + /* This makes sure all current packets have passed through
3178 + netfilter framework. Roll on, two-stage module
3180 + synchronize_net();
3182 + i_see_dead_people:
3183 + ip_ct_selective_cleanup(kill_all, NULL);
3184 + if (atomic_read(&ip_conntrack_count) != 0) {
3186 + goto i_see_dead_people;
3189 + kmem_cache_destroy(ip_conntrack_cachep);
3190 + vfree(ip_conntrack_hash);
3191 + nf_unregister_sockopt(&so_getorigdst);
3194 +static int hashsize;
3195 +MODULE_PARM(hashsize, "i");
3197 +int __init ip_conntrack_init(void)
3202 + /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
3203 + * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
3205 + ip_conntrack_htable_size = hashsize;
3207 + ip_conntrack_htable_size
3208 + = (((num_physpages << PAGE_SHIFT) / 16384)
3209 + / sizeof(struct list_head));
3210 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
3211 + ip_conntrack_htable_size = 8192;
3212 + if (ip_conntrack_htable_size < 16)
3213 + ip_conntrack_htable_size = 16;
3215 + ip_conntrack_max = 8 * ip_conntrack_htable_size;
3217 + printk("ip_conntrack version %s (%u buckets, %d max)"
3218 + " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
3219 + ip_conntrack_htable_size, ip_conntrack_max,
3220 + sizeof(struct ip_conntrack));
3222 + ret = nf_register_sockopt(&so_getorigdst);
3224 + printk(KERN_ERR "Unable to register netfilter socket option\n");
3228 + ip_conntrack_hash = vmalloc(sizeof(struct list_head)
3229 + * ip_conntrack_htable_size);
3230 + if (!ip_conntrack_hash) {
3231 + printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
3232 + goto err_unreg_sockopt;
3235 + ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
3236 + sizeof(struct ip_conntrack), 0,
3237 + SLAB_HWCACHE_ALIGN, NULL, NULL);
3238 + if (!ip_conntrack_cachep) {
3239 + printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
3240 + goto err_free_hash;
3242 + /* Don't NEED lock here, but good form anyway. */
3243 + WRITE_LOCK(&ip_conntrack_lock);
3244 + /* Sew in builtin protocols. */
3245 + list_append(&protocol_list, &ip_conntrack_protocol_tcp);
3246 + list_append(&protocol_list, &ip_conntrack_protocol_udp);
3247 + list_append(&protocol_list, &ip_conntrack_protocol_icmp);
3248 + WRITE_UNLOCK(&ip_conntrack_lock);
3250 + for (i = 0; i < ip_conntrack_htable_size; i++)
3251 + INIT_LIST_HEAD(&ip_conntrack_hash[i]);
3253 + /* For use by ipt_REJECT */
3254 + ip_ct_attach = ip_conntrack_attach;
3258 + vfree(ip_conntrack_hash);
3260 + nf_unregister_sockopt(&so_getorigdst);
3264 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c
3265 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-04 06:16:44.000000000 +0000
3266 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-05 07:39:43.000000000 +0000
3267 @@ -519,13 +519,20 @@
3271 -/* FIXME: Allow NULL functions and sub in pointers to generic for
3274 + * ip_conntrack_protocol_register - Register layer 4 protocol helper
3275 + * @proto: structure describing this layer 4 protocol helper
3277 + * This function is called by layer 4 protocol helpers to register
3278 + * themselves with the conntrack core.
3280 int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
3283 struct list_head *i;
3285 + /* FIXME: Allow NULL functions and sub in pointers to generic for
3287 WRITE_LOCK(&ip_conntrack_lock);
3288 list_for_each(i, &protocol_list) {
3289 if (((struct ip_conntrack_protocol *)i)->proto
3290 @@ -542,12 +549,20 @@
3295 + * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper
3296 + * @proto: structure describing this layer 4 protocol helper
3298 + * This function is called byh layer 4 protocol helpers to unregister
3299 + * themselvers from the conntrack core. Please note that all conntrack
3300 + * entries for this protocol are deleted from the conntrack hash table.
3302 void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
3304 WRITE_LOCK(&ip_conntrack_lock);
3306 - /* ip_ct_find_proto() returns proto_generic in case there is no protocol
3307 - * helper. So this should be enough - HW */
3308 + /* ip_ct_find_proto() returns proto_generic in case there is no
3309 + * protocol helper. So this should be enough - HW */
3310 LIST_DELETE(&protocol_list, proto);
3311 WRITE_UNLOCK(&ip_conntrack_lock);
3313 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig
3314 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 1970-01-01 00:00:00.000000000 +0000
3315 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 2004-03-04 06:16:44.000000000 +0000
3317 +/* This file contains all the functions required for the standalone
3318 + ip_conntrack module.
3320 + These are not required by the compatibility layer.
3323 +/* (C) 1999-2001 Paul `Rusty' Russell
3324 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3326 + * This program is free software; you can redistribute it and/or modify
3327 + * it under the terms of the GNU General Public License version 2 as
3328 + * published by the Free Software Foundation.
3331 +#include <linux/config.h>
3332 +#include <linux/types.h>
3333 +#include <linux/ip.h>
3334 +#include <linux/netfilter.h>
3335 +#include <linux/netfilter_ipv4.h>
3336 +#include <linux/module.h>
3337 +#include <linux/skbuff.h>
3338 +#include <linux/proc_fs.h>
3339 +#ifdef CONFIG_SYSCTL
3340 +#include <linux/sysctl.h>
3342 +#include <net/checksum.h>
3344 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
3345 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
3347 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3348 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
3349 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3350 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
3351 +#include <linux/netfilter_ipv4/listhelp.h>
3354 +#define DEBUGP printk
3356 +#define DEBUGP(format, args...)
3359 +MODULE_LICENSE("GPL");
3361 +static int kill_proto(const struct ip_conntrack *i, void *data)
3363 + return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
3364 + *((u_int8_t *) data));
3367 +static unsigned int
3368 +print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple,
3369 + struct ip_conntrack_protocol *proto)
3373 + len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
3374 + NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
3376 + len += proto->print_tuple(buffer + len, tuple);
3381 +/* FIXME: Don't print source proto part. --RR */
3382 +static unsigned int
3383 +print_expect(char *buffer, const struct ip_conntrack_expect *expect)
3387 + if (expect->expectant->helper->timeout)
3388 + len = sprintf(buffer, "EXPECTING: %lu ",
3389 + timer_pending(&expect->timeout)
3390 + ? (expect->timeout.expires - jiffies)/HZ : 0);
3392 + len = sprintf(buffer, "EXPECTING: - ");
3393 + len += sprintf(buffer + len, "use=%u proto=%u ",
3394 + atomic_read(&expect->use), expect->tuple.dst.protonum);
3395 + len += print_tuple(buffer + len, &expect->tuple,
3396 + __ip_ct_find_proto(expect->tuple.dst.protonum));
3397 + len += sprintf(buffer + len, "\n");
3401 +static unsigned int
3402 +print_conntrack(char *buffer, struct ip_conntrack *conntrack)
3405 + struct ip_conntrack_protocol *proto
3406 + = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
3407 + .tuple.dst.protonum);
3409 + len = sprintf(buffer, "%-8s %u %lu ",
3411 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
3412 + .tuple.dst.protonum,
3413 + timer_pending(&conntrack->timeout)
3414 + ? (conntrack->timeout.expires - jiffies)/HZ : 0);
3416 + len += proto->print_conntrack(buffer + len, conntrack);
3417 + len += print_tuple(buffer + len,
3418 + &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
3420 + if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
3421 + len += sprintf(buffer + len, "[UNREPLIED] ");
3422 + len += print_tuple(buffer + len,
3423 + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
3425 + if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
3426 + len += sprintf(buffer + len, "[ASSURED] ");
3427 + len += sprintf(buffer + len, "use=%u ",
3428 + atomic_read(&conntrack->ct_general.use));
3429 + len += sprintf(buffer + len, "\n");
3434 +/* Returns true when finished. */
3436 +conntrack_iterate(const struct ip_conntrack_tuple_hash *hash,
3437 + char *buffer, off_t offset, off_t *upto,
3438 + unsigned int *len, unsigned int maxlen)
3440 + unsigned int newlen;
3441 + IP_NF_ASSERT(hash->ctrack);
3443 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3445 + /* Only count originals */
3446 + if (DIRECTION(hash))
3449 + if ((*upto)++ < offset)
3452 + newlen = print_conntrack(buffer + *len, hash->ctrack);
3453 + if (*len + newlen > maxlen)
3455 + else *len += newlen;
3461 +list_conntracks(char *buffer, char **start, off_t offset, int length)
3464 + unsigned int len = 0;
3466 + struct list_head *e;
3468 + READ_LOCK(&ip_conntrack_lock);
3469 + /* Traverse hash; print originals then reply. */
3470 + for (i = 0; i < ip_conntrack_htable_size; i++) {
3471 + if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
3472 + struct ip_conntrack_tuple_hash *,
3473 + buffer, offset, &upto, &len, length))
3477 + /* Now iterate through expecteds. */
3478 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
3479 + list_for_each(e, &ip_conntrack_expect_list) {
3480 + unsigned int last_len;
3481 + struct ip_conntrack_expect *expect
3482 + = (struct ip_conntrack_expect *)e;
3483 + if (upto++ < offset) continue;
3486 + len += print_expect(buffer + len, expect);
3487 + if (len > length) {
3489 + goto finished_expects;
3494 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
3496 + READ_UNLOCK(&ip_conntrack_lock);
3498 + /* `start' hack - see fs/proc/generic.c line ~165 */
3499 + *start = (char *)((unsigned int)upto - offset);
3503 +static unsigned int ip_confirm(unsigned int hooknum,
3504 + struct sk_buff **pskb,
3505 + const struct net_device *in,
3506 + const struct net_device *out,
3507 + int (*okfn)(struct sk_buff *))
3509 + /* We've seen it coming out the other side: confirm it */
3510 + return ip_conntrack_confirm(*pskb);
3513 +static unsigned int ip_refrag(unsigned int hooknum,
3514 + struct sk_buff **pskb,
3515 + const struct net_device *in,
3516 + const struct net_device *out,
3517 + int (*okfn)(struct sk_buff *))
3519 + struct rtable *rt = (struct rtable *)(*pskb)->dst;
3521 + /* We've seen it coming out the other side: confirm */
3522 + if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
3525 + /* Local packets are never produced too large for their
3526 + interface. We degfragment them at LOCAL_OUT, however,
3527 + so we have to refragment them here. */
3528 + if ((*pskb)->len > dst_pmtu(&rt->u.dst) &&
3529 + !skb_shinfo(*pskb)->tso_size) {
3530 + /* No hook can be after us, so this should be OK. */
3531 + ip_fragment(*pskb, okfn);
3537 +static unsigned int ip_conntrack_local(unsigned int hooknum,
3538 + struct sk_buff **pskb,
3539 + const struct net_device *in,
3540 + const struct net_device *out,
3541 + int (*okfn)(struct sk_buff *))
3543 + /* root is playing with raw sockets. */
3544 + if ((*pskb)->len < sizeof(struct iphdr)
3545 + || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
3546 + if (net_ratelimit())
3547 + printk("ipt_hook: happy cracking.\n");
3550 + return ip_conntrack_in(hooknum, pskb, in, out, okfn);
3553 +/* Connection tracking may drop packets, but never alters them, so
3554 + make it the first hook. */
3555 +static struct nf_hook_ops ip_conntrack_in_ops = {
3556 + .hook = ip_conntrack_in,
3557 + .owner = THIS_MODULE,
3559 + .hooknum = NF_IP_PRE_ROUTING,
3560 + .priority = NF_IP_PRI_CONNTRACK,
3563 +static struct nf_hook_ops ip_conntrack_local_out_ops = {
3564 + .hook = ip_conntrack_local,
3565 + .owner = THIS_MODULE,
3567 + .hooknum = NF_IP_LOCAL_OUT,
3568 + .priority = NF_IP_PRI_CONNTRACK,
3571 +/* Refragmenter; last chance. */
3572 +static struct nf_hook_ops ip_conntrack_out_ops = {
3573 + .hook = ip_refrag,
3574 + .owner = THIS_MODULE,
3576 + .hooknum = NF_IP_POST_ROUTING,
3577 + .priority = NF_IP_PRI_LAST,
3580 +static struct nf_hook_ops ip_conntrack_local_in_ops = {
3581 + .hook = ip_confirm,
3582 + .owner = THIS_MODULE,
3584 + .hooknum = NF_IP_LOCAL_IN,
3585 + .priority = NF_IP_PRI_LAST-1,
3588 +/* Sysctl support */
3590 +#ifdef CONFIG_SYSCTL
3592 +/* From ip_conntrack_core.c */
3593 +extern int ip_conntrack_max;
3594 +extern unsigned int ip_conntrack_htable_size;
3596 +/* From ip_conntrack_proto_tcp.c */
3597 +extern unsigned long ip_ct_tcp_timeout_syn_sent;
3598 +extern unsigned long ip_ct_tcp_timeout_syn_recv;
3599 +extern unsigned long ip_ct_tcp_timeout_established;
3600 +extern unsigned long ip_ct_tcp_timeout_fin_wait;
3601 +extern unsigned long ip_ct_tcp_timeout_close_wait;
3602 +extern unsigned long ip_ct_tcp_timeout_last_ack;
3603 +extern unsigned long ip_ct_tcp_timeout_time_wait;
3604 +extern unsigned long ip_ct_tcp_timeout_close;
3606 +/* From ip_conntrack_proto_udp.c */
3607 +extern unsigned long ip_ct_udp_timeout;
3608 +extern unsigned long ip_ct_udp_timeout_stream;
3610 +/* From ip_conntrack_proto_icmp.c */
3611 +extern unsigned long ip_ct_icmp_timeout;
3613 +/* From ip_conntrack_proto_icmp.c */
3614 +extern unsigned long ip_ct_generic_timeout;
3616 +static struct ctl_table_header *ip_ct_sysctl_header;
3618 +static ctl_table ip_ct_sysctl_table[] = {
3620 + .ctl_name = NET_IPV4_NF_CONNTRACK_MAX,
3621 + .procname = "ip_conntrack_max",
3622 + .data = &ip_conntrack_max,
3623 + .maxlen = sizeof(int),
3625 + .proc_handler = &proc_dointvec,
3628 + .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
3629 + .procname = "ip_conntrack_buckets",
3630 + .data = &ip_conntrack_htable_size,
3631 + .maxlen = sizeof(unsigned int),
3633 + .proc_handler = &proc_dointvec,
3636 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
3637 + .procname = "ip_conntrack_tcp_timeout_syn_sent",
3638 + .data = &ip_ct_tcp_timeout_syn_sent,
3639 + .maxlen = sizeof(unsigned int),
3641 + .proc_handler = &proc_dointvec_jiffies,
3644 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
3645 + .procname = "ip_conntrack_tcp_timeout_syn_recv",
3646 + .data = &ip_ct_tcp_timeout_syn_recv,
3647 + .maxlen = sizeof(unsigned int),
3649 + .proc_handler = &proc_dointvec_jiffies,
3652 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
3653 + .procname = "ip_conntrack_tcp_timeout_established",
3654 + .data = &ip_ct_tcp_timeout_established,
3655 + .maxlen = sizeof(unsigned int),
3657 + .proc_handler = &proc_dointvec_jiffies,
3660 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
3661 + .procname = "ip_conntrack_tcp_timeout_fin_wait",
3662 + .data = &ip_ct_tcp_timeout_fin_wait,
3663 + .maxlen = sizeof(unsigned int),
3665 + .proc_handler = &proc_dointvec_jiffies,
3668 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
3669 + .procname = "ip_conntrack_tcp_timeout_close_wait",
3670 + .data = &ip_ct_tcp_timeout_close_wait,
3671 + .maxlen = sizeof(unsigned int),
3673 + .proc_handler = &proc_dointvec_jiffies,
3676 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
3677 + .procname = "ip_conntrack_tcp_timeout_last_ack",
3678 + .data = &ip_ct_tcp_timeout_last_ack,
3679 + .maxlen = sizeof(unsigned int),
3681 + .proc_handler = &proc_dointvec_jiffies,
3684 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
3685 + .procname = "ip_conntrack_tcp_timeout_time_wait",
3686 + .data = &ip_ct_tcp_timeout_time_wait,
3687 + .maxlen = sizeof(unsigned int),
3689 + .proc_handler = &proc_dointvec_jiffies,
3692 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
3693 + .procname = "ip_conntrack_tcp_timeout_close",
3694 + .data = &ip_ct_tcp_timeout_close,
3695 + .maxlen = sizeof(unsigned int),
3697 + .proc_handler = &proc_dointvec_jiffies,
3700 + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,
3701 + .procname = "ip_conntrack_udp_timeout",
3702 + .data = &ip_ct_udp_timeout,
3703 + .maxlen = sizeof(unsigned int),
3705 + .proc_handler = &proc_dointvec_jiffies,
3708 + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
3709 + .procname = "ip_conntrack_udp_timeout_stream",
3710 + .data = &ip_ct_udp_timeout_stream,
3711 + .maxlen = sizeof(unsigned int),
3713 + .proc_handler = &proc_dointvec_jiffies,
3716 + .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
3717 + .procname = "ip_conntrack_icmp_timeout",
3718 + .data = &ip_ct_icmp_timeout,
3719 + .maxlen = sizeof(unsigned int),
3721 + .proc_handler = &proc_dointvec_jiffies,
3724 + .ctl_name = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,
3725 + .procname = "ip_conntrack_generic_timeout",
3726 + .data = &ip_ct_generic_timeout,
3727 + .maxlen = sizeof(unsigned int),
3729 + .proc_handler = &proc_dointvec_jiffies,
3734 +#define NET_IP_CONNTRACK_MAX 2089
3736 +static ctl_table ip_ct_netfilter_table[] = {
3738 + .ctl_name = NET_IPV4_NETFILTER,
3739 + .procname = "netfilter",
3741 + .child = ip_ct_sysctl_table,
3744 + .ctl_name = NET_IP_CONNTRACK_MAX,
3745 + .procname = "ip_conntrack_max",
3746 + .data = &ip_conntrack_max,
3747 + .maxlen = sizeof(int),
3749 + .proc_handler = &proc_dointvec
3754 +static ctl_table ip_ct_ipv4_table[] = {
3756 + .ctl_name = NET_IPV4,
3757 + .procname = "ipv4",
3759 + .child = ip_ct_netfilter_table,
3764 +static ctl_table ip_ct_net_table[] = {
3766 + .ctl_name = CTL_NET,
3767 + .procname = "net",
3769 + .child = ip_ct_ipv4_table,
3774 +static int init_or_cleanup(int init)
3776 + struct proc_dir_entry *proc;
3779 + if (!init) goto cleanup;
3781 + ret = ip_conntrack_init();
3783 + goto cleanup_nothing;
3785 + proc = proc_net_create("ip_conntrack",0,list_conntracks);
3786 + if (!proc) goto cleanup_init;
3787 + proc->owner = THIS_MODULE;
3789 + ret = nf_register_hook(&ip_conntrack_in_ops);
3791 + printk("ip_conntrack: can't register pre-routing hook.\n");
3792 + goto cleanup_proc;
3794 + ret = nf_register_hook(&ip_conntrack_local_out_ops);
3796 + printk("ip_conntrack: can't register local out hook.\n");
3797 + goto cleanup_inops;
3799 + ret = nf_register_hook(&ip_conntrack_out_ops);
3801 + printk("ip_conntrack: can't register post-routing hook.\n");
3802 + goto cleanup_inandlocalops;
3804 + ret = nf_register_hook(&ip_conntrack_local_in_ops);
3806 + printk("ip_conntrack: can't register local in hook.\n");
3807 + goto cleanup_inoutandlocalops;
3809 +#ifdef CONFIG_SYSCTL
3810 + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
3811 + if (ip_ct_sysctl_header == NULL) {
3812 + printk("ip_conntrack: can't register to sysctl.\n");
3820 +#ifdef CONFIG_SYSCTL
3821 + unregister_sysctl_table(ip_ct_sysctl_header);
3823 + nf_unregister_hook(&ip_conntrack_local_in_ops);
3824 + cleanup_inoutandlocalops:
3825 + nf_unregister_hook(&ip_conntrack_out_ops);
3826 + cleanup_inandlocalops:
3827 + nf_unregister_hook(&ip_conntrack_local_out_ops);
3829 + nf_unregister_hook(&ip_conntrack_in_ops);
3831 + proc_net_remove("ip_conntrack");
3833 + ip_conntrack_cleanup();
3838 +/* FIXME: Allow NULL functions and sub in pointers to generic for
3840 +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
3843 + struct list_head *i;
3845 + WRITE_LOCK(&ip_conntrack_lock);
3846 + list_for_each(i, &protocol_list) {
3847 + if (((struct ip_conntrack_protocol *)i)->proto
3848 + == proto->proto) {
3854 + list_prepend(&protocol_list, proto);
3857 + WRITE_UNLOCK(&ip_conntrack_lock);
3861 +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
3863 + WRITE_LOCK(&ip_conntrack_lock);
3865 + /* ip_ct_find_proto() returns proto_generic in case there is no protocol
3866 + * helper. So this should be enough - HW */
3867 + LIST_DELETE(&protocol_list, proto);
3868 + WRITE_UNLOCK(&ip_conntrack_lock);
3870 + /* Somebody could be still looking at the proto in bh. */
3871 + synchronize_net();
3873 + /* Remove all contrack entries for this protocol */
3874 + ip_ct_selective_cleanup(kill_proto, &proto->proto);
3877 +static int __init init(void)
3879 + return init_or_cleanup(1);
3882 +static void __exit fini(void)
3884 + init_or_cleanup(0);
3890 +/* Some modules need us, but don't depend directly on any symbol.
3891 + They should call this. */
3892 +void need_ip_conntrack(void)
3896 +EXPORT_SYMBOL(ip_conntrack_protocol_register);
3897 +EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
3898 +EXPORT_SYMBOL(invert_tuplepr);
3899 +EXPORT_SYMBOL(ip_conntrack_alter_reply);
3900 +EXPORT_SYMBOL(ip_conntrack_destroyed);
3901 +EXPORT_SYMBOL(ip_conntrack_get);
3902 +EXPORT_SYMBOL(need_ip_conntrack);
3903 +EXPORT_SYMBOL(ip_conntrack_helper_register);
3904 +EXPORT_SYMBOL(ip_conntrack_helper_unregister);
3905 +EXPORT_SYMBOL(ip_ct_selective_cleanup);
3906 +EXPORT_SYMBOL(ip_ct_refresh);
3907 +EXPORT_SYMBOL(ip_ct_find_proto);
3908 +EXPORT_SYMBOL(__ip_ct_find_proto);
3909 +EXPORT_SYMBOL(ip_ct_find_helper);
3910 +EXPORT_SYMBOL(ip_conntrack_expect_related);
3911 +EXPORT_SYMBOL(ip_conntrack_change_expect);
3912 +EXPORT_SYMBOL(ip_conntrack_unexpect_related);
3913 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
3914 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
3915 +EXPORT_SYMBOL(ip_conntrack_tuple_taken);
3916 +EXPORT_SYMBOL(ip_ct_gather_frags);
3917 +EXPORT_SYMBOL(ip_conntrack_htable_size);
3918 +EXPORT_SYMBOL(ip_conntrack_expect_list);
3919 +EXPORT_SYMBOL(ip_conntrack_lock);
3920 +EXPORT_SYMBOL(ip_conntrack_hash);
3921 +EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
3922 +EXPORT_SYMBOL_GPL(ip_conntrack_put);
3923 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c
3924 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c 2004-03-04 06:16:37.000000000 +0000
3925 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c 2004-03-05 07:39:43.000000000 +0000
3927 WRITE_UNLOCK(&ip_nat_lock);
3930 -/* We do checksum mangling, so if they were wrong before they're still
3931 - * wrong. Also works for incomplete packets (eg. ICMP dest
3932 - * unreachables.) */
3934 + * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum
3935 + * @oldvalinv: bit-inverted old value of 32bit word
3936 + * @newval: new value of 32bit word
3937 + * @oldcheck: old checksum value
3939 + * This function implements incremental checksum mangling, so if a checksum
3940 + * was wrong it will still be wrong after mangling. Also works for incomplete
3941 + * packets (eg. ICMP dest unreachables). Return value is the new checksum.
3944 ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
3946 @@ -124,7 +131,14 @@
3950 -/* Is this tuple already taken? (not by us) */
3952 + * ip_nat_used_tuple - Is this tuple already in use?
3953 + * @tuple: tuple to be used for this check
3954 + * @ignored_conntrack: conntrack excluded from this check
3956 + * This function checks for the reply (inverted) tuple in the conntrack
3957 + * hash. This is necessarry with NAT, since there is no fixed mapping.
3960 ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
3961 const struct ip_conntrack *ignored_conntrack)
3962 @@ -515,6 +529,19 @@
3967 + * ip_nat_setup_info - Set up NAT mappings for NEW packet
3968 + * @conntrack: conntrack on which we operate
3969 + * @mr: address/port range which is valid for this NAT mapping
3970 + * @hooknum: hook at which this NAT mapping applies
3972 + * This function is called by NAT targets (SNAT,DNAT,...) and by
3973 + * the NAT application helper modules. It is called for the NEW packet
3974 + * of a connection in order to specify which NAT mappings shall apply to
3975 + * this connection at a given hook.
3977 + * Note: The reply mappings are created automagically by this function.
3980 ip_nat_setup_info(struct ip_conntrack *conntrack,
3981 const struct ip_nat_multi_range *mr,
3982 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c
3983 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c 2004-03-04 06:16:38.000000000 +0000
3984 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c 2004-03-05 07:39:43.000000000 +0000
3985 @@ -150,9 +150,19 @@
3989 -/* Generic function for mangling variable-length address changes inside
3990 - * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
3991 - * command in FTP).
3993 + * ip_nat_mangle_tcp_packet - Mangle and potentially resize payload packet
3994 + * @skb: pointer to skb of packet on which we operate
3995 + * @ct: conntrack of the connection to which this packet belongs
3996 + * @ctinfo: conntrack_info of the connection to which this packet belongs
3997 + * @match_offset: offset in bytes where to-be-manipulated part starts
3998 + * @match_len: lenght of the to-be-manipulated part
3999 + * @rep_buffer: pointer to buffer containing replacement
4000 + * @rep_len: length of replacement
4002 + * Generic function for mangling fixed and variable-length changes inside
4003 + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command
4006 * Takes care about all the nasty sequence number changes, checksumming,
4007 * skb enlargement, ...
4008 @@ -198,16 +208,27 @@
4012 -/* Generic function for mangling variable-length address changes inside
4013 - * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
4014 - * command in the Amanda protocol)
4016 + * ip_nat_mangle_udp_packet - Mangle and potentially resize payload packet
4017 + * @skb: pointer to skb of packet on which we operate
4018 + * @ct: conntrack of the connection to which this packet belongs
4019 + * @ctinfo: conntrack_info of the connection to which this packet belongs
4020 + * @match_offset: offset in bytes where to-be-manipulated part starts
4021 + * @match_len: lenght of the to-be-manipulated part
4022 + * @rep_buffer: pointer to buffer containing replacement
4023 + * @rep_len: length of replacement
4025 + * Generic function for mangling fixed and variable-length changes inside
4026 + * NATed TCP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
4027 + * commad in the Amanda protocol)
4029 * Takes care about all the nasty sequence number changes, checksumming,
4030 * skb enlargement, ...
4032 - * XXX - This function could be merged with ip_nat_mangle_tcp_packet which
4033 - * should be fairly easy to do.
4035 + * FIXME: should be unified with ip_nat_mangle_tcp_packet!!
4040 ip_nat_mangle_udp_packet(struct sk_buff **pskb,
4041 struct ip_conntrack *ct,
4042 @@ -405,6 +426,13 @@
4043 return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
4047 + * ip_nat_helper_register - Register NAT application helper
4048 + * @me: structure describing the helper
4050 + * This function is called by NAT application helpers to register
4051 + * themselves with the NAT core.
4053 int ip_nat_helper_register(struct ip_nat_helper *me)
4056 @@ -431,6 +459,13 @@
4061 + * ip_nat_helper_unregister - Unregister NAT application helper
4062 + * @me: structure describing the helper
4064 + * This function is called by NAT application helpers to unregister
4065 + * themselves from the NAT core.
4067 void ip_nat_helper_unregister(struct ip_nat_helper *me)
4069 WRITE_LOCK(&ip_nat_lock);
4070 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c
4071 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c 2004-03-04 06:16:55.000000000 +0000
4072 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c 2004-03-05 07:39:43.000000000 +0000
4073 @@ -266,7 +266,13 @@
4077 -/* Protocol registration. */
4079 + * ip_nat_protocol_register - Register a layer 4 protocol helper
4080 + * @proto: structure describing this helper
4082 + * This function is called by NAT layer 4 protocol helpers to register
4083 + * themselvers with the NAT core.
4085 int ip_nat_protocol_register(struct ip_nat_protocol *proto)
4088 @@ -287,9 +293,16 @@
4092 -/* Noone stores the protocol anywhere; simply delete it. */
4094 + * ip_nat_protocol_unregister - Unregister a layer 4 protocol helper
4095 + * @proto: structure describing the helper
4097 + * This function is called by NAT layer 4 protocol helpers to
4098 + * unregister themselves from the NAT core.
4100 void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
4102 + /* Noone stores the protocol anywhere; simply delete it. */
4103 WRITE_LOCK(&ip_nat_lock);
4104 LIST_DELETE(&protos, proto);
4105 WRITE_UNLOCK(&ip_nat_lock);
4106 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
4107 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 00:00:00.000000000 +0000
4108 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-03-05 07:39:55.000000000 +0000
4111 + * Strip all IP options in the IP packet header.
4113 + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
4114 + * This software is distributed under GNU GPL v2, 1991
4117 +#include <linux/module.h>
4118 +#include <linux/skbuff.h>
4119 +#include <linux/ip.h>
4120 +#include <net/checksum.h>
4122 +#include <linux/netfilter_ipv4/ip_tables.h>
4124 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
4125 +MODULE_DESCRIPTION("Strip all options in IPv4 packets");
4126 +MODULE_LICENSE("GPL");
4128 +static unsigned int
4129 +target(struct sk_buff **pskb,
4130 + const struct net_device *in,
4131 + const struct net_device *out,
4132 + unsigned int hooknum,
4133 + const void *targinfo,
4136 + struct iphdr *iph;
4137 + struct sk_buff *skb;
4138 + struct ip_options *opt;
4139 + unsigned char *optiph;
4142 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
4146 + iph = (*pskb)->nh.iph;
4147 + optiph = skb->nh.raw;
4148 + l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
4150 + /* if no options in packet then nothing to clear. */
4151 + if (iph->ihl * 4 == sizeof(struct iphdr))
4152 + return IPT_CONTINUE;
4154 + /* else clear all options */
4155 + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
4156 + memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
4157 + opt = &(IPCB(skb)->opt);
4161 + skb->nfcache |= NFC_ALTERED;
4163 + return IPT_CONTINUE;
4167 +checkentry(const char *tablename,
4168 + const struct ipt_entry *e,
4170 + unsigned int targinfosize,
4171 + unsigned int hook_mask)
4173 + if (strcmp(tablename, "mangle")) {
4174 + printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
4177 + /* nothing else to check because no parameters */
4181 +static struct ipt_target ipt_ipv4optsstrip_reg = {
4182 + .name = "IPV4OPTSSTRIP",
4184 + .checkentry = checkentry,
4185 + .me = THIS_MODULE };
4187 +static int __init init(void)
4189 + return ipt_register_target(&ipt_ipv4optsstrip_reg);
4192 +static void __exit fini(void)
4194 + ipt_unregister_target(&ipt_ipv4optsstrip_reg);
4199 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c
4200 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 00:00:00.000000000 +0000
4201 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c 2004-03-05 07:40:01.000000000 +0000
4203 +/* TTL modification target for IP tables
4204 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
4206 + * Version: $Revision$
4208 + * This software is distributed under the terms of GNU GPL
4211 +#include <linux/module.h>
4212 +#include <linux/skbuff.h>
4213 +#include <linux/ip.h>
4214 +#include <net/checksum.h>
4216 +#include <linux/netfilter_ipv4/ip_tables.h>
4217 +#include <linux/netfilter_ipv4/ipt_TTL.h>
4219 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
4220 +MODULE_DESCRIPTION("IP tables TTL modification module");
4221 +MODULE_LICENSE("GPL");
4223 +static unsigned int
4224 +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
4225 + const struct net_device *out, unsigned int hooknum,
4226 + const void *targinfo, void *userinfo)
4228 + struct iphdr *iph;
4229 + const struct ipt_TTL_info *info = targinfo;
4230 + u_int16_t diffs[2];
4233 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
4236 + iph = (*pskb)->nh.iph;
4238 + switch (info->mode) {
4240 + new_ttl = info->ttl;
4243 + new_ttl = iph->ttl + info->ttl;
4244 + if (new_ttl > 255)
4248 + new_ttl = iph->ttl + info->ttl;
4253 + new_ttl = iph->ttl;
4257 + if (new_ttl != iph->ttl) {
4258 + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
4259 + iph->ttl = new_ttl;
4260 + diffs[1] = htons(((unsigned)iph->ttl) << 8);
4261 + iph->check = csum_fold(csum_partial((char *)diffs,
4263 + iph->check^0xFFFF));
4264 + (*pskb)->nfcache |= NFC_ALTERED;
4267 + return IPT_CONTINUE;
4270 +static int ipt_ttl_checkentry(const char *tablename,
4271 + const struct ipt_entry *e,
4273 + unsigned int targinfosize,
4274 + unsigned int hook_mask)
4276 + struct ipt_TTL_info *info = targinfo;
4278 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
4279 + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
4281 + IPT_ALIGN(sizeof(struct ipt_TTL_info)));
4285 + if (strcmp(tablename, "mangle")) {
4286 + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
4290 + if (info->mode > IPT_TTL_MAXMODE) {
4291 + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n",
4296 + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
4297 + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
4304 +static struct ipt_target ipt_TTL = {
4306 + .target = ipt_ttl_target,
4307 + .checkentry = ipt_ttl_checkentry,
4311 +static int __init init(void)
4313 + return ipt_register_target(&ipt_TTL);
4316 +static void __exit fini(void)
4318 + ipt_unregister_target(&ipt_TTL);
4323 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c
4324 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 00:00:00.000000000 +0000
4325 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c 2004-03-05 07:40:04.000000000 +0000
4328 + * netfilter module to limit the number of parallel tcp
4329 + * connections per IP address.
4330 + * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
4331 + * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
4332 + * only ignore TIME_WAIT or gone connections
4336 + * Kernel module to match connection tracking information.
4337 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
4339 +#include <linux/module.h>
4340 +#include <linux/skbuff.h>
4341 +#include <linux/list.h>
4342 +#include <linux/netfilter_ipv4/ip_conntrack.h>
4343 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
4344 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
4345 +#include <linux/netfilter_ipv4/ip_tables.h>
4346 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
4350 +MODULE_LICENSE("GPL");
4352 +/* we'll save the tuples of all connections we care about */
4353 +struct ipt_connlimit_conn
4355 + struct list_head list;
4356 + struct ip_conntrack_tuple tuple;
4359 +struct ipt_connlimit_data {
4361 + struct list_head iphash[256];
4364 +static int ipt_iphash(u_int32_t addr)
4368 + hash = addr & 0xff;
4369 + hash ^= (addr >> 8) & 0xff;
4370 + hash ^= (addr >> 16) & 0xff;
4371 + hash ^= (addr >> 24) & 0xff;
4375 +static int count_them(struct ipt_connlimit_data *data,
4376 + u_int32_t addr, u_int32_t mask,
4377 + struct ip_conntrack *ct)
4380 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
4381 + "fin_wait", "time_wait", "close", "close_wait",
4382 + "last_ack", "listen" };
4384 + int addit = 1, matches = 0;
4385 + struct ip_conntrack_tuple tuple;
4386 + struct ip_conntrack_tuple_hash *found;
4387 + struct ipt_connlimit_conn *conn;
4388 + struct list_head *hash,*lh;
4390 + spin_lock(&data->lock);
4391 + tuple = ct->tuplehash[0].tuple;
4392 + hash = &data->iphash[ipt_iphash(addr & mask)];
4394 + /* check the saved connections */
4395 + for (lh = hash->next; lh != hash; lh = lh->next) {
4396 + conn = list_entry(lh,struct ipt_connlimit_conn,list);
4397 + found = ip_conntrack_find_get(&conn->tuple,ct);
4398 + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
4400 + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
4401 + /* Just to be sure we have it only once in the list.
4402 + We should'nt see tuples twice unless someone hooks this
4403 + into a table without "-p tcp --syn" */
4407 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
4408 + ipt_iphash(addr & mask),
4409 + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
4410 + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
4411 + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
4413 + if (NULL == found) {
4414 + /* this one is gone */
4416 + list_del(lh->next);
4420 + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
4421 + /* we don't care about connections which are
4422 + closed already -> ditch it */
4424 + list_del(lh->next);
4426 + nf_conntrack_put(&found->ctrack->infos[0]);
4429 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
4430 + /* same source IP address -> be counted! */
4433 + nf_conntrack_put(&found->ctrack->infos[0]);
4436 + /* save the new connection in our list */
4438 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
4439 + ipt_iphash(addr & mask),
4440 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
4441 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
4443 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
4446 + memset(conn,0,sizeof(*conn));
4447 + INIT_LIST_HEAD(&conn->list);
4448 + conn->tuple = tuple;
4449 + list_add(&conn->list,hash);
4452 + spin_unlock(&data->lock);
4457 +match(const struct sk_buff *skb,
4458 + const struct net_device *in,
4459 + const struct net_device *out,
4460 + const void *matchinfo,
4464 + const struct ipt_connlimit_info *info = matchinfo;
4465 + int connections, match;
4466 + struct ip_conntrack *ct;
4467 + enum ip_conntrack_info ctinfo;
4469 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
4471 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
4475 + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
4476 + if (-1 == connections) {
4477 + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
4478 + *hotdrop = 1; /* let's free some memory :-) */
4481 + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
4483 + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
4484 + "connections=%d limit=%d match=%s\n",
4485 + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
4486 + connections, info->limit, match ? "yes" : "no");
4492 +static int check(const char *tablename,
4493 + const struct ipt_ip *ip,
4495 + unsigned int matchsize,
4496 + unsigned int hook_mask)
4498 + struct ipt_connlimit_info *info = matchinfo;
4502 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
4505 + /* refuse anything but tcp */
4506 + if (ip->proto != IPPROTO_TCP)
4509 + /* init private data */
4510 + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
4511 + spin_lock_init(&(info->data->lock));
4512 + for (i = 0; i < 256; i++)
4513 + INIT_LIST_HEAD(&(info->data->iphash[i]));
4518 +static void destroy(void *matchinfo, unsigned int matchinfosize)
4520 + struct ipt_connlimit_info *info = matchinfo;
4521 + struct ipt_connlimit_conn *conn;
4522 + struct list_head *hash;
4526 + for (i = 0; i < 256; i++) {
4527 + hash = &(info->data->iphash[i]);
4528 + while (hash != hash->next) {
4529 + conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
4530 + list_del(hash->next);
4534 + kfree(info->data);
4537 +static struct ipt_match connlimit_match = {
4538 + .name = "connlimit",
4540 + .checkentry = &check,
4541 + .destroy = &destroy,
4545 +static int __init init(void)
4547 + return ipt_register_match(&connlimit_match);
4550 +static void __exit fini(void)
4552 + ipt_unregister_match(&connlimit_match);
4557 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c
4558 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 00:00:00.000000000 +0000
4559 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c 2004-03-05 07:40:06.000000000 +0000
4561 +/* iptables match extension to limit the number of packets per second
4562 + * seperately for each destination.
4564 + * (C) 2003 by Harald Welte <laforge@netfilter.org>
4568 + * Development of this code was funded by Astaro AG, http://www.astaro.com/
4570 + * based on ipt_limit.c by:
4571 + * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
4572 + * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
4573 + * Rusty Russell <rusty@rustcorp.com.au>
4575 + * The general idea is to create a hash table for every dstip and have a
4576 + * seperate limit counter per tuple. This way you can do something like 'limit
4577 + * the number of syn packets for each of my internal addresses.
4579 + * Ideally this would just be implemented as a general 'hash' match, which would
4580 + * allow us to attach any iptables target to it's hash buckets. But this is
4581 + * not possible in the current iptables architecture. As always, pkttables for
4582 + * 2.7.x will help ;)
4584 +#include <linux/module.h>
4585 +#include <linux/skbuff.h>
4586 +#include <linux/spinlock.h>
4587 +#include <linux/random.h>
4588 +#include <linux/jhash.h>
4589 +#include <linux/slab.h>
4590 +#include <linux/vmalloc.h>
4591 +#include <linux/tcp.h>
4592 +#include <linux/udp.h>
4593 +#include <linux/proc_fs.h>
4594 +#include <linux/seq_file.h>
4596 +#define ASSERT_READ_LOCK(x)
4597 +#define ASSERT_WRITE_LOCK(x)
4598 +#include <linux/netfilter_ipv4/lockhelp.h>
4599 +#include <linux/netfilter_ipv4/listhelp.h>
4601 +#include <linux/netfilter_ipv4/ip_tables.h>
4602 +#include <linux/netfilter_ipv4/ipt_dstlimit.h>
4604 +/* FIXME: this is just for IP_NF_ASSERRT */
4605 +#include <linux/netfilter_ipv4/ip_conntrack.h>
4607 +#define MS2JIFFIES(x) ((x*HZ)/1000)
4609 +MODULE_LICENSE("GPL");
4610 +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
4611 +MODULE_DESCRIPTION("iptables match for limiting per destination");
4613 +/* need to declare this at the top */
4614 +static struct proc_dir_entry *dstlimit_procdir;
4615 +static struct file_operations dl_file_ops;
4617 +/* hash table crap */
4619 +struct dsthash_dst {
4625 +struct dsthash_ent {
4626 + /* static / read-only parts in the beginning */
4627 + struct list_head list;
4628 + struct dsthash_dst dst;
4630 + /* modified structure members in the end */
4631 + unsigned long expires; /* precalculated expiry time */
4633 + unsigned long prev; /* last modification */
4635 + u_int32_t credit_cap, cost;
4639 +struct ipt_dstlimit_htable {
4640 + struct list_head list; /* global list of all htables */
4643 + struct dstlimit_cfg cfg; /* config */
4645 + /* used internally */
4646 + spinlock_t lock; /* lock for list_head */
4647 + u_int32_t rnd; /* random seed for hash */
4648 + struct timer_list timer; /* timer for gc */
4649 + atomic_t count; /* number entries in table */
4651 + /* seq_file stuff */
4652 + struct proc_dir_entry *pde;
4654 + struct list_head hash[0]; /* hashtable itself */
4657 +DECLARE_RWLOCK(dstlimit_lock); /* protects htables list */
4658 +static LIST_HEAD(dstlimit_htables);
4659 +static kmem_cache_t *dstlimit_cachep;
4661 +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
4663 + return (ent->dst.dst_ip == b->dst_ip
4664 + && ent->dst.port == b->port
4665 + && ent->dst.src_ip == b->src_ip);
4668 +static inline u_int32_t
4669 +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
4671 + return (jhash_3words(dst->dst_ip, dst->port,
4672 + dst->src_ip, ht->rnd) % ht->cfg.size);
4675 +static inline struct dsthash_ent *
4676 +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
4678 + struct dsthash_ent *ent;
4679 + u_int32_t hash = hash_dst(ht, dst);
4680 + MUST_BE_LOCKED(&ht->lock);
4681 + ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
4685 +/* allocate dsthash_ent, initialize dst, put in htable and lock it */
4686 +static struct dsthash_ent *
4687 +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
4689 + struct dsthash_ent *ent;
4691 + /* initialize hash with random val at the time we allocate
4692 + * the first hashtable entry */
4694 + get_random_bytes(&ht->rnd, 4);
4696 + if (ht->cfg.max &&
4697 + atomic_read(&ht->count) >= ht->cfg.max) {
4698 + /* FIXME: do something. question is what.. */
4699 + if (net_ratelimit())
4700 + printk(KERN_WARNING
4701 + "ipt_dstlimit: max count of %u reached\n",
4706 + ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
4708 + if (net_ratelimit())
4710 + "ipt_dstlimit: can't allocate dsthash_ent\n");
4714 + atomic_inc(&ht->count);
4716 + ent->dst.dst_ip = dst->dst_ip;
4717 + ent->dst.port = dst->port;
4718 + ent->dst.src_ip = dst->src_ip;
4720 + list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
4726 +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
4728 + MUST_BE_LOCKED(&ht->lock);
4730 + list_del(&ent->list);
4731 + kmem_cache_free(dstlimit_cachep, ent);
4732 + atomic_dec(&ht->count);
4734 +static void htable_gc(unsigned long htlong);
4736 +static int htable_create(struct ipt_dstlimit_info *minfo)
4739 + unsigned int size;
4740 + struct ipt_dstlimit_htable *hinfo;
4742 + if (minfo->cfg.size)
4743 + size = minfo->cfg.size;
4745 + size = (((num_physpages << PAGE_SHIFT) / 16384)
4746 + / sizeof(struct list_head));
4747 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
4752 + /* FIXME: don't use vmalloc() here or anywhere else -HW */
4753 + hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
4754 + + (sizeof(struct list_head) * size));
4756 + printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
4759 + minfo->hinfo = hinfo;
4761 + /* copy match config into hashtable config */
4762 + memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
4763 + hinfo->cfg.size = size;
4764 + if (!hinfo->cfg.max)
4765 + hinfo->cfg.max = 8 * hinfo->cfg.size;
4766 + else if (hinfo->cfg.max < hinfo->cfg.size)
4767 + hinfo->cfg.max = hinfo->cfg.size;
4769 + for (i = 0; i < hinfo->cfg.size; i++)
4770 + INIT_LIST_HEAD(&hinfo->hash[i]);
4772 + atomic_set(&hinfo->count, 0);
4773 + atomic_set(&hinfo->use, 1);
4775 + hinfo->lock = SPIN_LOCK_UNLOCKED;
4776 + hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
4777 + if (!hinfo->pde) {
4781 + hinfo->pde->proc_fops = &dl_file_ops;
4782 + hinfo->pde->data = hinfo;
4784 + init_timer(&hinfo->timer);
4785 + hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
4786 + hinfo->timer.data = (unsigned long )hinfo;
4787 + hinfo->timer.function = htable_gc;
4788 + add_timer(&hinfo->timer);
4790 + WRITE_LOCK(&dstlimit_lock);
4791 + list_add(&hinfo->list, &dstlimit_htables);
4792 + WRITE_UNLOCK(&dstlimit_lock);
4797 +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
4802 +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
4804 + return (jiffies >= he->expires);
4807 +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
4808 + int (*select)(struct ipt_dstlimit_htable *ht,
4809 + struct dsthash_ent *he))
4813 + IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
4815 + /* lock hash table and iterate over it */
4816 + LOCK_BH(&ht->lock);
4817 + for (i = 0; i < ht->cfg.size; i++) {
4818 + struct dsthash_ent *dh, *n;
4819 + list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
4820 + if ((*select)(ht, dh))
4821 + __dsthash_free(ht, dh);
4824 + UNLOCK_BH(&ht->lock);
4827 +/* hash table garbage collector, run by timer */
4828 +static void htable_gc(unsigned long htlong)
4830 + struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
4832 + htable_selective_cleanup(ht, select_gc);
4834 + /* re-add the timer accordingly */
4835 + ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
4836 + add_timer(&ht->timer);
4839 +static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
4841 + /* remove timer, if it is pending */
4842 + if (timer_pending(&hinfo->timer))
4843 + del_timer(&hinfo->timer);
4845 + /* remove proc entry */
4846 + remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
4848 + htable_selective_cleanup(hinfo, select_all);
4852 +static struct ipt_dstlimit_htable *htable_find_get(char *name)
4854 + struct ipt_dstlimit_htable *hinfo;
4856 + READ_LOCK(&dstlimit_lock);
4857 + list_for_each_entry(hinfo, &dstlimit_htables, list) {
4858 + if (!strcmp(name, hinfo->pde->name)) {
4859 + atomic_inc(&hinfo->use);
4860 + READ_UNLOCK(&dstlimit_lock);
4864 + READ_UNLOCK(&dstlimit_lock);
4869 +static void htable_put(struct ipt_dstlimit_htable *hinfo)
4871 + if (atomic_dec_and_test(&hinfo->use)) {
4872 + WRITE_LOCK(&dstlimit_lock);
4873 + list_del(&hinfo->list);
4874 + WRITE_UNLOCK(&dstlimit_lock);
4875 + htable_destroy(hinfo);
4880 +/* The algorithm used is the Simple Token Bucket Filter (TBF)
4881 + * see net/sched/sch_tbf.c in the linux source tree
4884 +/* Rusty: This is my (non-mathematically-inclined) understanding of
4885 + this algorithm. The `average rate' in jiffies becomes your initial
4886 + amount of credit `credit' and the most credit you can ever have
4887 + `credit_cap'. The `peak rate' becomes the cost of passing the
4890 + `prev' tracks the last packet hit: you gain one credit per jiffy.
4891 + If you get credit balance more than this, the extra credit is
4892 + discarded. Every time the match passes, you lose `cost' credits;
4893 + if you don't have that many, the test fails.
4895 + See Alexey's formal explanation in net/sched/sch_tbf.c.
4897 + To get the maximum range, we multiply by this factor (ie. you get N
4898 + credits per jiffy). We want to allow a rate as low as 1 per day
4899 + (slowest userspace tool allows), which means
4900 + CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
4902 +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
4904 +/* Repeated shift and or gives us all 1s, final shift and add 1 gives
4905 + * us the power of 2 below the theoretical max, so GCC simply does a
4907 +#define _POW2_BELOW2(x) ((x)|((x)>>1))
4908 +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
4909 +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
4910 +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
4911 +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
4912 +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
4914 +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
4916 +/* Precision saver. */
4917 +static inline u_int32_t
4918 +user2credits(u_int32_t user)
4920 + /* If multiplying would overflow... */
4921 + if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
4922 + /* Divide first. */
4923 + return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
4925 + return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
4928 +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
4930 + dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now))
4931 + * CREDITS_PER_JIFFY;
4932 + if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
4933 + dh->rateinfo.credit = dh->rateinfo.credit_cap;
4937 +dstlimit_match(const struct sk_buff *skb,
4938 + const struct net_device *in,
4939 + const struct net_device *out,
4940 + const void *matchinfo,
4944 + struct ipt_dstlimit_info *r =
4945 + ((struct ipt_dstlimit_info *)matchinfo)->u.master;
4946 + struct ipt_dstlimit_htable *hinfo = r->hinfo;
4947 + unsigned long now = jiffies;
4948 + struct dsthash_ent *dh;
4949 + struct dsthash_dst dst;
4951 + memset(&dst, 0, sizeof(dst));
4953 + /* dest ip is always in hash */
4954 + dst.dst_ip = skb->nh.iph->daddr;
4956 + /* source ip only if respective hashmode, otherwise set to
4958 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
4959 + dst.src_ip = skb->nh.iph->saddr;
4961 + /* dest port only if respective mode */
4962 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
4965 + /* Must not be a fragment. */
4969 + /* Must be big enough to read ports (both UDP and TCP have
4970 + them at the start). */
4971 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
4972 + /* We've been asked to examine this packet, and we
4973 + can't. Hence, no choice but to drop. */
4978 + switch (skb->nh.iph->protocol) {
4979 + struct tcphdr *th;
4980 + struct udphdr *uh;
4982 + th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4983 + dst.port = th->dest;
4986 + uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4987 + dst.port = uh->dest;
4994 + LOCK_BH(&hinfo->lock);
4995 + dh = __dsthash_find(hinfo, &dst);
4997 + dh = __dsthash_alloc_init(hinfo, &dst);
5000 + /* enomem... don't match == DROP */
5001 + if (net_ratelimit())
5002 + printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
5003 + UNLOCK_BH(&hinfo->lock);
5007 + dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
5009 + dh->rateinfo.prev = jiffies;
5010 + dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
5011 + hinfo->cfg.burst);
5012 + dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
5013 + hinfo->cfg.burst);
5014 + dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
5016 + UNLOCK_BH(&hinfo->lock);
5020 + /* update expiration timeout */
5021 + dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
5023 + rateinfo_recalc(dh, now);
5024 + if (dh->rateinfo.credit >= dh->rateinfo.cost) {
5025 + /* We're underlimit. */
5026 + dh->rateinfo.credit -= dh->rateinfo.cost;
5027 + UNLOCK_BH(&hinfo->lock);
5031 + UNLOCK_BH(&hinfo->lock);
5033 + /* default case: we're overlimit, thus don't match */
5038 +dstlimit_checkentry(const char *tablename,
5039 + const struct ipt_ip *ip,
5041 + unsigned int matchsize,
5042 + unsigned int hook_mask)
5044 + struct ipt_dstlimit_info *r = matchinfo;
5046 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
5049 + /* Check for overflow. */
5050 + if (r->cfg.burst == 0
5051 + || user2credits(r->cfg.avg * r->cfg.burst) <
5052 + user2credits(r->cfg.avg)) {
5053 + printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
5054 + r->cfg.avg, r->cfg.burst);
5058 + if (r->cfg.mode == 0
5059 + || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
5060 + |IPT_DSTLIMIT_HASH_DIP
5061 + |IPT_DSTLIMIT_HASH_SIP))
5064 + if (!r->cfg.gc_interval)
5067 + if (!r->cfg.expire)
5070 + r->hinfo = htable_find_get(r->name);
5071 + if (!r->hinfo && (htable_create(r) != 0)) {
5075 + /* Ugly hack: For SMP, we only want to use one set */
5082 +dstlimit_destroy(void *matchinfo, unsigned int matchsize)
5084 + struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
5086 + htable_put(r->hinfo);
5089 +static struct ipt_match ipt_dstlimit = {
5090 + .list = { .prev = NULL, .next = NULL },
5091 + .name = "dstlimit",
5092 + .match = dstlimit_match,
5093 + .checkentry = dstlimit_checkentry,
5094 + .destroy = dstlimit_destroy,
5100 +static void *dl_seq_start(struct seq_file *s, loff_t *pos)
5102 + struct proc_dir_entry *pde = s->private;
5103 + struct ipt_dstlimit_htable *htable = pde->data;
5104 + unsigned int *bucket;
5106 + LOCK_BH(&htable->lock);
5107 + if (*pos >= htable->cfg.size)
5110 + bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
5112 + return ERR_PTR(-ENOMEM);
5118 +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
5120 + struct proc_dir_entry *pde = s->private;
5121 + struct ipt_dstlimit_htable *htable = pde->data;
5122 + unsigned int *bucket = (unsigned int *)v;
5124 + *pos = ++(*bucket);
5125 + if (*pos >= htable->cfg.size) {
5132 +static void dl_seq_stop(struct seq_file *s, void *v)
5134 + struct proc_dir_entry *pde = s->private;
5135 + struct ipt_dstlimit_htable *htable = pde->data;
5136 + unsigned int *bucket = (unsigned int *)v;
5140 + UNLOCK_BH(&htable->lock);
5143 +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
5145 + /* recalculate to show accurate numbers */
5146 + rateinfo_recalc(ent, jiffies);
5148 + return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
5149 + (ent->expires - jiffies)/HZ,
5150 + NIPQUAD(ent->dst.src_ip),
5151 + NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
5152 + ent->rateinfo.credit, ent->rateinfo.credit_cap,
5153 + ent->rateinfo.cost);
5156 +static int dl_seq_show(struct seq_file *s, void *v)
5158 + struct proc_dir_entry *pde = s->private;
5159 + struct ipt_dstlimit_htable *htable = pde->data;
5160 + unsigned int *bucket = (unsigned int *)v;
5162 + if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
5163 + struct dsthash_ent *, s)) {
5164 + /* buffer was filled and unable to print that tuple */
5170 +static struct seq_operations dl_seq_ops = {
5171 + .start = dl_seq_start,
5172 + .next = dl_seq_next,
5173 + .stop = dl_seq_stop,
5174 + .show = dl_seq_show
5177 +static int dl_proc_open(struct inode *inode, struct file *file)
5179 + int ret = seq_open(file, &dl_seq_ops);
5182 + struct seq_file *sf = file->private_data;
5183 + sf->private = PDE(inode);
5188 +static struct file_operations dl_file_ops = {
5189 + .owner = THIS_MODULE,
5190 + .open = dl_proc_open,
5192 + .llseek = seq_lseek,
5193 + .release = seq_release
5196 +static int init_or_fini(int fini)
5203 + if (ipt_register_match(&ipt_dstlimit)) {
5205 + goto cleanup_nothing;
5208 + /* FIXME: do we really want HWCACHE_ALIGN since our objects are
5209 + * quite small ? */
5210 + dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
5211 + sizeof(struct dsthash_ent), 0,
5212 + SLAB_HWCACHE_ALIGN, NULL, NULL);
5213 + if (!dstlimit_cachep) {
5214 + printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
5216 + goto cleanup_unreg_match;
5219 + dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
5220 + if (!dstlimit_procdir) {
5221 + printk(KERN_ERR "Unable to create proc dir entry\n");
5223 + goto cleanup_free_slab;
5229 + remove_proc_entry("ipt_dstlimit", proc_net);
5231 + kmem_cache_destroy(dstlimit_cachep);
5232 +cleanup_unreg_match:
5233 + ipt_unregister_match(&ipt_dstlimit);
5239 +static int __init init(void)
5241 + return init_or_fini(0);
5244 +static void __exit fini(void)
5251 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c
5252 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
5253 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c 2004-03-05 07:40:08.000000000 +0000
5256 + * This module implements a simple TSK FLC
5257 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
5258 + * to limit , in an adaptive and flexible way , the packet rate crossing
5259 + * a given stream . It serves as an initial and very simple (but effective)
5260 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
5261 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
5262 + * into our code in a precise , adaptive and efficient manner.
5263 + * The goal is very similar to that of "limit" match , but using techniques of
5264 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
5265 + * avoiding over and undershoots - and stuff like that .
5268 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
5269 + * 2002-08-17 : Changed to eliminate floating point operations .
5270 + * 2002-08-23 : Coding style changes .
5273 +#include <linux/module.h>
5274 +#include <linux/skbuff.h>
5275 +#include <linux/ip.h>
5276 +#include <linux/random.h>
5277 +#include <net/tcp.h>
5278 +#include <linux/spinlock.h>
5279 +#include <linux/netfilter_ipv4/ip_tables.h>
5280 +#include <linux/netfilter_ipv4/ipt_fuzzy.h>
5283 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
5284 + Expressed in percentage
5287 +#define PAR_LOW 1/100
5290 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
5292 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
5293 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
5294 +MODULE_LICENSE("GPL");
5296 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
5304 + return ( (100*(tx-mini)) / (maxi-mini) );
5307 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
5315 + return ( (100*( maxi - tx )) / ( maxi - mini ) );
5319 +ipt_fuzzy_match(const struct sk_buff *pskb,
5320 + const struct net_device *in,
5321 + const struct net_device *out,
5322 + const void *matchinfo,
5326 + /* From userspace */
5328 + struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
5330 + u_int8_t random_number;
5331 + unsigned long amount;
5332 + u_int8_t howhigh, howlow;
5335 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
5337 + info->bytes_total += pskb->len;
5338 + info->packets_total++;
5340 + info->present_time = jiffies;
5342 + if (info->present_time >= info->previous_time)
5343 + amount = info->present_time - info->previous_time;
5345 + /* There was a transition : I choose to re-sample
5346 + and keep the old acceptance rate...
5350 + info->previous_time = info->present_time;
5351 + info->bytes_total = info->packets_total = 0;
5354 + if (amount > HZ/10) /* More than 100 ms elapsed ... */
5357 + info->mean_rate = (u_int32_t) ((HZ*info->packets_total) \
5360 + info->previous_time = info->present_time;
5361 + info->bytes_total = info->packets_total = 0;
5363 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
5364 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
5366 + info->acceptance_rate = (u_int8_t) \
5367 + (howhigh*PAR_LOW + PAR_HIGH*howlow);
5369 + /* In fact , the above defuzzification would require a denominator
5370 + proportional to (howhigh+howlow) but , in this particular case ,
5371 + that expression is constant .
5372 + An imediate consequence is that it isn't necessary to call
5373 + both mf_high and mf_low - but to keep things understandable ,
5378 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
5381 + if ( info->acceptance_rate < 100 )
5383 + get_random_bytes((void *)(&random_number), 1);
5385 + /* If within the acceptance , it can pass => don't match */
5386 + if (random_number <= (255 * info->acceptance_rate) / 100)
5389 + return 1; /* It can't pass ( It matches ) */
5392 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
5397 +ipt_fuzzy_checkentry(const char *tablename,
5398 + const struct ipt_ip *e,
5400 + unsigned int matchsize,
5401 + unsigned int hook_mask)
5404 + const struct ipt_fuzzy_info *info = matchinfo;
5406 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
5407 + printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
5408 + IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
5412 + if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
5413 + || (info->minimum_rate >= info->maximum_rate )) {
5414 + printk("ipt_fuzzy: BAD limits , please verify !!!\n");
5421 +static struct ipt_match ipt_fuzzy_reg = {
5423 + .match = ipt_fuzzy_match,
5424 + .checkentry = ipt_fuzzy_checkentry,
5428 +static int __init init(void)
5430 + return ipt_register_match(&ipt_fuzzy_reg);
5433 +static void __exit fini(void)
5435 + ipt_unregister_match(&ipt_fuzzy_reg);
5440 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c
5441 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c 1970-01-01 00:00:00.000000000 +0000
5442 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c 2004-03-05 07:40:09.000000000 +0000
5445 + This is a module which is used to match ipv4 options.
5446 + This file is distributed under the terms of the GNU General Public
5447 + License (GPL). Copies of the GPL can be obtained from:
5448 + ftp://prep.ai.mit.edu/pub/gnu/GPL
5450 + 11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
5451 + 12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
5452 + 12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
5453 + 18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
5454 + 19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
5457 +#include <linux/module.h>
5458 +#include <linux/skbuff.h>
5459 +#include <net/ip.h>
5461 +#include <linux/netfilter_ipv4/ip_tables.h>
5462 +#include <linux/netfilter_ipv4/ipt_ipv4options.h>
5464 +MODULE_LICENSE("GPL");
5465 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
5468 +match(const struct sk_buff *skb,
5469 + const struct net_device *in,
5470 + const struct net_device *out,
5471 + const void *matchinfo,
5475 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
5476 + const struct iphdr *iph = skb->nh.iph;
5477 + const struct ip_options *opt;
5479 + if (iph->ihl * 4 == sizeof(struct iphdr)) {
5480 + /* No options, so we match only the "DONTs" and the "IGNOREs" */
5482 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
5483 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
5484 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
5485 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
5486 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
5487 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
5492 + if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
5493 + /* there are options, and we don't need to care which one */
5496 + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
5497 + /* there are options but we don't want any ! */
5502 + opt = &(IPCB(skb)->opt);
5504 + /* source routing */
5505 + if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
5506 + if (!((opt->srr) & (opt->is_strictroute)))
5509 + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
5510 + if (!((opt->srr) & (!opt->is_strictroute)))
5513 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
5517 + /* record route */
5518 + if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
5522 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
5527 + if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
5531 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
5535 + /* router-alert option */
5536 + if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
5537 + if (!opt->router_alert)
5540 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
5541 + if (opt->router_alert)
5550 +checkentry(const char *tablename,
5551 + const struct ipt_ip *ip,
5553 + unsigned int matchsize,
5554 + unsigned int hook_mask)
5556 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
5557 + /* Check the size */
5558 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
5560 + /* Now check the coherence of the data ... */
5561 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
5562 + (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
5563 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
5564 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
5565 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
5566 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
5567 + return 0; /* opposites */
5568 + if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
5569 + (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
5570 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
5571 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
5572 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
5573 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
5574 + ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
5575 + return 0; /* opposites */
5576 + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
5577 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
5578 + return 0; /* cannot match in the same time loose and strict source routing */
5579 + if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
5580 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
5581 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
5582 + return 0; /* opposites */
5583 + if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
5584 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
5585 + return 0; /* opposites */
5586 + if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
5587 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
5588 + return 0; /* opposites */
5589 + if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
5590 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
5591 + return 0; /* opposites */
5593 + /* everything looks ok. */
5597 +static struct ipt_match ipv4options_match = {
5598 + .name = "ipv4options",
5600 + .checkentry = checkentry,
5604 +static int __init init(void)
5606 + return ipt_register_match(&ipv4options_match);
5609 +static void __exit fini(void)
5611 + ipt_unregister_match(&ipv4options_match);
5616 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c
5617 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 00:00:00.000000000 +0000
5618 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c 2004-03-05 07:40:11.000000000 +0000
5620 +/* Kernel module to match one of a list of TCP/UDP ports: ports are in
5621 + the same place so we can treat them as equal. */
5622 +#include <linux/module.h>
5623 +#include <linux/types.h>
5624 +#include <linux/udp.h>
5625 +#include <linux/skbuff.h>
5627 +#include <linux/netfilter_ipv4/ipt_mport.h>
5628 +#include <linux/netfilter_ipv4/ip_tables.h>
5630 +MODULE_LICENSE("GPL");
5633 +#define duprintf(format, args...) printk(format , ## args)
5635 +#define duprintf(format, args...)
5638 +/* Returns 1 if the port is matched by the test, 0 otherwise. */
5640 +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
5644 + u_int16_t pflags = minfo->pflags;
5645 + for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
5649 + && minfo->ports[i] == 65535)
5652 + s = minfo->ports[i];
5655 + e = minfo->ports[++i];
5660 + if (minfo->flags & IPT_MPORT_SOURCE
5661 + && src >= s && src <= e)
5664 + if (minfo->flags & IPT_MPORT_DESTINATION
5665 + && dst >= s && dst <= e)
5673 +match(const struct sk_buff *skb,
5674 + const struct net_device *in,
5675 + const struct net_device *out,
5676 + const void *matchinfo,
5681 + const struct ipt_mport *minfo = matchinfo;
5686 + /* Must be big enough to read ports (both UDP and TCP have
5687 + them at the start). */
5688 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
5689 + /* We've been asked to examine this packet, and we
5690 + can't. Hence, no choice but to drop. */
5691 + duprintf("ipt_multiport:"
5692 + " Dropping evil offset=0 tinygram.\n");
5697 + return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
5700 +/* Called when user tries to insert an entry of this type. */
5702 +checkentry(const char *tablename,
5703 + const struct ipt_ip *ip,
5705 + unsigned int matchsize,
5706 + unsigned int hook_mask)
5708 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
5711 + /* Must specify proto == TCP/UDP, no unknown flags or bad count */
5712 + return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
5713 + && !(ip->invflags & IPT_INV_PROTO)
5714 + && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
5717 +static struct ipt_match mport_match = {
5720 + .checkentry = &checkentry,
5724 +static int __init init(void)
5726 + return ipt_register_match(&mport_match);
5729 +static void __exit fini(void)
5731 + ipt_unregister_match(&mport_match);
5736 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c
5737 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 00:00:00.000000000 +0000
5738 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c 2004-03-05 07:40:13.000000000 +0000
5741 + This is a module which is used for match support for every Nth packet
5742 + This file is distributed under the terms of the GNU General Public
5743 + License (GPL). Copies of the GPL can be obtained from:
5744 + ftp://prep.ai.mit.edu/pub/gnu/GPL
5746 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
5747 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
5748 + * added support for multiple counters
5749 + * added support for matching on individual packets
5750 + in the counter cycle
5751 + 2004-02-19 Harald Welte <laforge@netfilter.org>
5756 +#include <linux/module.h>
5757 +#include <linux/skbuff.h>
5758 +#include <linux/ip.h>
5759 +#include <net/tcp.h>
5760 +#include <linux/spinlock.h>
5761 +#include <linux/netfilter_ipv4/ip_tables.h>
5762 +#include <linux/netfilter_ipv4/ipt_nth.h>
5764 +MODULE_LICENSE("GPL");
5765 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
5768 + * State information.
5775 +static struct state states[IPT_NTH_NUM_COUNTERS];
5778 +ipt_nth_match(const struct sk_buff *pskb,
5779 + const struct net_device *in,
5780 + const struct net_device *out,
5781 + const void *matchinfo,
5785 + /* Parameters from userspace */
5786 + const struct ipt_nth_info *info = matchinfo;
5787 + unsigned counter = info->counter;
5788 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
5790 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
5794 + spin_lock(&states[counter].lock);
5796 + /* Are we matching every nth packet?*/
5797 + if (info->packet == 0xFF)
5799 + /* We're matching every nth packet and only every nth packet*/
5800 + /* Do we match or invert match? */
5801 + if (info->not == 0)
5803 + if (states[counter].number == 0)
5805 + ++states[counter].number;
5808 + if (states[counter].number >= info->every)
5809 + states[counter].number = 0; /* reset the counter */
5811 + ++states[counter].number;
5816 + if (states[counter].number == 0)
5818 + ++states[counter].number;
5821 + if (states[counter].number >= info->every)
5822 + states[counter].number = 0;
5824 + ++states[counter].number;
5830 + /* We're using the --packet, so there must be a rule for every value */
5831 + if (states[counter].number == info->packet)
5833 + /* only increment the counter when a match happens */
5834 + if (states[counter].number >= info->every)
5835 + states[counter].number = 0; /* reset the counter */
5837 + ++states[counter].number;
5846 + spin_unlock(&states[counter].lock);
5850 + spin_unlock(&states[counter].lock);
5855 +ipt_nth_checkentry(const char *tablename,
5856 + const struct ipt_ip *e,
5858 + unsigned int matchsize,
5859 + unsigned int hook_mask)
5861 + /* Parameters from userspace */
5862 + const struct ipt_nth_info *info = matchinfo;
5863 + unsigned counter = info->counter;
5864 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
5866 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
5870 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
5871 + printk("nth: matchsize %u != %u\n", matchsize,
5872 + IPT_ALIGN(sizeof(struct ipt_nth_info)));
5876 + states[counter].number = info->startat;
5881 +static struct ipt_match ipt_nth_reg = {
5883 + .match = ipt_nth_match,
5884 + .checkentry = ipt_nth_checkentry,
5888 +static int __init init(void)
5892 + memset(&states, 0, sizeof(states));
5893 + for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++)
5894 + spin_lock_init(&(states[counter].lock));
5896 + return ipt_register_match(&ipt_nth_reg);
5899 +static void __exit fini(void)
5901 + ipt_unregister_match(&ipt_nth_reg);
5906 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c
5907 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 00:00:00.000000000 +0000
5908 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c 2004-03-05 07:40:14.000000000 +0000
5911 + * netfilter module to enforce network quotas
5913 + * Sam Johnston <samj@samj.net>
5915 +#include <linux/module.h>
5916 +#include <linux/skbuff.h>
5917 +#include <linux/spinlock.h>
5918 +#include <linux/interrupt.h>
5920 +#include <linux/netfilter_ipv4/ip_tables.h>
5921 +#include <linux/netfilter_ipv4/ipt_quota.h>
5923 +MODULE_LICENSE("GPL");
5924 +MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
5926 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
5929 +match(const struct sk_buff *skb,
5930 + const struct net_device *in,
5931 + const struct net_device *out,
5932 + const void *matchinfo,
5933 + int offset, int *hotdrop)
5935 + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
5936 + unsigned int datalen;
5938 + if (skb->len < sizeof(struct iphdr))
5941 + datalen = skb->len - skb->nh.iph->ihl*4;
5943 + spin_lock_bh("a_lock);
5945 + if (q->quota >= datalen) {
5946 + /* we can afford this one */
5947 + q->quota -= datalen;
5948 + spin_unlock_bh("a_lock);
5950 +#ifdef DEBUG_IPT_QUOTA
5951 + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
5956 + /* so we do not allow even small packets from now on */
5959 +#ifdef DEBUG_IPT_QUOTA
5960 + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
5963 + spin_unlock_bh("a_lock);
5968 +checkentry(const char *tablename,
5969 + const struct ipt_ip *ip,
5970 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
5972 + /* TODO: spinlocks? sanity checks? */
5973 + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
5979 +static struct ipt_match quota_match = {
5982 + .checkentry = checkentry,
5989 + return ipt_register_match("a_match);
5995 + ipt_unregister_match("a_match);
6001 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c
6002 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 00:00:00.000000000 +0000
6003 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c 2004-03-05 07:40:22.000000000 +0000
6005 +/* Kernel module to match realm from routing. */
6006 +#include <linux/module.h>
6007 +#include <linux/skbuff.h>
6008 +#include <linux/netdevice.h>
6009 +#include <net/route.h>
6011 +#include <linux/netfilter_ipv4/ipt_realm.h>
6012 +#include <linux/netfilter_ipv4/ip_tables.h>
6014 +MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
6015 +MODULE_LICENSE("GPL");
6018 +match(const struct sk_buff *skb,
6019 + const struct net_device *in,
6020 + const struct net_device *out,
6021 + const void *matchinfo,
6025 + const struct ipt_realm_info *info = matchinfo;
6026 + struct dst_entry *dst = skb->dst;
6031 + id = dst->tclassid;
6033 + return (info->id == (id & info->mask)) ^ info->invert;
6036 +static int check(const char *tablename,
6037 + const struct ipt_ip *ip,
6039 + unsigned int matchsize,
6040 + unsigned int hook_mask)
6043 + & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
6044 + (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
6045 + printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
6046 + "LOCAL_IN or FORWARD.\n");
6050 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
6056 +static struct ipt_match realm_match = {
6059 + .checkentry = check,
6063 +static int __init init(void)
6065 + return ipt_register_match(&realm_match);
6068 +static void __exit fini(void)
6070 + ipt_unregister_match(&realm_match);
6075 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c
6076 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 00:00:00.000000000 +0000
6077 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c 2004-03-05 07:40:24.000000000 +0000
6079 +#include <linux/module.h>
6080 +#include <linux/skbuff.h>
6081 +#include <net/ip.h>
6082 +#include <linux/sctp.h>
6084 +#include <linux/netfilter_ipv4/ip_tables.h>
6085 +#include <linux/netfilter_ipv4/ipt_sctp.h>
6088 +#define duprintf(format, args...) printk(format , ## args)
6090 +#define duprintf(format, args...)
6093 +#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
6094 + || (!!((invflag) & (option)) ^ (cond)))
6097 +match_flags(const struct ipt_sctp_flag_info *flag_info,
6098 + const int flag_count,
6099 + u_int8_t chunktype,
6100 + u_int8_t chunkflags)
6104 + for (i = 0; i < flag_count; i++) {
6105 + if (flag_info[i].chunktype == chunktype) {
6106 + return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
6114 +match_packet(const struct sk_buff *skb,
6115 + const u_int32_t *chunkmap,
6116 + int chunk_match_type,
6117 + const struct ipt_sctp_flag_info *flag_info,
6118 + const int flag_count,
6122 + u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
6123 + sctp_chunkhdr_t sch;
6125 + if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
6126 + SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
6129 + offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
6131 + if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
6132 + duprintf("Dropping invalid SCTP packet.\n");
6137 +// ERROR needed fix !!!!!!
6138 +// duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
6139 +// ++i, offset, sch.type, htons(sch.length), sch.flags);
6141 + offset += (htons(sch.length) + 3) & ~3;
6143 + duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
6145 + if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
6146 + switch (chunk_match_type) {
6147 + case SCTP_CHUNK_MATCH_ANY:
6148 + if (match_flags(flag_info, flag_count,
6149 + sch.type, sch.flags)) {
6154 + case SCTP_CHUNK_MATCH_ALL:
6155 + if (match_flags(flag_info, flag_count,
6156 + sch.type, sch.flags)) {
6157 + SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
6161 + case SCTP_CHUNK_MATCH_ONLY:
6162 + if (!match_flags(flag_info, flag_count,
6163 + sch.type, sch.flags)) {
6169 + switch (chunk_match_type) {
6170 + case SCTP_CHUNK_MATCH_ONLY:
6174 + } while (offset < skb->len);
6176 + switch (chunk_match_type) {
6177 + case SCTP_CHUNK_MATCH_ALL:
6178 + return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
6179 + case SCTP_CHUNK_MATCH_ANY:
6181 + case SCTP_CHUNK_MATCH_ONLY:
6185 + /* This will never be reached, but required to stop compiler whine */
6190 +match(const struct sk_buff *skb,
6191 + const struct net_device *in,
6192 + const struct net_device *out,
6193 + const void *matchinfo,
6197 + const struct ipt_sctp_info *info;
6198 + sctp_sctphdr_t sh;
6200 + info = (const struct ipt_sctp_info *)matchinfo;
6203 + duprintf("Dropping non-first fragment.. FIXME\n");
6207 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
6208 + duprintf("Dropping evil TCP offset=0 tinygram.\n");
6212 + duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
6214 + return SCCHECK(((ntohs(sh.source) >= info->spts[0])
6215 + && (ntohs(sh.source) <= info->spts[1])),
6216 + IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
6217 + && SCCHECK(((ntohs(sh.dest) >= info->dpts[0])
6218 + && (ntohs(sh.dest) <= info->dpts[1])),
6219 + IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
6220 + && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
6221 + info->flag_info, info->flag_count,
6223 + IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
6227 +checkentry(const char *tablename,
6228 + const struct ipt_ip *ip,
6230 + unsigned int matchsize,
6231 + unsigned int hook_mask)
6233 + const struct ipt_sctp_info *info;
6235 + info = (const struct ipt_sctp_info *)matchinfo;
6237 + return ip->proto == IPPROTO_SCTP
6238 + && !(ip->invflags & IPT_INV_PROTO)
6239 + && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
6240 + && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
6241 + && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
6242 + && !(info->invflags & ~info->flags)
6243 + && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) ||
6244 + (info->chunk_match_type &
6245 + (SCTP_CHUNK_MATCH_ALL
6246 + | SCTP_CHUNK_MATCH_ANY
6247 + | SCTP_CHUNK_MATCH_ONLY)));
6250 +static struct ipt_match sctp_match =
6252 + .list = { NULL, NULL},
6255 + .checkentry = &checkentry,
6260 +static int __init init(void)
6262 + return ipt_register_match(&sctp_match);
6265 +static void __exit fini(void)
6267 + ipt_unregister_match(&sctp_match);
6273 +MODULE_LICENSE("GPL");
6274 +MODULE_AUTHOR("Kiran Kumar Immidi");
6275 +MODULE_DESCRIPTION("Match for SCTP protocol packets");
6277 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig
6278 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig 2004-03-04 06:17:03.000000000 +0000
6279 +++ linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig 2004-03-05 07:40:13.000000000 +0000
6280 @@ -218,5 +218,25 @@
6281 To compile it as a module, choose M here. If unsure, say N.
6283 #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
6284 +config IP6_NF_TARGET_HOPLIMIT
6285 + tristate 'HOPLIMIT target support'
6286 + depends on IP6_NF_MANGLE
6289 +config IP6_NF_TARGET_REJECT
6290 + tristate 'REJECT target support'
6291 + depends on IP6_NF_FILTER
6294 +config IP6_NF_MATCH_FUZZY
6295 + tristate 'Fuzzy match support'
6296 + depends on IP6_NF_FILTER
6299 +config IP6_NF_MATCH_NTH
6300 + tristate 'Nth match support'
6301 + depends on IP6_NF_IPTABLES
6306 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile linux-2.6.4-rc2/net/ipv6/netfilter/Makefile
6307 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile 2004-03-04 06:16:48.000000000 +0000
6308 +++ linux-2.6.4-rc2/net/ipv6/netfilter/Makefile 2004-03-05 07:40:13.000000000 +0000
6310 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
6311 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
6312 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
6313 +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
6314 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
6315 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
6316 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
6318 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
6319 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
6320 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
6321 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
6322 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
6323 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
6325 +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
6326 +obj-$(CONFIG_IP6_NF_TARGET_HOPLIMIT) += ip6t_HL.o
6327 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
6328 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c
6329 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c 1970-01-01 00:00:00.000000000 +0000
6330 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c 2004-03-05 07:39:53.000000000 +0000
6333 + * Hop Limit modification target for ip6tables
6334 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
6335 + * Based on HW's TTL module
6337 + * This software is distributed under the terms of GNU GPL
6340 +#include <linux/module.h>
6341 +#include <linux/skbuff.h>
6342 +#include <linux/ip.h>
6344 +#include <linux/netfilter_ipv6/ip6_tables.h>
6345 +#include <linux/netfilter_ipv6/ip6t_HL.h>
6347 +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
6348 +MODULE_DESCRIPTION("IP tables Hop Limit modification module");
6349 +MODULE_LICENSE("GPL");
6351 +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
6352 + const struct net_device *in, const struct net_device *out,
6353 + const void *targinfo, void *userinfo)
6355 + struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
6356 + const struct ip6t_HOPLIMIT_info *info = targinfo;
6357 + u_int16_t diffs[2];
6360 + switch (info->mode) {
6361 + case IP6T_HOPLIMIT_SET:
6362 + new_hl = info->hop_limit;
6364 + case IP6T_HOPLIMIT_INC:
6365 + new_hl = ip6h->hop_limit + info->hop_limit;
6369 + case IP6T_HOPLIMIT_DEC:
6370 + new_hl = ip6h->hop_limit + info->hop_limit;
6375 + new_hl = ip6h->hop_limit;
6379 + if (new_hl != ip6h->hop_limit) {
6380 + diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
6381 + ip6h->hop_limit = new_hl;
6382 + diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
6385 + return IP6T_CONTINUE;
6388 +static int ip6t_hl_checkentry(const char *tablename,
6389 + const struct ip6t_entry *e,
6391 + unsigned int targinfosize,
6392 + unsigned int hook_mask)
6394 + struct ip6t_HOPLIMIT_info *info = targinfo;
6396 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HOPLIMIT_info))) {
6397 + printk(KERN_WARNING "HOPLIMIT: targinfosize %u != %Zu\n",
6399 + IP6T_ALIGN(sizeof(struct ip6t_HOPLIMIT_info)));
6403 + if (strcmp(tablename, "mangle")) {
6404 + printk(KERN_WARNING "HOPLIMIT: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
6408 + if (info->mode > IP6T_HOPLIMIT_MAXMODE) {
6409 + printk(KERN_WARNING "HOPLIMIT: invalid or unknown Mode %u\n",
6414 + if ((info->mode != IP6T_HOPLIMIT_SET) && (info->hop_limit == 0)) {
6415 + printk(KERN_WARNING "HOPLIMIT: increment/decrement doesn't make sense with value 0\n");
6422 +static struct ip6t_target ip6t_HOPLIMIT = { { NULL, NULL }, "HL",
6423 + ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
6425 +static int __init init(void)
6427 + return ip6t_register_target(&ip6t_HOPLIMIT);
6430 +static void __exit fini(void)
6432 + ip6t_unregister_target(&ip6t_HOPLIMIT);
6437 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c
6438 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 00:00:00.000000000 +0000
6439 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c 2004-03-05 07:39:59.000000000 +0000
6442 + * This is a module which is used for rejecting packets.
6443 + * Added support for customized reject packets (Jozsef Kadlecsik).
6445 + * Port to IPv6 / ip6tables (Harald Welte <laforge@gnumonks.org>)
6447 +#include <linux/config.h>
6448 +#include <linux/module.h>
6449 +#include <linux/skbuff.h>
6450 +#include <linux/icmpv6.h>
6451 +#include <net/tcp.h>
6452 +#include <linux/netfilter_ipv6/ip6_tables.h>
6453 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
6456 +#define DEBUGP printk
6458 +#define DEBUGP(format, args...)
6462 +/* Send RST reply */
6463 +static void send_reset(struct sk_buff *oldskb)
6465 + struct sk_buff *nskb;
6466 + struct tcphdr *otcph, *tcph;
6467 + struct rtable *rt;
6468 + unsigned int otcplen;
6471 + /* IP header checks: fragment, too short. */
6472 + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
6473 + || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
6476 + otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
6477 + otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
6479 + /* No RST for RST. */
6483 + /* Check checksum. */
6484 + if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
6485 + oldskb->nh.iph->daddr,
6486 + csum_partial((char *)otcph, otcplen, 0)) != 0)
6489 + /* Copy skb (even if skb is about to be dropped, we can't just
6490 + clone it because there may be other things, such as tcpdump,
6491 + interested in it) */
6492 + nskb = skb_copy(oldskb, GFP_ATOMIC);
6496 + /* This packet will not be the same as the other: clear nf fields */
6497 + nf_conntrack_put(nskb->nfct);
6498 + nskb->nfct = NULL;
6499 + nskb->nfcache = 0;
6500 +#ifdef CONFIG_NETFILTER_DEBUG
6501 + nskb->nf_debug = 0;
6504 + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
6506 + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
6507 + tcph->source = xchg(&tcph->dest, tcph->source);
6509 + /* Truncate to length (no data) */
6510 + tcph->doff = sizeof(struct tcphdr)/4;
6511 + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
6512 + nskb->nh.iph->tot_len = htons(nskb->len);
6516 + tcph->seq = otcph->ack_seq;
6517 + tcph->ack_seq = 0;
6520 + tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
6521 + + otcplen - (otcph->doff<<2));
6526 + ((u_int8_t *)tcph)[13] = 0;
6528 + tcph->ack = needs_ack;
6531 + tcph->urg_ptr = 0;
6533 + /* Adjust TCP checksum */
6535 + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
6536 + nskb->nh.iph->saddr,
6537 + nskb->nh.iph->daddr,
6538 + csum_partial((char *)tcph,
6539 + sizeof(struct tcphdr), 0));
6541 + /* Adjust IP TTL, DF */
6542 + nskb->nh.iph->ttl = MAXTTL;
6543 + /* Set DF, id = 0 */
6544 + nskb->nh.iph->frag_off = htons(IP_DF);
6545 + nskb->nh.iph->id = 0;
6547 + /* Adjust IP checksum */
6548 + nskb->nh.iph->check = 0;
6549 + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
6550 + nskb->nh.iph->ihl);
6553 + if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
6554 + RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
6558 + dst_release(nskb->dst);
6559 + nskb->dst = &rt->u.dst;
6561 + /* "Never happens" */
6562 + if (nskb->len > nskb->dst->pmtu)
6565 + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
6566 + ip_finish_output);
6574 +static unsigned int reject6_target(struct sk_buff **pskb,
6575 + unsigned int hooknum,
6576 + const struct net_device *in,
6577 + const struct net_device *out,
6578 + const void *targinfo,
6581 + const struct ip6t_reject_info *reject = targinfo;
6583 + /* WARNING: This code causes reentry within ip6tables.
6584 + This means that the ip6tables jump stack is now crap. We
6585 + must return an absolute verdict. --RR */
6586 + DEBUGP("REJECTv6: calling icmpv6_send\n");
6587 + switch (reject->with) {
6588 + case IP6T_ICMP6_NO_ROUTE:
6589 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out);
6591 + case IP6T_ICMP6_ADM_PROHIBITED:
6592 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out);
6594 + case IP6T_ICMP6_NOT_NEIGHBOUR:
6595 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out);
6597 + case IP6T_ICMP6_ADDR_UNREACH:
6598 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out);
6600 + case IP6T_ICMP6_PORT_UNREACH:
6601 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out);
6604 + case IPT_ICMP_ECHOREPLY: {
6605 + struct icmp6hdr *icmph = (struct icmphdr *)
6606 + ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
6607 + unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
6609 + /* Not non-head frags, or truncated */
6610 + if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0)
6611 + && datalen >= 4) {
6612 + /* Usually I don't like cut & pasting code,
6613 + but dammit, my party is starting in 45
6615 + struct icmp_bxm icmp_param;
6617 + icmp_param.icmph=*icmph;
6618 + icmp_param.icmph.type=ICMP_ECHOREPLY;
6619 + icmp_param.data_ptr=(icmph+1);
6620 + icmp_param.data_len=datalen;
6621 + icmp_reply(&icmp_param, *pskb);
6625 + case IPT_TCP_RESET:
6626 + send_reset(*pskb);
6630 + printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with);
6637 +static inline int find_ping_match(const struct ip6t_entry_match *m)
6639 + const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data;
6641 + if (strcmp(m->u.kernel.match->name, "icmp6") == 0
6642 + && icmpinfo->type == ICMPV6_ECHO_REQUEST
6643 + && !(icmpinfo->invflags & IP6T_ICMP_INV))
6649 +static int check(const char *tablename,
6650 + const struct ip6t_entry *e,
6652 + unsigned int targinfosize,
6653 + unsigned int hook_mask)
6655 + const struct ip6t_reject_info *rejinfo = targinfo;
6657 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
6658 + DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize);
6662 + /* Only allow these for packet filtering. */
6663 + if (strcmp(tablename, "filter") != 0) {
6664 + DEBUGP("REJECTv6: bad table `%s'.\n", tablename);
6667 + if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
6668 + | (1 << NF_IP6_FORWARD)
6669 + | (1 << NF_IP6_LOCAL_OUT))) != 0) {
6670 + DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask);
6674 + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
6675 + /* Must specify that it's an ICMP ping packet. */
6676 + if (e->ipv6.proto != IPPROTO_ICMPV6
6677 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
6678 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n");
6681 + /* Must contain ICMP match. */
6682 + if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) {
6683 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n");
6686 + } else if (rejinfo->with == IP6T_TCP_RESET) {
6687 + /* Must specify that it's a TCP packet */
6688 + if (e->ipv6.proto != IPPROTO_TCP
6689 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
6690 + DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n");
6698 +static struct ip6t_target ip6t_reject_reg
6699 += { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE };
6701 +static int __init init(void)
6703 + if (ip6t_register_target(&ip6t_reject_reg))
6708 +static void __exit fini(void)
6710 + ip6t_unregister_target(&ip6t_reject_reg);
6715 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c
6716 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
6717 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c 2004-03-05 07:40:08.000000000 +0000
6720 + * This module implements a simple TSK FLC
6721 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
6722 + * to limit , in an adaptive and flexible way , the packet rate crossing
6723 + * a given stream . It serves as an initial and very simple (but effective)
6724 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
6725 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
6726 + * into our code in a precise , adaptive and efficient manner.
6727 + * The goal is very similar to that of "limit" match , but using techniques of
6728 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
6729 + * avoiding over and undershoots - and stuff like that .
6732 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
6733 + * 2002-08-17 : Changed to eliminate floating point operations .
6734 + * 2002-08-23 : Coding style changes .
6735 + * 2003-04-08 Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
6738 +#include <linux/module.h>
6739 +#include <linux/skbuff.h>
6740 +#include <linux/ipv6.h>
6741 +#include <linux/random.h>
6742 +#include <net/tcp.h>
6743 +#include <linux/spinlock.h>
6744 +#include <linux/netfilter_ipv6/ip6_tables.h>
6745 +#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
6748 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
6749 + Expressed in percentage
6752 +#define PAR_LOW 1/100
6755 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
6757 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
6758 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
6759 +MODULE_LICENSE("GPL");
6761 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
6763 + if (tx >= maxi) return 100;
6765 + if (tx <= mini) return 0;
6767 + return ((100 * (tx-mini)) / (maxi-mini));
6770 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
6772 + if (tx <= mini) return 100;
6774 + if (tx >= maxi) return 0;
6776 + return ((100 * (maxi - tx)) / (maxi - mini));
6781 +ip6t_fuzzy_match(const struct sk_buff *pskb,
6782 + const struct net_device *in,
6783 + const struct net_device *out,
6784 + const void *matchinfo,
6787 + u_int16_t datalen,
6790 + /* From userspace */
6792 + struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
6794 + u_int8_t random_number;
6795 + unsigned long amount;
6796 + u_int8_t howhigh, howlow;
6799 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
6801 + info->bytes_total += pskb->len;
6802 + info->packets_total++;
6804 + info->present_time = jiffies;
6806 + if (info->present_time >= info->previous_time)
6807 + amount = info->present_time - info->previous_time;
6809 + /* There was a transition : I choose to re-sample
6810 + and keep the old acceptance rate...
6814 + info->previous_time = info->present_time;
6815 + info->bytes_total = info->packets_total = 0;
6818 + if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
6820 + info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
6823 + info->previous_time = info->present_time;
6824 + info->bytes_total = info->packets_total = 0;
6826 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
6827 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
6829 + info->acceptance_rate = (u_int8_t) \
6830 + (howhigh * PAR_LOW + PAR_HIGH * howlow);
6832 + /* In fact, the above defuzzification would require a denominator
6833 + * proportional to (howhigh+howlow) but, in this particular case,
6834 + * that expression is constant.
6835 + * An imediate consequence is that it is not necessary to call
6836 + * both mf_high and mf_low - but to keep things understandable,
6842 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
6845 + if (info->acceptance_rate < 100)
6847 + get_random_bytes((void *)(&random_number), 1);
6849 + /* If within the acceptance , it can pass => don't match */
6850 + if (random_number <= (255 * info->acceptance_rate) / 100)
6853 + return 1; /* It can't pass (It matches) */
6856 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
6861 +ip6t_fuzzy_checkentry(const char *tablename,
6862 + const struct ip6t_ip6 *ip,
6864 + unsigned int matchsize,
6865 + unsigned int hook_mask)
6868 + const struct ip6t_fuzzy_info *info = matchinfo;
6870 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
6871 + printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
6872 + IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
6876 + if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
6877 + || (info->minimum_rate >= info->maximum_rate)) {
6878 + printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
6885 +static struct ip6t_match ip6t_fuzzy_reg = {
6889 + ip6t_fuzzy_checkentry,
6893 +static int __init init(void)
6895 + if (ip6t_register_match(&ip6t_fuzzy_reg))
6901 +static void __exit fini(void)
6903 + ip6t_unregister_match(&ip6t_fuzzy_reg);
6908 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c
6909 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 00:00:00.000000000 +0000
6910 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c 2004-03-05 07:40:13.000000000 +0000
6913 + This is a module which is used for match support for every Nth packet
6914 + This file is distributed under the terms of the GNU General Public
6915 + License (GPL). Copies of the GPL can be obtained from:
6916 + ftp://prep.ai.mit.edu/pub/gnu/GPL
6918 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
6919 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
6920 + * added support for multiple counters
6921 + * added support for matching on individual packets
6922 + in the counter cycle
6923 + 2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
6927 +#include <linux/module.h>
6928 +#include <linux/skbuff.h>
6929 +#include <linux/ip.h>
6930 +#include <net/tcp.h>
6931 +#include <linux/spinlock.h>
6932 +#include <linux/netfilter_ipv6/ip6_tables.h>
6933 +#include <linux/netfilter_ipv6/ip6t_nth.h>
6935 +MODULE_LICENSE("GPL");
6938 + * State information.
6945 +static struct state states[IP6T_NTH_NUM_COUNTERS];
6948 +ip6t_nth_match(const struct sk_buff *pskb,
6949 + const struct net_device *in,
6950 + const struct net_device *out,
6951 + const void *matchinfo,
6954 + u_int16_t datalen,
6957 + /* Parameters from userspace */
6958 + const struct ip6t_nth_info *info = matchinfo;
6959 + unsigned counter = info->counter;
6960 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
6962 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
6966 + spin_lock(&states[counter].lock);
6968 + /* Are we matching every nth packet?*/
6969 + if (info->packet == 0xFF)
6971 + /* We're matching every nth packet and only every nth packet*/
6972 + /* Do we match or invert match? */
6973 + if (info->not == 0)
6975 + if (states[counter].number == 0)
6977 + ++states[counter].number;
6980 + if (states[counter].number >= info->every)
6981 + states[counter].number = 0; /* reset the counter */
6983 + ++states[counter].number;
6988 + if (states[counter].number == 0)
6990 + ++states[counter].number;
6993 + if (states[counter].number >= info->every)
6994 + states[counter].number = 0;
6996 + ++states[counter].number;
7002 + /* We're using the --packet, so there must be a rule for every value */
7003 + if (states[counter].number == info->packet)
7005 + /* only increment the counter when a match happens */
7006 + if (states[counter].number >= info->every)
7007 + states[counter].number = 0; /* reset the counter */
7009 + ++states[counter].number;
7018 + spin_unlock(&states[counter].lock);
7022 + spin_unlock(&states[counter].lock);
7027 +ip6t_nth_checkentry(const char *tablename,
7028 + const struct ip6t_ip6 *e,
7030 + unsigned int matchsize,
7031 + unsigned int hook_mask)
7033 + /* Parameters from userspace */
7034 + const struct ip6t_nth_info *info = matchinfo;
7035 + unsigned counter = info->counter;
7036 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
7038 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
7042 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
7043 + printk("nth: matchsize %u != %u\n", matchsize,
7044 + IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
7048 + states[counter].number = info->startat;
7053 +static struct ip6t_match ip6t_nth_reg = {
7057 + ip6t_nth_checkentry,
7061 +static int __init init(void)
7064 + memset(&states, 0, sizeof(states));
7065 + if (ip6t_register_match(&ip6t_nth_reg))
7068 + for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++)
7070 + spin_lock_init(&(states[counter].lock));
7073 + printk("ip6t_nth match loaded\n");
7077 +static void __exit fini(void)
7079 + ip6t_unregister_match(&ip6t_nth_reg);
7080 + printk("ip6t_nth match unloaded\n");