1 diff -Nur linux-2.6.3.org/include/linux/netfilter.h linux-2.6.3/include/linux/netfilter.h
2 --- linux-2.6.3.org/include/linux/netfilter.h 2004-02-18 04:57:59.000000000 +0100
3 +++ linux-2.6.3/include/linux/netfilter.h 2004-02-27 00:03:00.000228144 +0100
6 extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
8 +typedef void nf_logfn(unsigned int hooknum,
9 + const struct sk_buff *skb,
10 + const struct net_device *in,
11 + const struct net_device *out,
12 + const char *prefix);
14 +/* Function to register/unregister log function. */
15 +int nf_log_register(int pf, nf_logfn *logfn);
16 +void nf_log_unregister(int pf, nf_logfn *logfn);
18 +/* Calls the registered backend logging function */
19 +void nf_log_packet(int pf,
20 + unsigned int hooknum,
21 + const struct sk_buff *skb,
22 + const struct net_device *in,
23 + const struct net_device *out,
24 + const char *fmt, ...);
26 /* Activate hook; either okfn or kfree_skb called, unless a hook
27 returns NF_STOLEN (in which case, it's up to the hook to deal with
29 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.3/include/linux/netfilter_ipv4/ip_conntrack.h
30 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ip_conntrack.h 2004-02-18 04:59:30.000000000 +0100
31 +++ linux-2.6.3/include/linux/netfilter_ipv4/ip_conntrack.h 2004-02-27 00:03:14.480026880 +0100
33 /* Call me when a conntrack is destroyed. */
34 extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
36 +/* Fake conntrack entry for untracked connections */
37 +extern struct ip_conntrack ip_conntrack_untracked;
39 /* Returns new sk_buff, or NULL */
41 ip_ct_gather_frags(struct sk_buff *skb);
42 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_connlimit.h
43 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100
44 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-02-27 00:03:07.981014880 +0100
46 +#ifndef _IPT_CONNLIMIT_H
47 +#define _IPT_CONNLIMIT_H
49 +struct ipt_connlimit_data;
51 +struct ipt_connlimit_info {
55 + struct ipt_connlimit_data *data;
57 +#endif /* _IPT_CONNLIMIT_H */
58 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_conntrack.h
59 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_conntrack.h 2004-02-18 04:59:05.000000000 +0100
60 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_conntrack.h 2004-02-27 00:03:14.480026880 +0100
63 #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
64 #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
65 +#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
67 /* flags, invflags: */
68 #define IPT_CONNTRACK_STATE 0x01
69 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_dstlimit.h
70 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 01:00:00.000000000 +0100
71 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-02-27 00:03:08.651912888 +0100
73 +#ifndef _IPT_DSTLIMIT_H
74 +#define _IPT_DSTLIMIT_H
76 +/* timings are in milliseconds. */
77 +#define IPT_DSTLIMIT_SCALE 10000
78 +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
79 + seconds, or one every 59 hours. */
81 +/* details of this structure hidden by the implementation */
82 +struct ipt_dstlimit_htable;
84 +#define IPT_DSTLIMIT_HASH_DIP 0x0001
85 +#define IPT_DSTLIMIT_HASH_DPT 0x0002
86 +#define IPT_DSTLIMIT_HASH_SIP 0x0004
88 +struct dstlimit_cfg {
89 + u_int32_t mode; /* bitmask of IPT_DSTLIMIT_HASH_* */
90 + u_int32_t avg; /* Average secs between packets * scale */
91 + u_int32_t burst; /* Period multiplier for upper limit. */
93 + /* user specified */
94 + u_int32_t size; /* how many buckets */
95 + u_int32_t max; /* max number of entries */
96 + u_int32_t gc_interval; /* gc interval */
97 + u_int32_t expire; /* when do entries expire? */
100 +struct ipt_dstlimit_info {
101 + char name [IFNAMSIZ]; /* name */
102 + struct dstlimit_cfg cfg;
103 + struct ipt_dstlimit_htable *hinfo;
105 + /* Used internally by the kernel */
108 + struct ipt_dstlimit_info *master;
111 +#endif /*_IPT_DSTLIMIT_H*/
112 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_fuzzy.h
113 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 01:00:00.000000000 +0100
114 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_fuzzy.h 2004-02-27 00:03:09.359805272 +0100
116 +#ifndef _IPT_FUZZY_H
117 +#define _IPT_FUZZY_H
119 +#include <linux/param.h>
120 +#include <linux/types.h>
122 +#define MAXFUZZYRATE 10000000
123 +#define MINFUZZYRATE 3
125 +struct ipt_fuzzy_info {
126 + u_int32_t minimum_rate;
127 + u_int32_t maximum_rate;
128 + u_int32_t packets_total;
129 + u_int32_t bytes_total;
130 + u_int32_t previous_time;
131 + u_int32_t present_time;
132 + u_int32_t mean_rate;
133 + u_int8_t acceptance_rate;
136 +#endif /*_IPT_FUZZY_H*/
137 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_ipv4options.h
138 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 01:00:00.000000000 +0100
139 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-02-27 00:03:10.065697960 +0100
141 +#ifndef __ipt_ipv4options_h_included__
142 +#define __ipt_ipv4options_h_included__
144 +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */
145 +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */
146 +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */
147 +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */
148 +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10
149 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */
150 +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40
151 +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */
152 +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100
153 +#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */
154 +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */
156 +struct ipt_ipv4options_info {
161 +#endif /* __ipt_ipv4options_h_included__ */
162 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_mport.h
163 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 01:00:00.000000000 +0100
164 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_mport.h 2004-02-27 00:03:10.772590496 +0100
166 +#ifndef _IPT_MPORT_H
167 +#define _IPT_MPORT_H
168 +#include <linux/netfilter_ipv4/ip_tables.h>
170 +#define IPT_MPORT_SOURCE (1<<0)
171 +#define IPT_MPORT_DESTINATION (1<<1)
172 +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION)
174 +#define IPT_MULTI_PORTS 15
176 +/* Must fit inside union ipt_matchinfo: 32 bytes */
177 +/* every entry in ports[] except for the last one has one bit in pflags
178 + * associated with it. If this bit is set, the port is the first port of
179 + * a portrange, with the next entry being the last.
180 + * End of list is marked with pflags bit set and port=65535.
181 + * If 14 ports are used (last one does not have a pflag), the last port
182 + * is repeated to fill the last entry in ports[] */
185 + u_int8_t flags:2; /* Type of comparison */
186 + u_int16_t pflags:14; /* Port flags */
187 + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
189 +#endif /*_IPT_MPORT_H*/
190 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_nth.h
191 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 01:00:00.000000000 +0100
192 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_nth.h 2004-02-27 00:03:12.719294552 +0100
197 +#include <linux/param.h>
198 +#include <linux/types.h>
200 +#ifndef IPT_NTH_NUM_COUNTERS
201 +#define IPT_NTH_NUM_COUNTERS 16
204 +struct ipt_nth_info {
212 +#endif /*_IPT_NTH_H*/
213 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_quota.h
214 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 01:00:00.000000000 +0100
215 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_quota.h 2004-02-27 00:03:13.672149696 +0100
217 +#ifndef _IPT_QUOTA_H
218 +#define _IPT_QUOTA_H
220 +/* print debug info in both kernel/netfilter module & iptable library */
221 +//#define DEBUG_IPT_QUOTA
223 +struct ipt_quota_info {
227 +#endif /*_IPT_QUOTA_H*/
228 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_realm.h
229 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 01:00:00.000000000 +0100
230 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_realm.h 2004-02-27 00:03:15.261908016 +0100
232 +#ifndef _IPT_REALM_H
233 +#define _IPT_REALM_H
235 +struct ipt_realm_info {
240 +#endif /*_IPT_REALM_H*/
241 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_sctp.h
242 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 01:00:00.000000000 +0100
243 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_sctp.h 2004-02-27 00:03:16.145773648 +0100
245 +#ifndef _IPT_SCTP_H_
246 +#define _IPT_SCTP_H_
248 +#define IPT_SCTP_SRC_PORTS 0x01
249 +#define IPT_SCTP_DEST_PORTS 0x02
250 +#define IPT_SCTP_CHUNK_TYPES 0x04
252 +#define IPT_SCTP_VALID_FLAGS 0x07
254 +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
256 +struct ipt_sctp_info {
257 + u_int16_t dpts[2]; /* Min, Max */
258 + u_int16_t spts[2]; /* Min, Max */
260 + u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */
262 +#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */
263 +#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */
264 +#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */
266 + u_int32_t chunk_match_type;
269 + u_int32_t invflags;
272 +#define bytes(type) (sizeof(type) * 8)
274 +#define SCTP_CHUNKMAP_SET(chunkmap, type) \
276 + chunkmap[type / bytes(u_int32_t)] |= \
277 + 1 << (type % bytes(u_int32_t)); \
280 +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
282 + chunkmap[type / bytes(u_int32_t)] &= \
283 + ~(1 << (type % bytes(u_int32_t))); \
286 +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
288 + (chunkmap[type / bytes (u_int32_t)] & \
289 + (1 << (type % bytes (u_int32_t)))) ? 1: 0; \
292 +#define SCTP_CHUNKMAP_RESET(chunkmap) \
295 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
299 +#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
302 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
303 + chunkmap[i] = ~0; \
306 +#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
309 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
310 + destmap[i] = srcmap[i]; \
313 +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
317 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
318 + if (chunkmap[i]) { \
326 +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
330 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
331 + if (chunkmap[i] != ~0) { \
339 +#endif /* _IPT_SCTP_H_ */
341 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_state.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_state.h
342 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_state.h 2004-02-18 04:59:18.000000000 +0100
343 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_state.h 2004-02-27 00:03:14.480026880 +0100
345 #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
346 #define IPT_STATE_INVALID (1 << 0)
348 +#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
350 struct ipt_state_info
352 unsigned int statemask;
353 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_TTL.h
354 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100
355 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_TTL.h 2004-02-27 00:03:07.345111552 +0100
357 +/* TTL modification module for IP tables
358 + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
369 +#define IPT_TTL_MAXMODE IPT_TTL_DEC
371 +struct ipt_TTL_info {
378 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_ULOG.h linux-2.6.3/include/linux/netfilter_ipv4/ipt_ULOG.h
379 --- linux-2.6.3.org/include/linux/netfilter_ipv4/ipt_ULOG.h 2004-02-18 04:57:31.000000000 +0100
380 +++ linux-2.6.3/include/linux/netfilter_ipv4/ipt_ULOG.h 2004-02-27 00:03:00.000228144 +0100
382 #define NETLINK_NFLOG 5
385 +#define ULOG_DEFAULT_NLGROUP 1
386 +#define ULOG_DEFAULT_QTHRESHOLD 1
388 #define ULOG_MAC_LEN 80
389 #define ULOG_PREFIX_LEN 32
391 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv4.h linux-2.6.3/include/linux/netfilter_ipv4.h
392 --- linux-2.6.3.org/include/linux/netfilter_ipv4.h 2004-02-18 04:59:16.000000000 +0100
393 +++ linux-2.6.3/include/linux/netfilter_ipv4.h 2004-02-27 00:03:14.480026880 +0100
396 enum nf_ip_hook_priorities {
397 NF_IP_PRI_FIRST = INT_MIN,
398 + NF_IP_PRI_CONNTRACK_DEFRAG = -400,
399 + NF_IP_PRI_RAW = -300,
400 NF_IP_PRI_SELINUX_FIRST = -225,
401 NF_IP_PRI_CONNTRACK = -200,
402 NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
403 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.3/include/linux/netfilter_ipv6/ip6t_fuzzy.h
404 --- linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 01:00:00.000000000 +0100
405 +++ linux-2.6.3/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2004-02-27 00:03:09.360805120 +0100
407 +#ifndef _IP6T_FUZZY_H
408 +#define _IP6T_FUZZY_H
410 +#include <linux/param.h>
411 +#include <linux/types.h>
413 +#define MAXFUZZYRATE 10000000
414 +#define MINFUZZYRATE 3
416 +struct ip6t_fuzzy_info {
417 + u_int32_t minimum_rate;
418 + u_int32_t maximum_rate;
419 + u_int32_t packets_total;
420 + u_int32_t bytes_total;
421 + u_int32_t previous_time;
422 + u_int32_t present_time;
423 + u_int32_t mean_rate;
424 + u_int8_t acceptance_rate;
427 +#endif /*_IP6T_FUZZY_H*/
428 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.3/include/linux/netfilter_ipv6/ip6t_HL.h
429 --- linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 01:00:00.000000000 +0100
430 +++ linux-2.6.3/include/linux/netfilter_ipv6/ip6t_HL.h 2004-02-27 00:03:05.118450056 +0100
432 +/* Hop Limit modification module for ip6tables
433 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
434 + * Based on HW's TTL module */
445 +#define IP6T_HL_MAXMODE IP6T_HL_DEC
447 +struct ip6t_HL_info {
449 + u_int8_t hop_limit;
454 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.3/include/linux/netfilter_ipv6/ip6t_nth.h
455 --- linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 01:00:00.000000000 +0100
456 +++ linux-2.6.3/include/linux/netfilter_ipv6/ip6t_nth.h 2004-02-27 00:03:12.719294552 +0100
461 +#include <linux/param.h>
462 +#include <linux/types.h>
464 +#ifndef IP6T_NTH_NUM_COUNTERS
465 +#define IP6T_NTH_NUM_COUNTERS 16
468 +struct ip6t_nth_info {
476 +#endif /*_IP6T_NTH_H*/
477 diff -Nur linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.3/include/linux/netfilter_ipv6/ip6t_REJECT.h
478 --- linux-2.6.3.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-02-18 04:57:12.000000000 +0100
479 +++ linux-2.6.3/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-02-27 00:03:06.649217344 +0100
481 #define _IP6T_REJECT_H
483 enum ip6t_reject_with {
484 - IP6T_ICMP_NET_UNREACHABLE,
485 - IP6T_ICMP_HOST_UNREACHABLE,
486 - IP6T_ICMP_PROT_UNREACHABLE,
487 - IP6T_ICMP_PORT_UNREACHABLE,
488 - IP6T_ICMP_ECHOREPLY
489 + IP6T_ICMP6_NO_ROUTE,
490 + IP6T_ICMP6_ADM_PROHIBITED,
491 + IP6T_ICMP6_NOT_NEIGHBOUR,
492 + IP6T_ICMP6_ADDR_UNREACH,
493 + IP6T_ICMP6_PORT_UNREACH,
494 + IP6T_ICMP6_ECHOREPLY,
498 struct ip6t_reject_info {
499 enum ip6t_reject_with with; /* reject type */
502 -#endif /*_IPT_REJECT_H*/
503 +#endif /*_IP6T_REJECT_H*/
504 diff -Nur linux-2.6.3.org/net/core/netfilter.c linux-2.6.3/net/core/netfilter.c
505 --- linux-2.6.3.org/net/core/netfilter.c 2004-02-26 23:36:59.000000000 +0100
506 +++ linux-2.6.3/net/core/netfilter.c 2004-02-27 00:03:00.001227992 +0100
509 * February 2000: Modified by James Morris to have 1 queue per protocol.
510 * 15-Mar-2000: Added NF_REPEAT --RR.
511 + * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
513 #include <linux/config.h>
514 +#include <linux/kernel.h>
515 #include <linux/netfilter.h>
516 #include <net/protocol.h>
517 #include <linux/init.h>
519 EXPORT_SYMBOL(skb_ip_make_writable);
520 #endif /*CONFIG_INET*/
522 +/* Internal logging interface, which relies on the real
523 + LOG target modules */
525 +#define NF_LOG_PREFIXLEN 128
527 +static nf_logfn *nf_logging[NPROTO]; /* = NULL */
528 +static int reported = 0;
529 +static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
531 +int nf_log_register(int pf, nf_logfn *logfn)
535 + /* Any setup of logging members must be done before
536 + * substituting pointer. */
538 + spin_lock(&nf_log_lock);
539 + if (!nf_logging[pf]) {
540 + nf_logging[pf] = logfn;
543 + spin_unlock(&nf_log_lock);
547 +void nf_log_unregister(int pf, nf_logfn *logfn)
549 + spin_lock(&nf_log_lock);
550 + if (nf_logging[pf] == logfn)
551 + nf_logging[pf] = NULL;
552 + spin_unlock(&nf_log_lock);
554 + /* Give time to concurrent readers. */
558 +void nf_log_packet(int pf,
559 + unsigned int hooknum,
560 + const struct sk_buff *skb,
561 + const struct net_device *in,
562 + const struct net_device *out,
563 + const char *fmt, ...)
566 + char prefix[NF_LOG_PREFIXLEN];
570 + logfn = nf_logging[pf];
572 + va_start(args, fmt);
573 + vsnprintf(prefix, sizeof(prefix), fmt, args);
575 + /* We must read logging before nf_logfn[pf] */
576 + smp_read_barrier_depends();
577 + logfn(hooknum, skb, in, out, prefix);
578 + } else if (!reported) {
579 + printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
580 + "no backend logging module loaded in!\n");
585 +EXPORT_SYMBOL(nf_log_register);
586 +EXPORT_SYMBOL(nf_log_unregister);
587 +EXPORT_SYMBOL(nf_log_packet);
589 /* This does not belong here, but ipt_REJECT needs it if connection
590 tracking in use: without this, connection may not be in hash table,
591 diff -Nur linux-2.6.3.org/net/core/netfilter.c.orig linux-2.6.3/net/core/netfilter.c.orig
592 --- linux-2.6.3.org/net/core/netfilter.c.orig 1970-01-01 01:00:00.000000000 +0100
593 +++ linux-2.6.3/net/core/netfilter.c.orig 2004-02-27 00:02:49.299854848 +0100
595 +/* netfilter.c: look after the filters for various protocols.
596 + * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
598 + * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
601 + * Rusty Russell (C)2000 -- This code is GPL.
603 + * February 2000: Modified by James Morris to have 1 queue per protocol.
604 + * 15-Mar-2000: Added NF_REPEAT --RR.
606 +#include <linux/config.h>
607 +#include <linux/netfilter.h>
608 +#include <net/protocol.h>
609 +#include <linux/init.h>
610 +#include <linux/skbuff.h>
611 +#include <linux/wait.h>
612 +#include <linux/module.h>
613 +#include <linux/interrupt.h>
614 +#include <linux/if.h>
615 +#include <linux/netdevice.h>
616 +#include <linux/inetdevice.h>
617 +#include <linux/tcp.h>
618 +#include <linux/udp.h>
619 +#include <linux/icmp.h>
620 +#include <net/sock.h>
621 +#include <net/route.h>
622 +#include <linux/ip.h>
624 +/* In this code, we can be waiting indefinitely for userspace to
625 + * service a packet if a hook returns NF_QUEUE. We could keep a count
626 + * of skbuffs queued for userspace, and not deregister a hook unless
627 + * this is zero, but that sucks. Now, we simply check when the
628 + * packets come back: if the hook is gone, the packet is discarded. */
629 +#ifdef CONFIG_NETFILTER_DEBUG
630 +#define NFDEBUG(format, args...) printk(format , ## args)
632 +#define NFDEBUG(format, args...)
635 +/* Sockopts only registered and called from user context, so
636 + net locking would be overkill. Also, [gs]etsockopt calls may
638 +static DECLARE_MUTEX(nf_sockopt_mutex);
640 +struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
641 +static LIST_HEAD(nf_sockopts);
642 +static spinlock_t nf_hook_lock = SPIN_LOCK_UNLOCKED;
645 + * A queue handler may be registered for each protocol. Each is protected by
646 + * long term mutex. The handler must provide an an outfn() to accept packets
647 + * for queueing and must reinject all packets it receives, no matter what.
649 +static struct nf_queue_handler_t {
650 + nf_queue_outfn_t outfn;
652 +} queue_handler[NPROTO];
653 +static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
655 +int nf_register_hook(struct nf_hook_ops *reg)
657 + struct list_head *i;
659 + spin_lock_bh(&nf_hook_lock);
660 + list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
661 + if (reg->priority < ((struct nf_hook_ops *)i)->priority)
664 + list_add_rcu(®->list, i->prev);
665 + spin_unlock_bh(&nf_hook_lock);
671 +void nf_unregister_hook(struct nf_hook_ops *reg)
673 + spin_lock_bh(&nf_hook_lock);
674 + list_del_rcu(®->list);
675 + spin_unlock_bh(&nf_hook_lock);
680 +/* Do exclusive ranges overlap? */
681 +static inline int overlap(int min1, int max1, int min2, int max2)
683 + return max1 > min2 && min1 < max2;
686 +/* Functions to register sockopt ranges (exclusive). */
687 +int nf_register_sockopt(struct nf_sockopt_ops *reg)
689 + struct list_head *i;
692 + if (down_interruptible(&nf_sockopt_mutex) != 0)
695 + list_for_each(i, &nf_sockopts) {
696 + struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
697 + if (ops->pf == reg->pf
698 + && (overlap(ops->set_optmin, ops->set_optmax,
699 + reg->set_optmin, reg->set_optmax)
700 + || overlap(ops->get_optmin, ops->get_optmax,
701 + reg->get_optmin, reg->get_optmax))) {
702 + NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
703 + ops->set_optmin, ops->set_optmax,
704 + ops->get_optmin, ops->get_optmax,
705 + reg->set_optmin, reg->set_optmax,
706 + reg->get_optmin, reg->get_optmax);
712 + list_add(®->list, &nf_sockopts);
714 + up(&nf_sockopt_mutex);
718 +void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
720 + /* No point being interruptible: we're probably in cleanup_module() */
722 + down(&nf_sockopt_mutex);
723 + if (reg->use != 0) {
724 + /* To be woken by nf_sockopt call... */
725 + /* FIXME: Stuart Young's name appears gratuitously. */
726 + set_current_state(TASK_UNINTERRUPTIBLE);
727 + reg->cleanup_task = current;
728 + up(&nf_sockopt_mutex);
732 + list_del(®->list);
733 + up(&nf_sockopt_mutex);
736 +#ifdef CONFIG_NETFILTER_DEBUG
738 +#include <net/tcp.h>
739 +#include <linux/netfilter_ipv4.h>
741 +static void debug_print_hooks_ip(unsigned int nf_debug)
743 + if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
744 + printk("PRE_ROUTING ");
745 + nf_debug ^= (1 << NF_IP_PRE_ROUTING);
747 + if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
748 + printk("LOCAL_IN ");
749 + nf_debug ^= (1 << NF_IP_LOCAL_IN);
751 + if (nf_debug & (1 << NF_IP_FORWARD)) {
752 + printk("FORWARD ");
753 + nf_debug ^= (1 << NF_IP_FORWARD);
755 + if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
756 + printk("LOCAL_OUT ");
757 + nf_debug ^= (1 << NF_IP_LOCAL_OUT);
759 + if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
760 + printk("POST_ROUTING ");
761 + nf_debug ^= (1 << NF_IP_POST_ROUTING);
764 + printk("Crap bits: 0x%04X", nf_debug);
768 +void nf_dump_skb(int pf, struct sk_buff *skb)
770 + printk("skb: pf=%i %s dev=%s len=%u\n",
772 + skb->sk ? "(owned)" : "(unowned)",
773 + skb->dev ? skb->dev->name : "(no dev)",
777 + const struct iphdr *ip = skb->nh.iph;
778 + __u32 *opt = (__u32 *) (ip + 1);
780 + __u16 src_port = 0, dst_port = 0;
782 + if (ip->protocol == IPPROTO_TCP
783 + || ip->protocol == IPPROTO_UDP) {
784 + struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
785 + src_port = ntohs(tcp->source);
786 + dst_port = ntohs(tcp->dest);
789 + printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
790 + " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
791 + ip->protocol, NIPQUAD(ip->saddr),
792 + src_port, NIPQUAD(ip->daddr),
794 + ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
795 + ntohs(ip->frag_off), ip->ttl);
797 + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
798 + printk(" O=0x%8.8X", *opt++);
804 +void nf_debug_ip_local_deliver(struct sk_buff *skb)
806 + /* If it's a loopback packet, it must have come through
807 + * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and
808 + * NF_IP_LOCAL_IN. Otherwise, must have gone through
809 + * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */
811 + printk("ip_local_deliver: skb->dev is NULL.\n");
813 + else if (strcmp(skb->dev->name, "lo") == 0) {
814 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
815 + | (1 << NF_IP_POST_ROUTING)
816 + | (1 << NF_IP_PRE_ROUTING)
817 + | (1 << NF_IP_LOCAL_IN))) {
818 + printk("ip_local_deliver: bad loopback skb: ");
819 + debug_print_hooks_ip(skb->nf_debug);
820 + nf_dump_skb(PF_INET, skb);
824 + if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)
825 + | (1<<NF_IP_LOCAL_IN))) {
826 + printk("ip_local_deliver: bad non-lo skb: ");
827 + debug_print_hooks_ip(skb->nf_debug);
828 + nf_dump_skb(PF_INET, skb);
833 +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb)
835 + if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
836 + | (1 << NF_IP_POST_ROUTING))) {
837 + printk("ip_dev_loopback_xmit: bad owned skb = %p: ",
839 + debug_print_hooks_ip(newskb->nf_debug);
840 + nf_dump_skb(PF_INET, newskb);
842 + /* Clear to avoid confusing input check */
843 + newskb->nf_debug = 0;
846 +void nf_debug_ip_finish_output2(struct sk_buff *skb)
848 + /* If it's owned, it must have gone through the
849 + * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING.
850 + * Otherwise, must have gone through
851 + * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING.
854 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
855 + | (1 << NF_IP_POST_ROUTING))) {
856 + printk("ip_finish_output: bad owned skb = %p: ", skb);
857 + debug_print_hooks_ip(skb->nf_debug);
858 + nf_dump_skb(PF_INET, skb);
861 + if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING)
862 + | (1 << NF_IP_FORWARD)
863 + | (1 << NF_IP_POST_ROUTING))) {
864 + /* Fragments, entunnelled packets, TCP RSTs
865 + generated by ipt_REJECT will have no
866 + owners, but still may be local */
867 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
868 + | (1 << NF_IP_POST_ROUTING))){
869 + printk("ip_finish_output:"
870 + " bad unowned skb = %p: ",skb);
871 + debug_print_hooks_ip(skb->nf_debug);
872 + nf_dump_skb(PF_INET, skb);
877 +#endif /*CONFIG_NETFILTER_DEBUG*/
879 +/* Call get/setsockopt() */
880 +static int nf_sockopt(struct sock *sk, int pf, int val,
881 + char *opt, int *len, int get)
883 + struct list_head *i;
884 + struct nf_sockopt_ops *ops;
887 + if (down_interruptible(&nf_sockopt_mutex) != 0)
890 + list_for_each(i, &nf_sockopts) {
891 + ops = (struct nf_sockopt_ops *)i;
892 + if (ops->pf == pf) {
894 + if (val >= ops->get_optmin
895 + && val < ops->get_optmax) {
897 + up(&nf_sockopt_mutex);
898 + ret = ops->get(sk, val, opt, len);
902 + if (val >= ops->set_optmin
903 + && val < ops->set_optmax) {
905 + up(&nf_sockopt_mutex);
906 + ret = ops->set(sk, val, opt, *len);
912 + up(&nf_sockopt_mutex);
913 + return -ENOPROTOOPT;
916 + down(&nf_sockopt_mutex);
918 + if (ops->cleanup_task)
919 + wake_up_process(ops->cleanup_task);
920 + up(&nf_sockopt_mutex);
924 +int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
927 + return nf_sockopt(sk, pf, val, opt, &len, 0);
930 +int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
932 + return nf_sockopt(sk, pf, val, opt, len, 1);
935 +static unsigned int nf_iterate(struct list_head *head,
936 + struct sk_buff **skb,
938 + const struct net_device *indev,
939 + const struct net_device *outdev,
940 + struct list_head **i,
941 + int (*okfn)(struct sk_buff *),
945 + * The caller must not block between calls to this
946 + * function because of risk of continuing from deleted element.
948 + list_for_each_continue_rcu(*i, head) {
949 + struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
951 + if (hook_thresh > elem->priority)
954 + /* Optimization: we don't need to hold module
955 + reference here, since function can't sleep. --RR */
956 + switch (elem->hook(hook, skb, indev, outdev, okfn)) {
970 +#ifdef CONFIG_NETFILTER_DEBUG
975 + NFDEBUG("Evil return from %p(%u).\n",
983 +int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
987 + write_lock_bh(&queue_handler_lock);
988 + if (queue_handler[pf].outfn)
991 + queue_handler[pf].outfn = outfn;
992 + queue_handler[pf].data = data;
995 + write_unlock_bh(&queue_handler_lock);
1000 +/* The caller must flush their queue before this */
1001 +int nf_unregister_queue_handler(int pf)
1003 + write_lock_bh(&queue_handler_lock);
1004 + queue_handler[pf].outfn = NULL;
1005 + queue_handler[pf].data = NULL;
1006 + write_unlock_bh(&queue_handler_lock);
1012 + * Any packet that leaves via this function must come back
1013 + * through nf_reinject().
1015 +static int nf_queue(struct sk_buff *skb,
1016 + struct list_head *elem,
1017 + int pf, unsigned int hook,
1018 + struct net_device *indev,
1019 + struct net_device *outdev,
1020 + int (*okfn)(struct sk_buff *))
1023 + struct nf_info *info;
1024 +#ifdef CONFIG_BRIDGE_NETFILTER
1025 + struct net_device *physindev = NULL;
1026 + struct net_device *physoutdev = NULL;
1029 + /* QUEUE == DROP if noone is waiting, to be safe. */
1030 + read_lock(&queue_handler_lock);
1031 + if (!queue_handler[pf].outfn) {
1032 + read_unlock(&queue_handler_lock);
1037 + info = kmalloc(sizeof(*info), GFP_ATOMIC);
1039 + if (net_ratelimit())
1040 + printk(KERN_ERR "OOM queueing packet %p\n",
1042 + read_unlock(&queue_handler_lock);
1047 + *info = (struct nf_info) {
1048 + (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
1050 + /* If it's going away, ignore hook. */
1051 + if (!try_module_get(info->elem->owner)) {
1052 + read_unlock(&queue_handler_lock);
1057 + /* Bump dev refs so they don't vanish while packet is out */
1058 + if (indev) dev_hold(indev);
1059 + if (outdev) dev_hold(outdev);
1061 +#ifdef CONFIG_BRIDGE_NETFILTER
1062 + if (skb->nf_bridge) {
1063 + physindev = skb->nf_bridge->physindev;
1064 + if (physindev) dev_hold(physindev);
1065 + physoutdev = skb->nf_bridge->physoutdev;
1066 + if (physoutdev) dev_hold(physoutdev);
1070 + status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
1071 + read_unlock(&queue_handler_lock);
1074 + /* James M doesn't say fuck enough. */
1075 + if (indev) dev_put(indev);
1076 + if (outdev) dev_put(outdev);
1077 +#ifdef CONFIG_BRIDGE_NETFILTER
1078 + if (physindev) dev_put(physindev);
1079 + if (physoutdev) dev_put(physoutdev);
1081 + module_put(info->elem->owner);
1089 +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
1090 + struct net_device *indev,
1091 + struct net_device *outdev,
1092 + int (*okfn)(struct sk_buff *),
1095 + struct list_head *elem;
1096 + unsigned int verdict;
1099 + if (skb->ip_summed == CHECKSUM_HW) {
1100 + if (outdev == NULL) {
1101 + skb->ip_summed = CHECKSUM_NONE;
1103 + skb_checksum_help(skb);
1107 + /* We may already have this, but read-locks nest anyway */
1110 +#ifdef CONFIG_NETFILTER_DEBUG
1111 + if (skb->nf_debug & (1 << hook)) {
1112 + printk("nf_hook: hook %i already set.\n", hook);
1113 + nf_dump_skb(pf, skb);
1115 + skb->nf_debug |= (1 << hook);
1118 + elem = &nf_hooks[pf][hook];
1120 + verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
1121 + outdev, &elem, okfn, hook_thresh);
1122 + if (verdict == NF_QUEUE) {
1123 + NFDEBUG("nf_hook: Verdict = QUEUE.\n");
1124 + if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn))
1128 + switch (verdict) {
1139 + rcu_read_unlock();
1143 +void nf_reinject(struct sk_buff *skb, struct nf_info *info,
1144 + unsigned int verdict)
1146 + struct list_head *elem = &info->elem->list;
1147 + struct list_head *i;
1151 + /* Release those devices we held, or Alexey will kill me. */
1152 + if (info->indev) dev_put(info->indev);
1153 + if (info->outdev) dev_put(info->outdev);
1154 +#ifdef CONFIG_BRIDGE_NETFILTER
1155 + if (skb->nf_bridge) {
1156 + if (skb->nf_bridge->physindev)
1157 + dev_put(skb->nf_bridge->physindev);
1158 + if (skb->nf_bridge->physoutdev)
1159 + dev_put(skb->nf_bridge->physoutdev);
1163 + /* Drop reference to owner of hook which queued us. */
1164 + module_put(info->elem->owner);
1166 + list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
1171 + if (elem == &nf_hooks[info->pf][info->hook]) {
1172 + /* The module which sent it to userspace is gone. */
1173 + NFDEBUG("%s: module disappeared, dropping packet.\n",
1175 + verdict = NF_DROP;
1178 + /* Continue traversal iff userspace said ok... */
1179 + if (verdict == NF_REPEAT) {
1180 + elem = elem->prev;
1181 + verdict = NF_ACCEPT;
1184 + if (verdict == NF_ACCEPT) {
1186 + verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
1188 + info->indev, info->outdev, &elem,
1189 + info->okfn, INT_MIN);
1192 + switch (verdict) {
1198 + if (!nf_queue(skb, elem, info->pf, info->hook,
1199 + info->indev, info->outdev, info->okfn))
1203 + rcu_read_unlock();
1205 + if (verdict == NF_DROP)
1213 +/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
1214 +int ip_route_me_harder(struct sk_buff **pskb)
1216 + struct iphdr *iph = (*pskb)->nh.iph;
1217 + struct rtable *rt;
1218 + struct flowi fl = {};
1219 + struct dst_entry *odst;
1220 + unsigned int hh_len;
1222 + /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
1223 + * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
1225 + if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
1226 + fl.nl_u.ip4_u.daddr = iph->daddr;
1227 + fl.nl_u.ip4_u.saddr = iph->saddr;
1228 + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
1229 + fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
1230 +#ifdef CONFIG_IP_ROUTE_FWMARK
1231 + fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
1233 + if (ip_route_output_key(&rt, &fl) != 0)
1236 + /* Drop old route. */
1237 + dst_release((*pskb)->dst);
1238 + (*pskb)->dst = &rt->u.dst;
1240 + /* non-local src, find valid iif to satisfy
1241 + * rp-filter when calling ip_route_input. */
1242 + fl.nl_u.ip4_u.daddr = iph->saddr;
1243 + if (ip_route_output_key(&rt, &fl) != 0)
1246 + odst = (*pskb)->dst;
1247 + if (ip_route_input(*pskb, iph->daddr, iph->saddr,
1248 + RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
1249 + dst_release(&rt->u.dst);
1252 + dst_release(&rt->u.dst);
1253 + dst_release(odst);
1256 + if ((*pskb)->dst->error)
1259 + /* Change in oif may mean change in hh_len. */
1260 + hh_len = (*pskb)->dst->dev->hard_header_len;
1261 + if (skb_headroom(*pskb) < hh_len) {
1262 + struct sk_buff *nskb;
1264 + nskb = skb_realloc_headroom(*pskb, hh_len);
1268 + skb_set_owner_w(nskb, (*pskb)->sk);
1276 +int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
1278 + struct sk_buff *nskb;
1279 + unsigned int iplen;
1281 + if (writable_len > (*pskb)->len)
1284 + /* Not exclusive use of packet? Must copy. */
1285 + if (skb_shared(*pskb) || skb_cloned(*pskb))
1288 + /* Alexey says IP hdr is always modifiable and linear, so ok. */
1289 + if (writable_len <= (*pskb)->nh.iph->ihl*4)
1292 + iplen = writable_len - (*pskb)->nh.iph->ihl*4;
1294 + /* DaveM says protocol headers are also modifiable. */
1295 + switch ((*pskb)->nh.iph->protocol) {
1296 + case IPPROTO_TCP: {
1297 + struct tcphdr hdr;
1298 + if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
1299 + &hdr, sizeof(hdr)) != 0)
1301 + if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
1306 + if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
1309 + case IPPROTO_ICMP:
1311 + <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
1314 + /* Insert other cases here as desired */
1318 + nskb = skb_copy(*pskb, GFP_ATOMIC);
1321 + BUG_ON(skb_is_nonlinear(nskb));
1323 + /* Rest of kernel will get very unhappy if we pass it a
1324 + suddenly-orphaned skbuff */
1326 + skb_set_owner_w(nskb, (*pskb)->sk);
1332 + return pskb_may_pull(*pskb, writable_len);
1334 +EXPORT_SYMBOL(skb_ip_make_writable);
1335 +#endif /*CONFIG_INET*/
1338 +/* This does not belong here, but ipt_REJECT needs it if connection
1339 + tracking in use: without this, connection may not be in hash table,
1340 + and hence manufactured ICMP or RST packets will not be associated
1342 +void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
1344 +void __init netfilter_init(void)
1348 + for (i = 0; i < NPROTO; i++) {
1349 + for (h = 0; h < NF_MAX_HOOKS; h++)
1350 + INIT_LIST_HEAD(&nf_hooks[i][h]);
1354 +EXPORT_SYMBOL(ip_ct_attach);
1355 +EXPORT_SYMBOL(ip_route_me_harder);
1356 +EXPORT_SYMBOL(nf_getsockopt);
1357 +EXPORT_SYMBOL(nf_hook_slow);
1358 +EXPORT_SYMBOL(nf_hooks);
1359 +EXPORT_SYMBOL(nf_register_hook);
1360 +EXPORT_SYMBOL(nf_register_queue_handler);
1361 +EXPORT_SYMBOL(nf_register_sockopt);
1362 +EXPORT_SYMBOL(nf_reinject);
1363 +EXPORT_SYMBOL(nf_setsockopt);
1364 +EXPORT_SYMBOL(nf_unregister_hook);
1365 +EXPORT_SYMBOL(nf_unregister_queue_handler);
1366 +EXPORT_SYMBOL(nf_unregister_sockopt);
1367 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.3/net/ipv4/netfilter/ip_conntrack_core.c
1368 --- linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-02-26 23:36:59.000000000 +0100
1369 +++ linux-2.6.3/net/ipv4/netfilter/ip_conntrack_core.c 2004-02-27 00:03:14.481026728 +0100
1371 static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
1372 struct list_head *ip_conntrack_hash;
1373 static kmem_cache_t *ip_conntrack_cachep;
1374 +struct ip_conntrack ip_conntrack_untracked;
1376 extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
1378 @@ -794,6 +795,15 @@
1382 + /* Never happen */
1383 + if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
1384 + if (net_ratelimit()) {
1385 + printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
1386 + (*pskb)->nh.iph->protocol, hooknum);
1391 /* FIXME: Do this right please. --RR */
1392 (*pskb)->nfcache |= NFC_UNKNOWN;
1394 @@ -812,18 +822,10 @@
1398 - /* Previously seen (loopback)? Ignore. Do this before
1399 - fragment check. */
1400 + /* Previously seen (loopback or untracked)? Ignore. */
1404 - /* Gather fragments. */
1405 - if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
1406 - *pskb = ip_ct_gather_frags(*pskb);
1411 proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
1413 /* It may be an icmp error... */
1414 @@ -1422,6 +1424,18 @@
1416 /* For use by ipt_REJECT */
1417 ip_ct_attach = ip_conntrack_attach;
1419 + /* Set up fake conntrack:
1420 + - to never be deleted, not in any hashes */
1421 + atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
1422 + /* - and look it like as a confirmed connection */
1423 + set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
1424 + /* - and prepare the ctinfo field for REJECT & NAT. */
1425 + ip_conntrack_untracked.infos[IP_CT_NEW].master =
1426 + ip_conntrack_untracked.infos[IP_CT_RELATED].master =
1427 + ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master =
1428 + &ip_conntrack_untracked.ct_general;
1433 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux-2.6.3/net/ipv4/netfilter/ip_conntrack_core.c.orig
1434 --- linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 01:00:00.000000000 +0100
1435 +++ linux-2.6.3/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-02-27 00:02:49.320851656 +0100
1437 +/* Connection state tracking for netfilter. This is separated from,
1438 + but required by, the NAT layer; it can also be used by an iptables
1441 +/* (C) 1999-2001 Paul `Rusty' Russell
1442 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
1444 + * This program is free software; you can redistribute it and/or modify
1445 + * it under the terms of the GNU General Public License version 2 as
1446 + * published by the Free Software Foundation.
1448 + * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
1449 + * - new API and handling of conntrack/nat helpers
1450 + * - now capable of multiple expectations for one master
1451 + * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
1452 + * - add usage/reference counts to ip_conntrack_expect
1453 + * - export ip_conntrack[_expect]_{find_get,put} functions
1456 +#include <linux/config.h>
1457 +#include <linux/types.h>
1458 +#include <linux/icmp.h>
1459 +#include <linux/ip.h>
1460 +#include <linux/netfilter.h>
1461 +#include <linux/netfilter_ipv4.h>
1462 +#include <linux/module.h>
1463 +#include <linux/skbuff.h>
1464 +#include <linux/proc_fs.h>
1465 +#include <linux/vmalloc.h>
1466 +#include <net/checksum.h>
1467 +#include <linux/stddef.h>
1468 +#include <linux/sysctl.h>
1469 +#include <linux/slab.h>
1470 +#include <linux/random.h>
1471 +#include <linux/jhash.h>
1472 +/* For ERR_PTR(). Yeah, I know... --RR */
1473 +#include <linux/fs.h>
1475 +/* This rwlock protects the main hash table, protocol/helper/expected
1476 + registrations, conntrack timers*/
1477 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
1478 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
1480 +#include <linux/netfilter_ipv4/ip_conntrack.h>
1481 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
1482 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1483 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
1484 +#include <linux/netfilter_ipv4/listhelp.h>
1486 +#define IP_CONNTRACK_VERSION "2.1"
1489 +#define DEBUGP printk
1491 +#define DEBUGP(format, args...)
1494 +DECLARE_RWLOCK(ip_conntrack_lock);
1495 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
1497 +void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
1498 +LIST_HEAD(ip_conntrack_expect_list);
1499 +LIST_HEAD(protocol_list);
1500 +static LIST_HEAD(helpers);
1501 +unsigned int ip_conntrack_htable_size = 0;
1502 +int ip_conntrack_max;
1503 +static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
1504 +struct list_head *ip_conntrack_hash;
1505 +static kmem_cache_t *ip_conntrack_cachep;
1507 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
1509 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
1510 + u_int8_t protocol)
1512 + return protocol == curr->proto;
1515 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
1517 + struct ip_conntrack_protocol *p;
1519 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1520 + p = LIST_FIND(&protocol_list, proto_cmpfn,
1521 + struct ip_conntrack_protocol *, protocol);
1523 + p = &ip_conntrack_generic_protocol;
1528 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
1530 + struct ip_conntrack_protocol *p;
1532 + READ_LOCK(&ip_conntrack_lock);
1533 + p = __ip_ct_find_proto(protocol);
1534 + READ_UNLOCK(&ip_conntrack_lock);
1539 +ip_conntrack_put(struct ip_conntrack *ct)
1542 + IP_NF_ASSERT(ct->infos[0].master);
1543 + /* nf_conntrack_put wants to go via an info struct, so feed it
1545 + nf_conntrack_put(&ct->infos[0]);
1548 +static int ip_conntrack_hash_rnd_initted;
1549 +static unsigned int ip_conntrack_hash_rnd;
1552 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
1555 + dump_tuple(tuple);
1557 + return (jhash_3words(tuple->src.ip,
1558 + (tuple->dst.ip ^ tuple->dst.protonum),
1559 + (tuple->src.u.all | (tuple->dst.u.all << 16)),
1560 + ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
1564 +get_tuple(const struct iphdr *iph,
1565 + const struct sk_buff *skb,
1566 + unsigned int dataoff,
1567 + struct ip_conntrack_tuple *tuple,
1568 + const struct ip_conntrack_protocol *protocol)
1570 + /* Never happen */
1571 + if (iph->frag_off & htons(IP_OFFSET)) {
1572 + printk("ip_conntrack_core: Frag of proto %u.\n",
1577 + tuple->src.ip = iph->saddr;
1578 + tuple->dst.ip = iph->daddr;
1579 + tuple->dst.protonum = iph->protocol;
1581 + return protocol->pkt_to_tuple(skb, dataoff, tuple);
1585 +invert_tuple(struct ip_conntrack_tuple *inverse,
1586 + const struct ip_conntrack_tuple *orig,
1587 + const struct ip_conntrack_protocol *protocol)
1589 + inverse->src.ip = orig->dst.ip;
1590 + inverse->dst.ip = orig->src.ip;
1591 + inverse->dst.protonum = orig->dst.protonum;
1593 + return protocol->invert_tuple(inverse, orig);
1597 +/* ip_conntrack_expect helper functions */
1599 +/* Compare tuple parts depending on mask. */
1600 +static inline int expect_cmp(const struct ip_conntrack_expect *i,
1601 + const struct ip_conntrack_tuple *tuple)
1603 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1604 + return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1608 +destroy_expect(struct ip_conntrack_expect *exp)
1610 + DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
1611 + IP_NF_ASSERT(atomic_read(&exp->use));
1612 + IP_NF_ASSERT(!timer_pending(&exp->timeout));
1618 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
1620 + IP_NF_ASSERT(exp);
1622 + if (atomic_dec_and_test(&exp->use)) {
1623 + /* usage count dropped to zero */
1624 + destroy_expect(exp);
1628 +static inline struct ip_conntrack_expect *
1629 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
1631 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1632 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1633 + return LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
1634 + struct ip_conntrack_expect *, tuple);
1637 +/* Find a expectation corresponding to a tuple. */
1638 +struct ip_conntrack_expect *
1639 +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
1641 + struct ip_conntrack_expect *exp;
1643 + READ_LOCK(&ip_conntrack_lock);
1644 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
1645 + exp = __ip_ct_expect_find(tuple);
1647 + atomic_inc(&exp->use);
1648 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1649 + READ_UNLOCK(&ip_conntrack_lock);
1654 +/* remove one specific expectation from all lists and drop refcount,
1655 + * does _NOT_ delete the timer. */
1656 +static void __unexpect_related(struct ip_conntrack_expect *expect)
1658 + DEBUGP("unexpect_related(%p)\n", expect);
1659 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1661 + /* we're not allowed to unexpect a confirmed expectation! */
1662 + IP_NF_ASSERT(!expect->sibling);
1664 + /* delete from global and local lists */
1665 + list_del(&expect->list);
1666 + list_del(&expect->expected_list);
1668 + /* decrement expect-count of master conntrack */
1669 + if (expect->expectant)
1670 + expect->expectant->expecting--;
1672 + ip_conntrack_expect_put(expect);
1675 +/* remove one specific expecatation from all lists, drop refcount
1676 + * and expire timer.
1677 + * This function can _NOT_ be called for confirmed expects! */
1678 +static void unexpect_related(struct ip_conntrack_expect *expect)
1680 + IP_NF_ASSERT(expect->expectant);
1681 + IP_NF_ASSERT(expect->expectant->helper);
1682 + /* if we are supposed to have a timer, but we can't delete
1683 + * it: race condition. __unexpect_related will
1684 + * be calledd by timeout function */
1685 + if (expect->expectant->helper->timeout
1686 + && !del_timer(&expect->timeout))
1689 + __unexpect_related(expect);
1692 +/* delete all unconfirmed expectations for this conntrack */
1693 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
1695 + struct list_head *exp_entry, *next;
1696 + struct ip_conntrack_expect *exp;
1698 + DEBUGP("remove_expectations(%p)\n", ct);
1700 + list_for_each_safe(exp_entry, next, &ct->sibling_list) {
1701 + exp = list_entry(exp_entry, struct ip_conntrack_expect,
1704 + /* we skip established expectations, as we want to delete
1705 + * the un-established ones only */
1706 + if (exp->sibling) {
1707 + DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
1708 + if (drop_refcount) {
1709 + /* Indicate that this expectations parent is dead */
1710 + ip_conntrack_put(exp->expectant);
1711 + exp->expectant = NULL;
1716 + IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
1717 + IP_NF_ASSERT(exp->expectant == ct);
1719 + /* delete expectation from global and private lists */
1720 + unexpect_related(exp);
1725 +clean_from_lists(struct ip_conntrack *ct)
1727 + unsigned int ho, hr;
1729 + DEBUGP("clean_from_lists(%p)\n", ct);
1730 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1732 + ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1733 + hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
1734 + LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
1735 + LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
1737 + /* Destroy all un-established, pending expectations */
1738 + remove_expectations(ct, 1);
1742 +destroy_conntrack(struct nf_conntrack *nfct)
1744 + struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
1745 + struct ip_conntrack_protocol *proto;
1747 + DEBUGP("destroy_conntrack(%p)\n", ct);
1748 + IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
1749 + IP_NF_ASSERT(!timer_pending(&ct->timeout));
1751 + /* To make sure we don't get any weird locking issues here:
1752 + * destroy_conntrack() MUST NOT be called with a write lock
1753 + * to ip_conntrack_lock!!! -HW */
1754 + proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
1755 + if (proto && proto->destroy)
1756 + proto->destroy(ct);
1758 + if (ip_conntrack_destroyed)
1759 + ip_conntrack_destroyed(ct);
1761 + WRITE_LOCK(&ip_conntrack_lock);
1762 + /* Delete us from our own list to prevent corruption later */
1763 + list_del(&ct->sibling_list);
1765 + /* Delete our master expectation */
1767 + if (ct->master->expectant) {
1768 + /* can't call __unexpect_related here,
1769 + * since it would screw up expect_list */
1770 + list_del(&ct->master->expected_list);
1771 + master = ct->master->expectant;
1773 + kfree(ct->master);
1775 + WRITE_UNLOCK(&ip_conntrack_lock);
1778 + ip_conntrack_put(master);
1780 + DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
1781 + kmem_cache_free(ip_conntrack_cachep, ct);
1782 + atomic_dec(&ip_conntrack_count);
1785 +static void death_by_timeout(unsigned long ul_conntrack)
1787 + struct ip_conntrack *ct = (void *)ul_conntrack;
1789 + WRITE_LOCK(&ip_conntrack_lock);
1790 + clean_from_lists(ct);
1791 + WRITE_UNLOCK(&ip_conntrack_lock);
1792 + ip_conntrack_put(ct);
1796 +conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
1797 + const struct ip_conntrack_tuple *tuple,
1798 + const struct ip_conntrack *ignored_conntrack)
1800 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1801 + return i->ctrack != ignored_conntrack
1802 + && ip_ct_tuple_equal(tuple, &i->tuple);
1805 +static struct ip_conntrack_tuple_hash *
1806 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
1807 + const struct ip_conntrack *ignored_conntrack)
1809 + struct ip_conntrack_tuple_hash *h;
1810 + unsigned int hash = hash_conntrack(tuple);
1812 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1813 + h = LIST_FIND(&ip_conntrack_hash[hash],
1814 + conntrack_tuple_cmp,
1815 + struct ip_conntrack_tuple_hash *,
1816 + tuple, ignored_conntrack);
1820 +/* Find a connection corresponding to a tuple. */
1821 +struct ip_conntrack_tuple_hash *
1822 +ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
1823 + const struct ip_conntrack *ignored_conntrack)
1825 + struct ip_conntrack_tuple_hash *h;
1827 + READ_LOCK(&ip_conntrack_lock);
1828 + h = __ip_conntrack_find(tuple, ignored_conntrack);
1830 + atomic_inc(&h->ctrack->ct_general.use);
1831 + READ_UNLOCK(&ip_conntrack_lock);
1836 +static inline struct ip_conntrack *
1837 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
1839 + struct ip_conntrack *ct
1840 + = (struct ip_conntrack *)nfct->master;
1842 + /* ctinfo is the index of the nfct inside the conntrack */
1843 + *ctinfo = nfct - ct->infos;
1844 + IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
1848 +/* Return conntrack and conntrack_info given skb->nfct->master */
1849 +struct ip_conntrack *
1850 +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
1853 + return __ip_conntrack_get(skb->nfct, ctinfo);
1857 +/* Confirm a connection given skb->nfct; places it in hash table */
1859 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
1861 + unsigned int hash, repl_hash;
1862 + struct ip_conntrack *ct;
1863 + enum ip_conntrack_info ctinfo;
1865 + ct = __ip_conntrack_get(nfct, &ctinfo);
1867 + /* ipt_REJECT uses ip_conntrack_attach to attach related
1868 + ICMP/TCP RST packets in other direction. Actual packet
1869 + which created connection will be IP_CT_NEW or for an
1870 + expected connection, IP_CT_RELATED. */
1871 + if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
1874 + hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1875 + repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
1877 + /* We're not in hash table, and we refuse to set up related
1878 + connections for unconfirmed conns. But packet copies and
1879 + REJECT will give spurious warnings here. */
1880 + /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
1882 + /* No external references means noone else could have
1884 + IP_NF_ASSERT(!is_confirmed(ct));
1885 + DEBUGP("Confirming conntrack %p\n", ct);
1887 + WRITE_LOCK(&ip_conntrack_lock);
1888 + /* See if there's one in the list already, including reverse:
1889 + NAT could have grabbed it without realizing, since we're
1890 + not in the hash. If there is, we lost race. */
1891 + if (!LIST_FIND(&ip_conntrack_hash[hash],
1892 + conntrack_tuple_cmp,
1893 + struct ip_conntrack_tuple_hash *,
1894 + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
1895 + && !LIST_FIND(&ip_conntrack_hash[repl_hash],
1896 + conntrack_tuple_cmp,
1897 + struct ip_conntrack_tuple_hash *,
1898 + &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
1899 + list_prepend(&ip_conntrack_hash[hash],
1900 + &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
1901 + list_prepend(&ip_conntrack_hash[repl_hash],
1902 + &ct->tuplehash[IP_CT_DIR_REPLY]);
1903 + /* Timer relative to confirmation time, not original
1904 + setting time, otherwise we'd get timer wrap in
1905 + weird delay cases. */
1906 + ct->timeout.expires += jiffies;
1907 + add_timer(&ct->timeout);
1908 + atomic_inc(&ct->ct_general.use);
1909 + set_bit(IPS_CONFIRMED_BIT, &ct->status);
1910 + WRITE_UNLOCK(&ip_conntrack_lock);
1914 + WRITE_UNLOCK(&ip_conntrack_lock);
1918 +/* Returns true if a connection correspondings to the tuple (required
1921 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
1922 + const struct ip_conntrack *ignored_conntrack)
1924 + struct ip_conntrack_tuple_hash *h;
1926 + READ_LOCK(&ip_conntrack_lock);
1927 + h = __ip_conntrack_find(tuple, ignored_conntrack);
1928 + READ_UNLOCK(&ip_conntrack_lock);
1933 +/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
1934 +struct ip_conntrack *
1935 +icmp_error_track(struct sk_buff *skb,
1936 + enum ip_conntrack_info *ctinfo,
1937 + unsigned int hooknum)
1939 + struct ip_conntrack_tuple innertuple, origtuple;
1941 + struct icmphdr icmp;
1944 + struct ip_conntrack_protocol *innerproto;
1945 + struct ip_conntrack_tuple_hash *h;
1948 + IP_NF_ASSERT(skb->nfct == NULL);
1950 + /* Not enough header? */
1951 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
1954 + if (inside.icmp.type != ICMP_DEST_UNREACH
1955 + && inside.icmp.type != ICMP_SOURCE_QUENCH
1956 + && inside.icmp.type != ICMP_TIME_EXCEEDED
1957 + && inside.icmp.type != ICMP_PARAMETERPROB
1958 + && inside.icmp.type != ICMP_REDIRECT)
1961 + /* Ignore ICMP's containing fragments (shouldn't happen) */
1962 + if (inside.ip.frag_off & htons(IP_OFFSET)) {
1963 + DEBUGP("icmp_error_track: fragment of proto %u\n",
1964 + inside.ip.protocol);
1968 + innerproto = ip_ct_find_proto(inside.ip.protocol);
1969 + dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
1970 + /* Are they talking about one of our connections? */
1971 + if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
1972 + DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
1976 + /* Ordinarily, we'd expect the inverted tupleproto, but it's
1977 + been preserved inside the ICMP. */
1978 + if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
1979 + DEBUGP("icmp_error_track: Can't invert tuple\n");
1983 + *ctinfo = IP_CT_RELATED;
1985 + h = ip_conntrack_find_get(&innertuple, NULL);
1987 + /* Locally generated ICMPs will match inverted if they
1988 + haven't been SNAT'ed yet */
1989 + /* FIXME: NAT code has to handle half-done double NAT --RR */
1990 + if (hooknum == NF_IP_LOCAL_OUT)
1991 + h = ip_conntrack_find_get(&origtuple, NULL);
1994 + DEBUGP("icmp_error_track: no match\n");
1997 + /* Reverse direction from that found */
1998 + if (DIRECTION(h) != IP_CT_DIR_REPLY)
1999 + *ctinfo += IP_CT_IS_REPLY;
2001 + if (DIRECTION(h) == IP_CT_DIR_REPLY)
2002 + *ctinfo += IP_CT_IS_REPLY;
2005 + /* Update skb to refer to this connection */
2006 + skb->nfct = &h->ctrack->infos[*ctinfo];
2010 +/* There's a small race here where we may free a just-assured
2011 + connection. Too bad: we're in trouble anyway. */
2012 +static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
2014 + return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
2017 +static int early_drop(struct list_head *chain)
2019 + /* Traverse backwards: gives us oldest, which is roughly LRU */
2020 + struct ip_conntrack_tuple_hash *h;
2023 + READ_LOCK(&ip_conntrack_lock);
2024 + h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
2026 + atomic_inc(&h->ctrack->ct_general.use);
2027 + READ_UNLOCK(&ip_conntrack_lock);
2032 + if (del_timer(&h->ctrack->timeout)) {
2033 + death_by_timeout((unsigned long)h->ctrack);
2036 + ip_conntrack_put(h->ctrack);
2040 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
2041 + const struct ip_conntrack_tuple *rtuple)
2043 + return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
2046 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
2048 + return LIST_FIND(&helpers, helper_cmp,
2049 + struct ip_conntrack_helper *,
2053 +/* Allocate a new conntrack: we return -ENOMEM if classification
2054 + failed due to stress. Otherwise it really is unclassifiable. */
2055 +static struct ip_conntrack_tuple_hash *
2056 +init_conntrack(const struct ip_conntrack_tuple *tuple,
2057 + struct ip_conntrack_protocol *protocol,
2058 + struct sk_buff *skb)
2060 + struct ip_conntrack *conntrack;
2061 + struct ip_conntrack_tuple repl_tuple;
2063 + struct ip_conntrack_expect *expected;
2065 + static unsigned int drop_next;
2067 + if (!ip_conntrack_hash_rnd_initted) {
2068 + get_random_bytes(&ip_conntrack_hash_rnd, 4);
2069 + ip_conntrack_hash_rnd_initted = 1;
2072 + hash = hash_conntrack(tuple);
2074 + if (ip_conntrack_max &&
2075 + atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
2076 + /* Try dropping from random chain, or else from the
2077 + chain about to put into (in case they're trying to
2078 + bomb one hash chain). */
2079 + unsigned int next = (drop_next++)%ip_conntrack_htable_size;
2081 + if (!early_drop(&ip_conntrack_hash[next])
2082 + && !early_drop(&ip_conntrack_hash[hash])) {
2083 + if (net_ratelimit())
2084 + printk(KERN_WARNING
2085 + "ip_conntrack: table full, dropping"
2087 + return ERR_PTR(-ENOMEM);
2091 + if (!invert_tuple(&repl_tuple, tuple, protocol)) {
2092 + DEBUGP("Can't invert tuple.\n");
2096 + conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
2098 + DEBUGP("Can't allocate conntrack.\n");
2099 + return ERR_PTR(-ENOMEM);
2102 + memset(conntrack, 0, sizeof(*conntrack));
2103 + atomic_set(&conntrack->ct_general.use, 1);
2104 + conntrack->ct_general.destroy = destroy_conntrack;
2105 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
2106 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
2107 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
2108 + conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
2109 + for (i=0; i < IP_CT_NUMBER; i++)
2110 + conntrack->infos[i].master = &conntrack->ct_general;
2112 + if (!protocol->new(conntrack, skb)) {
2113 + kmem_cache_free(ip_conntrack_cachep, conntrack);
2116 + /* Don't set timer yet: wait for confirmation */
2117 + init_timer(&conntrack->timeout);
2118 + conntrack->timeout.data = (unsigned long)conntrack;
2119 + conntrack->timeout.function = death_by_timeout;
2121 + INIT_LIST_HEAD(&conntrack->sibling_list);
2123 + WRITE_LOCK(&ip_conntrack_lock);
2124 + /* Need finding and deleting of expected ONLY if we win race */
2125 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
2126 + expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
2127 + struct ip_conntrack_expect *, tuple);
2128 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2130 + /* If master is not in hash table yet (ie. packet hasn't left
2131 + this machine yet), how can other end know about expected?
2132 + Hence these are not the droids you are looking for (if
2133 + master ct never got confirmed, we'd hold a reference to it
2134 + and weird things would happen to future packets). */
2135 + if (expected && !is_confirmed(expected->expectant))
2138 + /* Look up the conntrack helper for master connections only */
2140 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
2142 + /* If the expectation is dying, then this is a loser. */
2144 + && expected->expectant->helper->timeout
2145 + && ! del_timer(&expected->timeout))
2149 + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
2150 + conntrack, expected);
2151 + /* Welcome, Mr. Bond. We've been expecting you... */
2152 + IP_NF_ASSERT(master_ct(conntrack));
2153 + __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
2154 + conntrack->master = expected;
2155 + expected->sibling = conntrack;
2156 + LIST_DELETE(&ip_conntrack_expect_list, expected);
2157 + expected->expectant->expecting--;
2158 + nf_conntrack_get(&master_ct(conntrack)->infos[0]);
2160 + atomic_inc(&ip_conntrack_count);
2161 + WRITE_UNLOCK(&ip_conntrack_lock);
2163 + if (expected && expected->expectfn)
2164 + expected->expectfn(conntrack);
2165 + return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
2168 +/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
2169 +static inline struct ip_conntrack *
2170 +resolve_normal_ct(struct sk_buff *skb,
2171 + struct ip_conntrack_protocol *proto,
2173 + unsigned int hooknum,
2174 + enum ip_conntrack_info *ctinfo)
2176 + struct ip_conntrack_tuple tuple;
2177 + struct ip_conntrack_tuple_hash *h;
2179 + IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
2181 + if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
2184 + /* look for tuple match */
2185 + h = ip_conntrack_find_get(&tuple, NULL);
2187 + h = init_conntrack(&tuple, proto, skb);
2194 + /* It exists; we have (non-exclusive) reference. */
2195 + if (DIRECTION(h) == IP_CT_DIR_REPLY) {
2196 + *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
2197 + /* Please set reply bit if this packet OK */
2200 + /* Once we've had two way comms, always ESTABLISHED. */
2201 + if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
2202 + DEBUGP("ip_conntrack_in: normal packet for %p\n",
2204 + *ctinfo = IP_CT_ESTABLISHED;
2205 + } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
2206 + DEBUGP("ip_conntrack_in: related packet for %p\n",
2208 + *ctinfo = IP_CT_RELATED;
2210 + DEBUGP("ip_conntrack_in: new packet for %p\n",
2212 + *ctinfo = IP_CT_NEW;
2216 + skb->nfct = &h->ctrack->infos[*ctinfo];
2220 +/* Netfilter hook itself. */
2221 +unsigned int ip_conntrack_in(unsigned int hooknum,
2222 + struct sk_buff **pskb,
2223 + const struct net_device *in,
2224 + const struct net_device *out,
2225 + int (*okfn)(struct sk_buff *))
2227 + struct ip_conntrack *ct;
2228 + enum ip_conntrack_info ctinfo;
2229 + struct ip_conntrack_protocol *proto;
2233 + /* FIXME: Do this right please. --RR */
2234 + (*pskb)->nfcache |= NFC_UNKNOWN;
2236 +/* Doesn't cover locally-generated broadcast, so not worth it. */
2238 + /* Ignore broadcast: no `connection'. */
2239 + if ((*pskb)->pkt_type == PACKET_BROADCAST) {
2240 + printk("Broadcast packet!\n");
2242 + } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
2243 + == htonl(0x000000FF)) {
2244 + printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
2245 + NIPQUAD((*pskb)->nh.iph->saddr),
2246 + NIPQUAD((*pskb)->nh.iph->daddr),
2247 + (*pskb)->sk, (*pskb)->pkt_type);
2251 + /* Previously seen (loopback)? Ignore. Do this before
2252 + fragment check. */
2253 + if ((*pskb)->nfct)
2256 + /* Gather fragments. */
2257 + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
2258 + *pskb = ip_ct_gather_frags(*pskb);
2263 + proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2265 + /* It may be an icmp error... */
2266 + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
2267 + && icmp_error_track(*pskb, &ctinfo, hooknum))
2270 + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
2271 + /* Not valid part of a connection */
2275 + /* Too stressed to deal. */
2278 + IP_NF_ASSERT((*pskb)->nfct);
2280 + ret = proto->packet(ct, *pskb, ctinfo);
2283 + nf_conntrack_put((*pskb)->nfct);
2284 + (*pskb)->nfct = NULL;
2288 + if (ret != NF_DROP && ct->helper) {
2289 + ret = ct->helper->help(*pskb, ct, ctinfo);
2292 + nf_conntrack_put((*pskb)->nfct);
2293 + (*pskb)->nfct = NULL;
2298 + set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
2303 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
2304 + const struct ip_conntrack_tuple *orig)
2306 + return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
2309 +static inline int resent_expect(const struct ip_conntrack_expect *i,
2310 + const struct ip_conntrack_tuple *tuple,
2311 + const struct ip_conntrack_tuple *mask)
2313 + DEBUGP("resent_expect\n");
2314 + DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
2315 + DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
2316 + DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
2317 + return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
2318 + || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
2319 + && ip_ct_tuple_equal(&i->mask, mask));
2322 +/* Would two expected things clash? */
2323 +static inline int expect_clash(const struct ip_conntrack_expect *i,
2324 + const struct ip_conntrack_tuple *tuple,
2325 + const struct ip_conntrack_tuple *mask)
2327 + /* Part covered by intersection of masks must be unequal,
2328 + otherwise they clash */
2329 + struct ip_conntrack_tuple intersect_mask
2330 + = { { i->mask.src.ip & mask->src.ip,
2331 + { i->mask.src.u.all & mask->src.u.all } },
2332 + { i->mask.dst.ip & mask->dst.ip,
2333 + { i->mask.dst.u.all & mask->dst.u.all },
2334 + i->mask.dst.protonum & mask->dst.protonum } };
2336 + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
2339 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
2341 + WRITE_LOCK(&ip_conntrack_lock);
2342 + unexpect_related(expect);
2343 + WRITE_UNLOCK(&ip_conntrack_lock);
2346 +static void expectation_timed_out(unsigned long ul_expect)
2348 + struct ip_conntrack_expect *expect = (void *) ul_expect;
2350 + DEBUGP("expectation %p timed out\n", expect);
2351 + WRITE_LOCK(&ip_conntrack_lock);
2352 + __unexpect_related(expect);
2353 + WRITE_UNLOCK(&ip_conntrack_lock);
2356 +/* Add a related connection. */
2357 +int ip_conntrack_expect_related(struct ip_conntrack *related_to,
2358 + struct ip_conntrack_expect *expect)
2360 + struct ip_conntrack_expect *old, *new;
2363 + WRITE_LOCK(&ip_conntrack_lock);
2364 + /* Because of the write lock, no reader can walk the lists,
2365 + * so there is no need to use the tuple lock too */
2367 + DEBUGP("ip_conntrack_expect_related %p\n", related_to);
2368 + DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
2369 + DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
2371 + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
2372 + struct ip_conntrack_expect *, &expect->tuple,
2375 + /* Helper private data may contain offsets but no pointers
2376 + pointing into the payload - otherwise we should have to copy
2377 + the data filled out by the helper over the old one */
2378 + DEBUGP("expect_related: resent packet\n");
2379 + if (related_to->helper->timeout) {
2380 + if (!del_timer(&old->timeout)) {
2381 + /* expectation is dying. Fall through */
2384 + old->timeout.expires = jiffies +
2385 + related_to->helper->timeout * HZ;
2386 + add_timer(&old->timeout);
2391 + WRITE_UNLOCK(&ip_conntrack_lock);
2394 + } else if (related_to->helper->max_expected &&
2395 + related_to->expecting >= related_to->helper->max_expected) {
2396 + struct list_head *cur_item;
2398 + if (!(related_to->helper->flags &
2399 + IP_CT_HELPER_F_REUSE_EXPECT)) {
2400 + WRITE_UNLOCK(&ip_conntrack_lock);
2401 + if (net_ratelimit())
2402 + printk(KERN_WARNING
2403 + "ip_conntrack: max number of expected "
2404 + "connections %i of %s reached for "
2405 + "%u.%u.%u.%u->%u.%u.%u.%u\n",
2406 + related_to->helper->max_expected,
2407 + related_to->helper->name,
2408 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
2409 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
2412 + DEBUGP("ip_conntrack: max number of expected "
2413 + "connections %i of %s reached for "
2414 + "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
2415 + related_to->helper->max_expected,
2416 + related_to->helper->name,
2417 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
2418 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
2420 + /* choose the the oldest expectation to evict */
2421 + list_for_each(cur_item, &related_to->sibling_list) {
2422 + struct ip_conntrack_expect *cur;
2424 + cur = list_entry(cur_item,
2425 + struct ip_conntrack_expect,
2427 + if (cur->sibling == NULL) {
2433 + /* (!old) cannot happen, since related_to->expecting is the
2434 + * number of unconfirmed expects */
2435 + IP_NF_ASSERT(old);
2437 + /* newnat14 does not reuse the real allocated memory
2438 + * structures but rather unexpects the old and
2439 + * allocates a new. unexpect_related will decrement
2440 + * related_to->expecting.
2442 + unexpect_related(old);
2444 + } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
2445 + struct ip_conntrack_expect *, &expect->tuple,
2447 + WRITE_UNLOCK(&ip_conntrack_lock);
2448 + DEBUGP("expect_related: busy!\n");
2452 + new = (struct ip_conntrack_expect *)
2453 + kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
2455 + WRITE_UNLOCK(&ip_conntrack_lock);
2456 + DEBUGP("expect_relaed: OOM allocating expect\n");
2460 + DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
2461 + memcpy(new, expect, sizeof(*expect));
2462 + new->expectant = related_to;
2463 + new->sibling = NULL;
2464 + atomic_set(&new->use, 1);
2466 + /* add to expected list for this connection */
2467 + list_add(&new->expected_list, &related_to->sibling_list);
2468 + /* add to global list of expectations */
2469 + list_prepend(&ip_conntrack_expect_list, &new->list);
2470 + /* add and start timer if required */
2471 + if (related_to->helper->timeout) {
2472 + init_timer(&new->timeout);
2473 + new->timeout.data = (unsigned long)new;
2474 + new->timeout.function = expectation_timed_out;
2475 + new->timeout.expires = jiffies +
2476 + related_to->helper->timeout * HZ;
2477 + add_timer(&new->timeout);
2479 + related_to->expecting++;
2481 + WRITE_UNLOCK(&ip_conntrack_lock);
2486 +/* Change tuple in an existing expectation */
2487 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
2488 + struct ip_conntrack_tuple *newtuple)
2492 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2493 + WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
2495 + DEBUGP("change_expect:\n");
2496 + DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
2497 + DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
2498 + DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
2499 + if (expect->ct_tuple.dst.protonum == 0) {
2500 + /* Never seen before */
2501 + DEBUGP("change expect: never seen before\n");
2502 + if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
2503 + && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
2504 + struct ip_conntrack_expect *, newtuple, &expect->mask)) {
2505 + /* Force NAT to find an unused tuple */
2508 + memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
2509 + memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
2513 + /* Resent packet */
2514 + DEBUGP("change expect: resent packet\n");
2515 + if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
2518 + /* Force NAT to choose again the same port */
2522 + WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
2527 +/* Alter reply tuple (maybe alter helper). If it's already taken,
2528 + return 0 and don't do alteration. */
2529 +int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
2530 + const struct ip_conntrack_tuple *newreply)
2532 + WRITE_LOCK(&ip_conntrack_lock);
2533 + if (__ip_conntrack_find(newreply, conntrack)) {
2534 + WRITE_UNLOCK(&ip_conntrack_lock);
2537 + /* Should be unconfirmed, so not in hash table yet */
2538 + IP_NF_ASSERT(!is_confirmed(conntrack));
2540 + DEBUGP("Altering reply tuple of %p to ", conntrack);
2541 + DUMP_TUPLE(newreply);
2543 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
2544 + if (!conntrack->master)
2545 + conntrack->helper = LIST_FIND(&helpers, helper_cmp,
2546 + struct ip_conntrack_helper *,
2548 + WRITE_UNLOCK(&ip_conntrack_lock);
2553 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
2555 + WRITE_LOCK(&ip_conntrack_lock);
2556 + list_prepend(&helpers, me);
2557 + WRITE_UNLOCK(&ip_conntrack_lock);
2562 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
2563 + const struct ip_conntrack_helper *me)
2565 + if (i->ctrack->helper == me) {
2566 + /* Get rid of any expected. */
2567 + remove_expectations(i->ctrack, 0);
2568 + /* And *then* set helper to NULL */
2569 + i->ctrack->helper = NULL;
2574 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
2578 + /* Need write lock here, to delete helper. */
2579 + WRITE_LOCK(&ip_conntrack_lock);
2580 + LIST_DELETE(&helpers, me);
2582 + /* Get rid of expecteds, set helpers to NULL. */
2583 + for (i = 0; i < ip_conntrack_htable_size; i++)
2584 + LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
2585 + struct ip_conntrack_tuple_hash *, me);
2586 + WRITE_UNLOCK(&ip_conntrack_lock);
2588 + /* Someone could be still looking at the helper in a bh. */
2589 + synchronize_net();
2592 +/* Refresh conntrack for this many jiffies. */
2593 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
2595 + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
2597 + WRITE_LOCK(&ip_conntrack_lock);
2598 + /* If not in hash table, timer will not be active yet */
2599 + if (!is_confirmed(ct))
2600 + ct->timeout.expires = extra_jiffies;
2602 + /* Need del_timer for race avoidance (may already be dying). */
2603 + if (del_timer(&ct->timeout)) {
2604 + ct->timeout.expires = jiffies + extra_jiffies;
2605 + add_timer(&ct->timeout);
2608 + WRITE_UNLOCK(&ip_conntrack_lock);
2611 +/* Returns new sk_buff, or NULL */
2613 +ip_ct_gather_frags(struct sk_buff *skb)
2615 + struct sock *sk = skb->sk;
2616 +#ifdef CONFIG_NETFILTER_DEBUG
2617 + unsigned int olddebug = skb->nf_debug;
2624 + local_bh_disable();
2625 + skb = ip_defrag(skb);
2626 + local_bh_enable();
2635 + skb_set_owner_w(skb, sk);
2639 + ip_send_check(skb->nh.iph);
2640 + skb->nfcache |= NFC_ALTERED;
2641 +#ifdef CONFIG_NETFILTER_DEBUG
2642 + /* Packet path as if nothing had happened. */
2643 + skb->nf_debug = olddebug;
2648 +/* Used by ipt_REJECT. */
2649 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
2651 + struct ip_conntrack *ct;
2652 + enum ip_conntrack_info ctinfo;
2654 + ct = __ip_conntrack_get(nfct, &ctinfo);
2656 + /* This ICMP is in reverse direction to the packet which
2658 + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
2659 + ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
2661 + ctinfo = IP_CT_RELATED;
2663 + /* Attach new skbuff, and increment count */
2664 + nskb->nfct = &ct->infos[ctinfo];
2665 + atomic_inc(&ct->ct_general.use);
2669 +do_kill(const struct ip_conntrack_tuple_hash *i,
2670 + int (*kill)(const struct ip_conntrack *i, void *data),
2673 + return kill(i->ctrack, data);
2676 +/* Bring out ya dead! */
2677 +static struct ip_conntrack_tuple_hash *
2678 +get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
2679 + void *data, unsigned int *bucket)
2681 + struct ip_conntrack_tuple_hash *h = NULL;
2683 + READ_LOCK(&ip_conntrack_lock);
2684 + for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
2685 + h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
2686 + struct ip_conntrack_tuple_hash *, kill, data);
2689 + atomic_inc(&h->ctrack->ct_general.use);
2690 + READ_UNLOCK(&ip_conntrack_lock);
2696 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
2699 + struct ip_conntrack_tuple_hash *h;
2700 + unsigned int bucket = 0;
2702 + while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
2703 + /* Time to push up daises... */
2704 + if (del_timer(&h->ctrack->timeout))
2705 + death_by_timeout((unsigned long)h->ctrack);
2706 + /* ... else the timer will get him soon. */
2708 + ip_conntrack_put(h->ctrack);
2712 +/* Fast function for those who don't want to parse /proc (and I don't
2714 +/* Reversing the socket's dst/src point of view gives us the reply
2717 +getorigdst(struct sock *sk, int optval, void *user, int *len)
2719 + struct inet_opt *inet = inet_sk(sk);
2720 + struct ip_conntrack_tuple_hash *h;
2721 + struct ip_conntrack_tuple tuple;
2723 + IP_CT_TUPLE_U_BLANK(&tuple);
2724 + tuple.src.ip = inet->rcv_saddr;
2725 + tuple.src.u.tcp.port = inet->sport;
2726 + tuple.dst.ip = inet->daddr;
2727 + tuple.dst.u.tcp.port = inet->dport;
2728 + tuple.dst.protonum = IPPROTO_TCP;
2730 + /* We only do TCP at the moment: is there a better way? */
2731 + if (strcmp(sk->sk_prot->name, "TCP")) {
2732 + DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
2733 + return -ENOPROTOOPT;
2736 + if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
2737 + DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
2738 + *len, sizeof(struct sockaddr_in));
2742 + h = ip_conntrack_find_get(&tuple, NULL);
2744 + struct sockaddr_in sin;
2746 + sin.sin_family = AF_INET;
2747 + sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
2748 + .tuple.dst.u.tcp.port;
2749 + sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
2752 + DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
2753 + NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
2754 + ip_conntrack_put(h->ctrack);
2755 + if (copy_to_user(user, &sin, sizeof(sin)) != 0)
2760 + DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
2761 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
2762 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
2766 +static struct nf_sockopt_ops so_getorigdst = {
2768 + .get_optmin = SO_ORIGINAL_DST,
2769 + .get_optmax = SO_ORIGINAL_DST+1,
2770 + .get = &getorigdst,
2773 +static int kill_all(const struct ip_conntrack *i, void *data)
2778 +/* Mishearing the voices in his head, our hero wonders how he's
2779 + supposed to kill the mall. */
2780 +void ip_conntrack_cleanup(void)
2782 + ip_ct_attach = NULL;
2783 + /* This makes sure all current packets have passed through
2784 + netfilter framework. Roll on, two-stage module
2786 + synchronize_net();
2788 + i_see_dead_people:
2789 + ip_ct_selective_cleanup(kill_all, NULL);
2790 + if (atomic_read(&ip_conntrack_count) != 0) {
2792 + goto i_see_dead_people;
2795 + kmem_cache_destroy(ip_conntrack_cachep);
2796 + vfree(ip_conntrack_hash);
2797 + nf_unregister_sockopt(&so_getorigdst);
2800 +static int hashsize;
2801 +MODULE_PARM(hashsize, "i");
2803 +int __init ip_conntrack_init(void)
2808 + /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
2809 + * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
2811 + ip_conntrack_htable_size = hashsize;
2813 + ip_conntrack_htable_size
2814 + = (((num_physpages << PAGE_SHIFT) / 16384)
2815 + / sizeof(struct list_head));
2816 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
2817 + ip_conntrack_htable_size = 8192;
2818 + if (ip_conntrack_htable_size < 16)
2819 + ip_conntrack_htable_size = 16;
2821 + ip_conntrack_max = 8 * ip_conntrack_htable_size;
2823 + printk("ip_conntrack version %s (%u buckets, %d max)"
2824 + " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
2825 + ip_conntrack_htable_size, ip_conntrack_max,
2826 + sizeof(struct ip_conntrack));
2828 + ret = nf_register_sockopt(&so_getorigdst);
2830 + printk(KERN_ERR "Unable to register netfilter socket option\n");
2834 + ip_conntrack_hash = vmalloc(sizeof(struct list_head)
2835 + * ip_conntrack_htable_size);
2836 + if (!ip_conntrack_hash) {
2837 + printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
2838 + goto err_unreg_sockopt;
2841 + ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
2842 + sizeof(struct ip_conntrack), 0,
2843 + SLAB_HWCACHE_ALIGN, NULL, NULL);
2844 + if (!ip_conntrack_cachep) {
2845 + printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
2846 + goto err_free_hash;
2848 + /* Don't NEED lock here, but good form anyway. */
2849 + WRITE_LOCK(&ip_conntrack_lock);
2850 + /* Sew in builtin protocols. */
2851 + list_append(&protocol_list, &ip_conntrack_protocol_tcp);
2852 + list_append(&protocol_list, &ip_conntrack_protocol_udp);
2853 + list_append(&protocol_list, &ip_conntrack_protocol_icmp);
2854 + WRITE_UNLOCK(&ip_conntrack_lock);
2856 + for (i = 0; i < ip_conntrack_htable_size; i++)
2857 + INIT_LIST_HEAD(&ip_conntrack_hash[i]);
2859 + /* For use by ipt_REJECT */
2860 + ip_ct_attach = ip_conntrack_attach;
2864 + vfree(ip_conntrack_hash);
2866 + nf_unregister_sockopt(&so_getorigdst);
2870 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.3/net/ipv4/netfilter/ip_conntrack_standalone.c
2871 --- linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-02-26 23:36:59.000000000 +0100
2872 +++ linux-2.6.3/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-02-27 00:03:14.482026576 +0100
2873 @@ -194,6 +194,26 @@
2874 return ip_conntrack_confirm(*pskb);
2877 +static unsigned int ip_conntrack_defrag(unsigned int hooknum,
2878 + struct sk_buff **pskb,
2879 + const struct net_device *in,
2880 + const struct net_device *out,
2881 + int (*okfn)(struct sk_buff *))
2883 + /* Previously seen (loopback)? Ignore. Do this before
2884 + fragment check. */
2885 + if ((*pskb)->nfct)
2888 + /* Gather fragments. */
2889 + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
2890 + *pskb = ip_ct_gather_frags(*pskb);
2897 static unsigned int ip_refrag(unsigned int hooknum,
2898 struct sk_buff **pskb,
2899 const struct net_device *in,
2900 @@ -236,6 +256,14 @@
2902 /* Connection tracking may drop packets, but never alters them, so
2903 make it the first hook. */
2904 +static struct nf_hook_ops ip_conntrack_defrag_ops = {
2905 + .hook = ip_conntrack_defrag,
2906 + .owner = THIS_MODULE,
2908 + .hooknum = NF_IP_PRE_ROUTING,
2909 + .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
2912 static struct nf_hook_ops ip_conntrack_in_ops = {
2913 .hook = ip_conntrack_in,
2914 .owner = THIS_MODULE,
2915 @@ -244,6 +272,14 @@
2916 .priority = NF_IP_PRI_CONNTRACK,
2919 +static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = {
2920 + .hook = ip_conntrack_defrag,
2921 + .owner = THIS_MODULE,
2923 + .hooknum = NF_IP_LOCAL_OUT,
2924 + .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
2927 static struct nf_hook_ops ip_conntrack_local_out_ops = {
2928 .hook = ip_conntrack_local,
2929 .owner = THIS_MODULE,
2930 @@ -470,10 +506,20 @@
2931 if (!proc) goto cleanup_init;
2932 proc->owner = THIS_MODULE;
2934 + ret = nf_register_hook(&ip_conntrack_defrag_ops);
2936 + printk("ip_conntrack: can't register pre-routing defrag hook.\n");
2937 + goto cleanup_proc;
2939 + ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
2941 + printk("ip_conntrack: can't register local_out defrag hook.\n");
2942 + goto cleanup_defragops;
2944 ret = nf_register_hook(&ip_conntrack_in_ops);
2946 printk("ip_conntrack: can't register pre-routing hook.\n");
2947 - goto cleanup_proc;
2948 + goto cleanup_defraglocalops;
2950 ret = nf_register_hook(&ip_conntrack_local_out_ops);
2952 @@ -511,6 +557,10 @@
2953 nf_unregister_hook(&ip_conntrack_local_out_ops);
2955 nf_unregister_hook(&ip_conntrack_in_ops);
2956 + cleanup_defraglocalops:
2957 + nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
2958 + cleanup_defragops:
2959 + nf_unregister_hook(&ip_conntrack_defrag_ops);
2961 proc_net_remove("ip_conntrack");
2964 EXPORT_SYMBOL(ip_conntrack_expect_list);
2965 EXPORT_SYMBOL(ip_conntrack_lock);
2966 EXPORT_SYMBOL(ip_conntrack_hash);
2967 +EXPORT_SYMBOL(ip_conntrack_untracked);
2968 EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
2969 EXPORT_SYMBOL_GPL(ip_conntrack_put);
2970 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig linux-2.6.3/net/ipv4/netfilter/ip_conntrack_standalone.c.orig
2971 --- linux-2.6.3.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 1970-01-01 01:00:00.000000000 +0100
2972 +++ linux-2.6.3/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 2004-02-27 00:02:49.321851504 +0100
2974 +/* This file contains all the functions required for the standalone
2975 + ip_conntrack module.
2977 + These are not required by the compatibility layer.
2980 +/* (C) 1999-2001 Paul `Rusty' Russell
2981 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
2983 + * This program is free software; you can redistribute it and/or modify
2984 + * it under the terms of the GNU General Public License version 2 as
2985 + * published by the Free Software Foundation.
2988 +#include <linux/config.h>
2989 +#include <linux/types.h>
2990 +#include <linux/ip.h>
2991 +#include <linux/netfilter.h>
2992 +#include <linux/netfilter_ipv4.h>
2993 +#include <linux/module.h>
2994 +#include <linux/skbuff.h>
2995 +#include <linux/proc_fs.h>
2996 +#ifdef CONFIG_SYSCTL
2997 +#include <linux/sysctl.h>
2999 +#include <net/checksum.h>
3001 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
3002 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
3004 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3005 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
3006 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3007 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
3008 +#include <linux/netfilter_ipv4/listhelp.h>
3011 +#define DEBUGP printk
3013 +#define DEBUGP(format, args...)
3016 +MODULE_LICENSE("GPL");
3018 +static int kill_proto(const struct ip_conntrack *i, void *data)
3020 + return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
3021 + *((u_int8_t *) data));
3024 +static unsigned int
3025 +print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple,
3026 + struct ip_conntrack_protocol *proto)
3030 + len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
3031 + NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
3033 + len += proto->print_tuple(buffer + len, tuple);
3038 +/* FIXME: Don't print source proto part. --RR */
3039 +static unsigned int
3040 +print_expect(char *buffer, const struct ip_conntrack_expect *expect)
3044 + if (expect->expectant->helper->timeout)
3045 + len = sprintf(buffer, "EXPECTING: %lu ",
3046 + timer_pending(&expect->timeout)
3047 + ? (expect->timeout.expires - jiffies)/HZ : 0);
3049 + len = sprintf(buffer, "EXPECTING: - ");
3050 + len += sprintf(buffer + len, "use=%u proto=%u ",
3051 + atomic_read(&expect->use), expect->tuple.dst.protonum);
3052 + len += print_tuple(buffer + len, &expect->tuple,
3053 + __ip_ct_find_proto(expect->tuple.dst.protonum));
3054 + len += sprintf(buffer + len, "\n");
3058 +static unsigned int
3059 +print_conntrack(char *buffer, struct ip_conntrack *conntrack)
3062 + struct ip_conntrack_protocol *proto
3063 + = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
3064 + .tuple.dst.protonum);
3066 + len = sprintf(buffer, "%-8s %u %lu ",
3068 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
3069 + .tuple.dst.protonum,
3070 + timer_pending(&conntrack->timeout)
3071 + ? (conntrack->timeout.expires - jiffies)/HZ : 0);
3073 + len += proto->print_conntrack(buffer + len, conntrack);
3074 + len += print_tuple(buffer + len,
3075 + &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
3077 + if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
3078 + len += sprintf(buffer + len, "[UNREPLIED] ");
3079 + len += print_tuple(buffer + len,
3080 + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
3082 + if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
3083 + len += sprintf(buffer + len, "[ASSURED] ");
3084 + len += sprintf(buffer + len, "use=%u ",
3085 + atomic_read(&conntrack->ct_general.use));
3086 + len += sprintf(buffer + len, "\n");
3091 +/* Returns true when finished. */
3093 +conntrack_iterate(const struct ip_conntrack_tuple_hash *hash,
3094 + char *buffer, off_t offset, off_t *upto,
3095 + unsigned int *len, unsigned int maxlen)
3097 + unsigned int newlen;
3098 + IP_NF_ASSERT(hash->ctrack);
3100 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3102 + /* Only count originals */
3103 + if (DIRECTION(hash))
3106 + if ((*upto)++ < offset)
3109 + newlen = print_conntrack(buffer + *len, hash->ctrack);
3110 + if (*len + newlen > maxlen)
3112 + else *len += newlen;
3118 +list_conntracks(char *buffer, char **start, off_t offset, int length)
3121 + unsigned int len = 0;
3123 + struct list_head *e;
3125 + READ_LOCK(&ip_conntrack_lock);
3126 + /* Traverse hash; print originals then reply. */
3127 + for (i = 0; i < ip_conntrack_htable_size; i++) {
3128 + if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
3129 + struct ip_conntrack_tuple_hash *,
3130 + buffer, offset, &upto, &len, length))
3134 + /* Now iterate through expecteds. */
3135 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
3136 + list_for_each(e, &ip_conntrack_expect_list) {
3137 + unsigned int last_len;
3138 + struct ip_conntrack_expect *expect
3139 + = (struct ip_conntrack_expect *)e;
3140 + if (upto++ < offset) continue;
3143 + len += print_expect(buffer + len, expect);
3144 + if (len > length) {
3146 + goto finished_expects;
3151 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
3153 + READ_UNLOCK(&ip_conntrack_lock);
3155 + /* `start' hack - see fs/proc/generic.c line ~165 */
3156 + *start = (char *)((unsigned int)upto - offset);
3160 +static unsigned int ip_confirm(unsigned int hooknum,
3161 + struct sk_buff **pskb,
3162 + const struct net_device *in,
3163 + const struct net_device *out,
3164 + int (*okfn)(struct sk_buff *))
3166 + /* We've seen it coming out the other side: confirm it */
3167 + return ip_conntrack_confirm(*pskb);
3170 +static unsigned int ip_refrag(unsigned int hooknum,
3171 + struct sk_buff **pskb,
3172 + const struct net_device *in,
3173 + const struct net_device *out,
3174 + int (*okfn)(struct sk_buff *))
3176 + struct rtable *rt = (struct rtable *)(*pskb)->dst;
3178 + /* We've seen it coming out the other side: confirm */
3179 + if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
3182 + /* Local packets are never produced too large for their
3183 + interface. We degfragment them at LOCAL_OUT, however,
3184 + so we have to refragment them here. */
3185 + if ((*pskb)->len > dst_pmtu(&rt->u.dst) &&
3186 + !skb_shinfo(*pskb)->tso_size) {
3187 + /* No hook can be after us, so this should be OK. */
3188 + ip_fragment(*pskb, okfn);
3194 +static unsigned int ip_conntrack_local(unsigned int hooknum,
3195 + struct sk_buff **pskb,
3196 + const struct net_device *in,
3197 + const struct net_device *out,
3198 + int (*okfn)(struct sk_buff *))
3200 + /* root is playing with raw sockets. */
3201 + if ((*pskb)->len < sizeof(struct iphdr)
3202 + || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
3203 + if (net_ratelimit())
3204 + printk("ipt_hook: happy cracking.\n");
3207 + return ip_conntrack_in(hooknum, pskb, in, out, okfn);
3210 +/* Connection tracking may drop packets, but never alters them, so
3211 + make it the first hook. */
3212 +static struct nf_hook_ops ip_conntrack_in_ops = {
3213 + .hook = ip_conntrack_in,
3214 + .owner = THIS_MODULE,
3216 + .hooknum = NF_IP_PRE_ROUTING,
3217 + .priority = NF_IP_PRI_CONNTRACK,
3220 +static struct nf_hook_ops ip_conntrack_local_out_ops = {
3221 + .hook = ip_conntrack_local,
3222 + .owner = THIS_MODULE,
3224 + .hooknum = NF_IP_LOCAL_OUT,
3225 + .priority = NF_IP_PRI_CONNTRACK,
3228 +/* Refragmenter; last chance. */
3229 +static struct nf_hook_ops ip_conntrack_out_ops = {
3230 + .hook = ip_refrag,
3231 + .owner = THIS_MODULE,
3233 + .hooknum = NF_IP_POST_ROUTING,
3234 + .priority = NF_IP_PRI_LAST,
3237 +static struct nf_hook_ops ip_conntrack_local_in_ops = {
3238 + .hook = ip_confirm,
3239 + .owner = THIS_MODULE,
3241 + .hooknum = NF_IP_LOCAL_IN,
3242 + .priority = NF_IP_PRI_LAST-1,
3245 +/* Sysctl support */
3247 +#ifdef CONFIG_SYSCTL
3249 +/* From ip_conntrack_core.c */
3250 +extern int ip_conntrack_max;
3251 +extern unsigned int ip_conntrack_htable_size;
3253 +/* From ip_conntrack_proto_tcp.c */
3254 +extern unsigned long ip_ct_tcp_timeout_syn_sent;
3255 +extern unsigned long ip_ct_tcp_timeout_syn_recv;
3256 +extern unsigned long ip_ct_tcp_timeout_established;
3257 +extern unsigned long ip_ct_tcp_timeout_fin_wait;
3258 +extern unsigned long ip_ct_tcp_timeout_close_wait;
3259 +extern unsigned long ip_ct_tcp_timeout_last_ack;
3260 +extern unsigned long ip_ct_tcp_timeout_time_wait;
3261 +extern unsigned long ip_ct_tcp_timeout_close;
3263 +/* From ip_conntrack_proto_udp.c */
3264 +extern unsigned long ip_ct_udp_timeout;
3265 +extern unsigned long ip_ct_udp_timeout_stream;
3267 +/* From ip_conntrack_proto_icmp.c */
3268 +extern unsigned long ip_ct_icmp_timeout;
3270 +/* From ip_conntrack_proto_icmp.c */
3271 +extern unsigned long ip_ct_generic_timeout;
3273 +static struct ctl_table_header *ip_ct_sysctl_header;
3275 +static ctl_table ip_ct_sysctl_table[] = {
3277 + .ctl_name = NET_IPV4_NF_CONNTRACK_MAX,
3278 + .procname = "ip_conntrack_max",
3279 + .data = &ip_conntrack_max,
3280 + .maxlen = sizeof(int),
3282 + .proc_handler = &proc_dointvec,
3285 + .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
3286 + .procname = "ip_conntrack_buckets",
3287 + .data = &ip_conntrack_htable_size,
3288 + .maxlen = sizeof(unsigned int),
3290 + .proc_handler = &proc_dointvec,
3293 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
3294 + .procname = "ip_conntrack_tcp_timeout_syn_sent",
3295 + .data = &ip_ct_tcp_timeout_syn_sent,
3296 + .maxlen = sizeof(unsigned int),
3298 + .proc_handler = &proc_dointvec_jiffies,
3301 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
3302 + .procname = "ip_conntrack_tcp_timeout_syn_recv",
3303 + .data = &ip_ct_tcp_timeout_syn_recv,
3304 + .maxlen = sizeof(unsigned int),
3306 + .proc_handler = &proc_dointvec_jiffies,
3309 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
3310 + .procname = "ip_conntrack_tcp_timeout_established",
3311 + .data = &ip_ct_tcp_timeout_established,
3312 + .maxlen = sizeof(unsigned int),
3314 + .proc_handler = &proc_dointvec_jiffies,
3317 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
3318 + .procname = "ip_conntrack_tcp_timeout_fin_wait",
3319 + .data = &ip_ct_tcp_timeout_fin_wait,
3320 + .maxlen = sizeof(unsigned int),
3322 + .proc_handler = &proc_dointvec_jiffies,
3325 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
3326 + .procname = "ip_conntrack_tcp_timeout_close_wait",
3327 + .data = &ip_ct_tcp_timeout_close_wait,
3328 + .maxlen = sizeof(unsigned int),
3330 + .proc_handler = &proc_dointvec_jiffies,
3333 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
3334 + .procname = "ip_conntrack_tcp_timeout_last_ack",
3335 + .data = &ip_ct_tcp_timeout_last_ack,
3336 + .maxlen = sizeof(unsigned int),
3338 + .proc_handler = &proc_dointvec_jiffies,
3341 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
3342 + .procname = "ip_conntrack_tcp_timeout_time_wait",
3343 + .data = &ip_ct_tcp_timeout_time_wait,
3344 + .maxlen = sizeof(unsigned int),
3346 + .proc_handler = &proc_dointvec_jiffies,
3349 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
3350 + .procname = "ip_conntrack_tcp_timeout_close",
3351 + .data = &ip_ct_tcp_timeout_close,
3352 + .maxlen = sizeof(unsigned int),
3354 + .proc_handler = &proc_dointvec_jiffies,
3357 + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,
3358 + .procname = "ip_conntrack_udp_timeout",
3359 + .data = &ip_ct_udp_timeout,
3360 + .maxlen = sizeof(unsigned int),
3362 + .proc_handler = &proc_dointvec_jiffies,
3365 + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
3366 + .procname = "ip_conntrack_udp_timeout_stream",
3367 + .data = &ip_ct_udp_timeout_stream,
3368 + .maxlen = sizeof(unsigned int),
3370 + .proc_handler = &proc_dointvec_jiffies,
3373 + .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
3374 + .procname = "ip_conntrack_icmp_timeout",
3375 + .data = &ip_ct_icmp_timeout,
3376 + .maxlen = sizeof(unsigned int),
3378 + .proc_handler = &proc_dointvec_jiffies,
3381 + .ctl_name = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,
3382 + .procname = "ip_conntrack_generic_timeout",
3383 + .data = &ip_ct_generic_timeout,
3384 + .maxlen = sizeof(unsigned int),
3386 + .proc_handler = &proc_dointvec_jiffies,
3391 +#define NET_IP_CONNTRACK_MAX 2089
3393 +static ctl_table ip_ct_netfilter_table[] = {
3395 + .ctl_name = NET_IPV4_NETFILTER,
3396 + .procname = "netfilter",
3398 + .child = ip_ct_sysctl_table,
3401 + .ctl_name = NET_IP_CONNTRACK_MAX,
3402 + .procname = "ip_conntrack_max",
3403 + .data = &ip_conntrack_max,
3404 + .maxlen = sizeof(int),
3406 + .proc_handler = &proc_dointvec
3411 +static ctl_table ip_ct_ipv4_table[] = {
3413 + .ctl_name = NET_IPV4,
3414 + .procname = "ipv4",
3416 + .child = ip_ct_netfilter_table,
3421 +static ctl_table ip_ct_net_table[] = {
3423 + .ctl_name = CTL_NET,
3424 + .procname = "net",
3426 + .child = ip_ct_ipv4_table,
3431 +static int init_or_cleanup(int init)
3433 + struct proc_dir_entry *proc;
3436 + if (!init) goto cleanup;
3438 + ret = ip_conntrack_init();
3440 + goto cleanup_nothing;
3442 + proc = proc_net_create("ip_conntrack",0,list_conntracks);
3443 + if (!proc) goto cleanup_init;
3444 + proc->owner = THIS_MODULE;
3446 + ret = nf_register_hook(&ip_conntrack_in_ops);
3448 + printk("ip_conntrack: can't register pre-routing hook.\n");
3449 + goto cleanup_proc;
3451 + ret = nf_register_hook(&ip_conntrack_local_out_ops);
3453 + printk("ip_conntrack: can't register local out hook.\n");
3454 + goto cleanup_inops;
3456 + ret = nf_register_hook(&ip_conntrack_out_ops);
3458 + printk("ip_conntrack: can't register post-routing hook.\n");
3459 + goto cleanup_inandlocalops;
3461 + ret = nf_register_hook(&ip_conntrack_local_in_ops);
3463 + printk("ip_conntrack: can't register local in hook.\n");
3464 + goto cleanup_inoutandlocalops;
3466 +#ifdef CONFIG_SYSCTL
3467 + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
3468 + if (ip_ct_sysctl_header == NULL) {
3469 + printk("ip_conntrack: can't register to sysctl.\n");
3477 +#ifdef CONFIG_SYSCTL
3478 + unregister_sysctl_table(ip_ct_sysctl_header);
3480 + nf_unregister_hook(&ip_conntrack_local_in_ops);
3481 + cleanup_inoutandlocalops:
3482 + nf_unregister_hook(&ip_conntrack_out_ops);
3483 + cleanup_inandlocalops:
3484 + nf_unregister_hook(&ip_conntrack_local_out_ops);
3486 + nf_unregister_hook(&ip_conntrack_in_ops);
3488 + proc_net_remove("ip_conntrack");
3490 + ip_conntrack_cleanup();
3495 +/* FIXME: Allow NULL functions and sub in pointers to generic for
3497 +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
3500 + struct list_head *i;
3502 + WRITE_LOCK(&ip_conntrack_lock);
3503 + list_for_each(i, &protocol_list) {
3504 + if (((struct ip_conntrack_protocol *)i)->proto
3505 + == proto->proto) {
3511 + list_prepend(&protocol_list, proto);
3514 + WRITE_UNLOCK(&ip_conntrack_lock);
3518 +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
3520 + WRITE_LOCK(&ip_conntrack_lock);
3522 + /* ip_ct_find_proto() returns proto_generic in case there is no protocol
3523 + * helper. So this should be enough - HW */
3524 + LIST_DELETE(&protocol_list, proto);
3525 + WRITE_UNLOCK(&ip_conntrack_lock);
3527 + /* Somebody could be still looking at the proto in bh. */
3528 + synchronize_net();
3530 + /* Remove all contrack entries for this protocol */
3531 + ip_ct_selective_cleanup(kill_proto, &proto->proto);
3534 +static int __init init(void)
3536 + return init_or_cleanup(1);
3539 +static void __exit fini(void)
3541 + init_or_cleanup(0);
3547 +/* Some modules need us, but don't depend directly on any symbol.
3548 + They should call this. */
3549 +void need_ip_conntrack(void)
3553 +EXPORT_SYMBOL(ip_conntrack_protocol_register);
3554 +EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
3555 +EXPORT_SYMBOL(invert_tuplepr);
3556 +EXPORT_SYMBOL(ip_conntrack_alter_reply);
3557 +EXPORT_SYMBOL(ip_conntrack_destroyed);
3558 +EXPORT_SYMBOL(ip_conntrack_get);
3559 +EXPORT_SYMBOL(need_ip_conntrack);
3560 +EXPORT_SYMBOL(ip_conntrack_helper_register);
3561 +EXPORT_SYMBOL(ip_conntrack_helper_unregister);
3562 +EXPORT_SYMBOL(ip_ct_selective_cleanup);
3563 +EXPORT_SYMBOL(ip_ct_refresh);
3564 +EXPORT_SYMBOL(ip_ct_find_proto);
3565 +EXPORT_SYMBOL(__ip_ct_find_proto);
3566 +EXPORT_SYMBOL(ip_ct_find_helper);
3567 +EXPORT_SYMBOL(ip_conntrack_expect_related);
3568 +EXPORT_SYMBOL(ip_conntrack_change_expect);
3569 +EXPORT_SYMBOL(ip_conntrack_unexpect_related);
3570 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
3571 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
3572 +EXPORT_SYMBOL(ip_conntrack_tuple_taken);
3573 +EXPORT_SYMBOL(ip_ct_gather_frags);
3574 +EXPORT_SYMBOL(ip_conntrack_htable_size);
3575 +EXPORT_SYMBOL(ip_conntrack_expect_list);
3576 +EXPORT_SYMBOL(ip_conntrack_lock);
3577 +EXPORT_SYMBOL(ip_conntrack_hash);
3578 +EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
3579 +EXPORT_SYMBOL_GPL(ip_conntrack_put);
3580 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.3/net/ipv4/netfilter/ip_nat_core.c
3581 --- linux-2.6.3.org/net/ipv4/netfilter/ip_nat_core.c 2004-02-18 04:57:16.000000000 +0100
3582 +++ linux-2.6.3/net/ipv4/netfilter/ip_nat_core.c 2004-02-27 00:03:14.483026424 +0100
3583 @@ -1016,6 +1016,10 @@
3584 /* FIXME: Man, this is a hack. <SIGH> */
3585 IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
3586 ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
3588 + /* Initialize fake conntrack so that NAT will skip it */
3589 + ip_conntrack_untracked.nat.info.initialized |=
3590 + (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST);
3594 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ip_nat_core.c.orig linux-2.6.3/net/ipv4/netfilter/ip_nat_core.c.orig
3595 --- linux-2.6.3.org/net/ipv4/netfilter/ip_nat_core.c.orig 1970-01-01 01:00:00.000000000 +0100
3596 +++ linux-2.6.3/net/ipv4/netfilter/ip_nat_core.c.orig 2004-02-18 04:57:16.000000000 +0100
3598 +/* NAT for netfilter; shared with compatibility layer. */
3600 +/* (C) 1999-2001 Paul `Rusty' Russell
3601 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3603 + * This program is free software; you can redistribute it and/or modify
3604 + * it under the terms of the GNU General Public License version 2 as
3605 + * published by the Free Software Foundation.
3608 +#include <linux/module.h>
3609 +#include <linux/types.h>
3610 +#include <linux/timer.h>
3611 +#include <linux/skbuff.h>
3612 +#include <linux/netfilter_ipv4.h>
3613 +#include <linux/vmalloc.h>
3614 +#include <net/checksum.h>
3615 +#include <net/icmp.h>
3616 +#include <net/ip.h>
3617 +#include <net/tcp.h> /* For tcp_prot in getorigdst */
3618 +#include <linux/icmp.h>
3619 +#include <linux/udp.h>
3621 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
3622 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
3624 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3625 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3626 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
3627 +#include <linux/netfilter_ipv4/ip_nat.h>
3628 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
3629 +#include <linux/netfilter_ipv4/ip_nat_core.h>
3630 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
3631 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
3632 +#include <linux/netfilter_ipv4/listhelp.h>
3635 +#define DEBUGP printk
3637 +#define DEBUGP(format, args...)
3640 +DECLARE_RWLOCK(ip_nat_lock);
3641 +DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
3643 +/* Calculated at init based on memory size */
3644 +static unsigned int ip_nat_htable_size;
3646 +static struct list_head *bysource;
3647 +static struct list_head *byipsproto;
3649 +LIST_HEAD(helpers);
3651 +extern struct ip_nat_protocol unknown_nat_protocol;
3653 +/* We keep extra hashes for each conntrack, for fast searching. */
3654 +static inline size_t
3655 +hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto)
3657 + /* Modified src and dst, to ensure we don't create two
3658 + identical streams. */
3659 + return (src + dst + proto) % ip_nat_htable_size;
3662 +static inline size_t
3663 +hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
3665 + /* Original src, to ensure we map it consistently if poss. */
3666 + return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
3669 +/* Noone using conntrack by the time this called. */
3670 +static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
3672 + struct ip_nat_info *info = &conn->nat.info;
3673 + unsigned int hs, hp;
3675 + if (!info->initialized)
3678 + IP_NF_ASSERT(info->bysource.conntrack);
3679 + IP_NF_ASSERT(info->byipsproto.conntrack);
3681 + hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
3682 + conn->tuplehash[IP_CT_DIR_ORIGINAL]
3683 + .tuple.dst.protonum);
3685 + hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
3686 + conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
3687 + conn->tuplehash[IP_CT_DIR_REPLY]
3688 + .tuple.dst.protonum);
3690 + WRITE_LOCK(&ip_nat_lock);
3691 + LIST_DELETE(&bysource[hs], &info->bysource);
3692 + LIST_DELETE(&byipsproto[hp], &info->byipsproto);
3693 + WRITE_UNLOCK(&ip_nat_lock);
3696 +/* We do checksum mangling, so if they were wrong before they're still
3697 + * wrong. Also works for incomplete packets (eg. ICMP dest
3698 + * unreachables.) */
3700 +ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
3702 + u_int32_t diffs[] = { oldvalinv, newval };
3703 + return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
3704 + oldcheck^0xFFFF));
3707 +static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
3709 + return i->protonum == proto;
3712 +struct ip_nat_protocol *
3713 +find_nat_proto(u_int16_t protonum)
3715 + struct ip_nat_protocol *i;
3717 + MUST_BE_READ_LOCKED(&ip_nat_lock);
3718 + i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
3720 + i = &unknown_nat_protocol;
3724 +/* Is this tuple already taken? (not by us) */
3726 +ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
3727 + const struct ip_conntrack *ignored_conntrack)
3729 + /* Conntrack tracking doesn't keep track of outgoing tuples; only
3730 + incoming ones. NAT means they don't have a fixed mapping,
3731 + so we invert the tuple and look for the incoming reply.
3733 + We could keep a separate hash if this proves too slow. */
3734 + struct ip_conntrack_tuple reply;
3736 + invert_tuplepr(&reply, tuple);
3737 + return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
3740 +/* Does tuple + the source manip come within the range mr */
3742 +in_range(const struct ip_conntrack_tuple *tuple,
3743 + const struct ip_conntrack_manip *manip,
3744 + const struct ip_nat_multi_range *mr)
3746 + struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
3748 + struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
3750 + for (i = 0; i < mr->rangesize; i++) {
3751 + /* If we are allowed to map IPs, then we must be in the
3752 + range specified, otherwise we must be unchanged. */
3753 + if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
3754 + if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
3755 + || (ntohl(newtuple.src.ip)
3756 + > ntohl(mr->range[i].max_ip)))
3759 + if (newtuple.src.ip != tuple->src.ip)
3763 + if (!(mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
3764 + || proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
3765 + &mr->range[i].min, &mr->range[i].max))
3772 +src_cmp(const struct ip_nat_hash *i,
3773 + const struct ip_conntrack_tuple *tuple,
3774 + const struct ip_nat_multi_range *mr)
3776 + return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
3777 + == tuple->dst.protonum
3778 + && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
3780 + && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
3781 + == tuple->src.u.all
3782 + && in_range(tuple,
3783 + &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
3788 +/* Only called for SRC manip */
3789 +static struct ip_conntrack_manip *
3790 +find_appropriate_src(const struct ip_conntrack_tuple *tuple,
3791 + const struct ip_nat_multi_range *mr)
3793 + unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
3794 + struct ip_nat_hash *i;
3796 + MUST_BE_READ_LOCKED(&ip_nat_lock);
3797 + i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
3799 + return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
3804 +#ifdef CONFIG_IP_NF_NAT_LOCAL
3805 +/* If it's really a local destination manip, it may need to do a
3806 + source manip too. */
3808 +do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
3810 + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = var_ip } } };
3811 + struct rtable *rt;
3813 + /* FIXME: IPTOS_TOS(iph->tos) --RR */
3814 + if (ip_route_output_key(&rt, &fl) != 0) {
3815 + DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
3820 + *other_ipp = rt->rt_src;
3826 +/* Simple way to iterate through all. */
3827 +static inline int fake_cmp(const struct ip_nat_hash *i,
3828 + u_int32_t src, u_int32_t dst, u_int16_t protonum,
3829 + unsigned int *score,
3830 + const struct ip_conntrack *conntrack)
3832 + /* Compare backwards: we're dealing with OUTGOING tuples, and
3833 + inside the conntrack is the REPLY tuple. Don't count this
3835 + if (i->conntrack != conntrack
3836 + && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
3837 + && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
3838 + && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
3844 +static inline unsigned int
3845 +count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
3846 + const struct ip_conntrack *conntrack)
3848 + unsigned int score = 0;
3851 + MUST_BE_READ_LOCKED(&ip_nat_lock);
3852 + h = hash_by_ipsproto(src, dst, protonum);
3853 + LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
3854 + src, dst, protonum, &score, conntrack);
3859 +/* For [FUTURE] fragmentation handling, we want the least-used
3860 + src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
3861 + if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
3862 + 1-65535, we don't do pro-rata allocation based on ports; we choose
3863 + the ip with the lowest src-ip/dst-ip/proto usage.
3865 + If an allocation then fails (eg. all 6 ports used in the 1.2.3.4
3866 + range), we eliminate that and try again. This is not the most
3867 + efficient approach, but if you're worried about that, don't hand us
3868 + ranges you don't really have. */
3869 +static struct ip_nat_range *
3870 +find_best_ips_proto(struct ip_conntrack_tuple *tuple,
3871 + const struct ip_nat_multi_range *mr,
3872 + const struct ip_conntrack *conntrack,
3873 + unsigned int hooknum)
3877 + const struct ip_nat_range *range;
3878 + unsigned int score;
3879 + struct ip_conntrack_tuple tuple;
3880 + } best = { NULL, 0xFFFFFFFF };
3881 + u_int32_t *var_ipp, *other_ipp, saved_ip, orig_dstip;
3882 + static unsigned int randomness;
3884 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
3885 + var_ipp = &tuple->src.ip;
3886 + saved_ip = tuple->dst.ip;
3887 + other_ipp = &tuple->dst.ip;
3889 + var_ipp = &tuple->dst.ip;
3890 + saved_ip = tuple->src.ip;
3891 + other_ipp = &tuple->src.ip;
3893 + /* Don't do do_extra_mangle unless necessary (overrides
3894 + explicit socket bindings, for example) */
3895 + orig_dstip = tuple->dst.ip;
3897 + IP_NF_ASSERT(mr->rangesize >= 1);
3898 + for (i = 0; i < mr->rangesize; i++) {
3900 + u_int32_t minip, maxip, j;
3902 + /* Don't do ranges which are already eliminated. */
3903 + if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
3907 + if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
3908 + minip = ntohl(mr->range[i].min_ip);
3909 + maxip = ntohl(mr->range[i].max_ip);
3911 + minip = maxip = ntohl(*var_ipp);
3914 + for (j = 0; j < maxip - minip + 1; j++) {
3915 + unsigned int score;
3917 + *var_ipp = htonl(minip + (randomness + j)
3918 + % (maxip - minip + 1));
3920 + /* Reset the other ip in case it was mangled by
3921 + * do_extra_mangle last time. */
3922 + *other_ipp = saved_ip;
3924 +#ifdef CONFIG_IP_NF_NAT_LOCAL
3925 + if (hooknum == NF_IP_LOCAL_OUT
3926 + && *var_ipp != orig_dstip
3927 + && !do_extra_mangle(*var_ipp, other_ipp)) {
3928 + DEBUGP("Range %u %u.%u.%u.%u rt failed!\n",
3929 + i, NIPQUAD(*var_ipp));
3930 + /* Can't route? This whole range part is
3931 + * probably screwed, but keep trying
3937 + /* Count how many others map onto this. */
3938 + score = count_maps(tuple->src.ip, tuple->dst.ip,
3939 + tuple->dst.protonum, conntrack);
3940 + if (score < best.score) {
3941 + /* Optimization: doesn't get any better than
3944 + return (struct ip_nat_range *)
3947 + best.score = score;
3948 + best.tuple = *tuple;
3949 + best.range = &mr->range[i];
3953 + *tuple = best.tuple;
3955 + /* Discard const. */
3956 + return (struct ip_nat_range *)best.range;
3959 +/* Fast version doesn't iterate through hash chains, but only handles
3960 + common case of single IP address (null NAT, masquerade) */
3961 +static struct ip_nat_range *
3962 +find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,
3963 + const struct ip_nat_multi_range *mr,
3964 + const struct ip_conntrack *conntrack,
3965 + unsigned int hooknum)
3967 + if (mr->rangesize != 1
3968 + || (mr->range[0].flags & IP_NAT_RANGE_FULL)
3969 + || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
3970 + && mr->range[0].min_ip != mr->range[0].max_ip))
3971 + return find_best_ips_proto(tuple, mr, conntrack, hooknum);
3973 + if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
3974 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
3975 + tuple->src.ip = mr->range[0].min_ip;
3977 + /* Only do extra mangle when required (breaks
3978 + socket binding) */
3979 +#ifdef CONFIG_IP_NF_NAT_LOCAL
3980 + if (tuple->dst.ip != mr->range[0].min_ip
3981 + && hooknum == NF_IP_LOCAL_OUT
3982 + && !do_extra_mangle(mr->range[0].min_ip,
3986 + tuple->dst.ip = mr->range[0].min_ip;
3990 + /* Discard const. */
3991 + return (struct ip_nat_range *)&mr->range[0];
3995 +get_unique_tuple(struct ip_conntrack_tuple *tuple,
3996 + const struct ip_conntrack_tuple *orig_tuple,
3997 + const struct ip_nat_multi_range *mrr,
3998 + struct ip_conntrack *conntrack,
3999 + unsigned int hooknum)
4001 + struct ip_nat_protocol *proto
4002 + = find_nat_proto(orig_tuple->dst.protonum);
4003 + struct ip_nat_range *rptr;
4007 + /* We temporarily use flags for marking full parts, but we
4008 + always clean up afterwards */
4009 + struct ip_nat_multi_range *mr = (void *)mrr;
4011 + /* 1) If this srcip/proto/src-proto-part is currently mapped,
4012 + and that same mapping gives a unique tuple within the given
4015 + This is only required for source (ie. NAT/masq) mappings.
4016 + So far, we don't do local source mappings, so multiple
4017 + manips not an issue. */
4018 + if (hooknum == NF_IP_POST_ROUTING) {
4019 + struct ip_conntrack_manip *manip;
4021 + manip = find_appropriate_src(orig_tuple, mr);
4023 + /* Apply same source manipulation. */
4024 + *tuple = ((struct ip_conntrack_tuple)
4025 + { *manip, orig_tuple->dst });
4026 + DEBUGP("get_unique_tuple: Found current src map\n");
4027 + if (!ip_nat_used_tuple(tuple, conntrack))
4032 + /* 2) Select the least-used IP/proto combination in the given
4035 + *tuple = *orig_tuple;
4036 + while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
4038 + DEBUGP("Found best for "); DUMP_TUPLE(tuple);
4039 + /* 3) The per-protocol part of the manip is made to
4040 + map into the range to make a unique tuple. */
4042 + /* Only bother mapping if it's not already in range
4044 + if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
4045 + || proto->in_range(tuple, HOOK2MANIP(hooknum),
4046 + &rptr->min, &rptr->max))
4047 + && !ip_nat_used_tuple(tuple, conntrack)) {
4051 + if (proto->unique_tuple(tuple, rptr,
4052 + HOOK2MANIP(hooknum),
4054 + /* Must be unique. */
4055 + IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
4059 + } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
4060 + /* Try implicit source NAT; protocol
4061 + may be able to play with ports to
4062 + make it unique. */
4063 + struct ip_nat_range r
4064 + = { IP_NAT_RANGE_MAP_IPS,
4065 + tuple->src.ip, tuple->src.ip,
4067 + DEBUGP("Trying implicit mapping\n");
4068 + if (proto->unique_tuple(tuple, &r,
4071 + /* Must be unique. */
4072 + IP_NF_ASSERT(!ip_nat_used_tuple
4073 + (tuple, conntrack));
4078 + DEBUGP("Protocol can't get unique tuple %u.\n",
4082 + /* Eliminate that from range, and try again. */
4083 + rptr->flags |= IP_NAT_RANGE_FULL;
4084 + *tuple = *orig_tuple;
4090 + /* Clear full flags. */
4091 + IP_NF_ASSERT(mr->rangesize >= 1);
4092 + for (i = 0; i < mr->rangesize; i++)
4093 + mr->range[i].flags &= ~IP_NAT_RANGE_FULL;
4099 +helper_cmp(const struct ip_nat_helper *helper,
4100 + const struct ip_conntrack_tuple *tuple)
4102 + return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
4105 +/* Where to manip the reply packets (will be reverse manip). */
4106 +static unsigned int opposite_hook[NF_IP_NUMHOOKS]
4107 += { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
4108 + [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
4109 +#ifdef CONFIG_IP_NF_NAT_LOCAL
4110 + [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
4111 + [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
4116 +ip_nat_setup_info(struct ip_conntrack *conntrack,
4117 + const struct ip_nat_multi_range *mr,
4118 + unsigned int hooknum)
4120 + struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
4121 + struct ip_conntrack_tuple orig_tp;
4122 + struct ip_nat_info *info = &conntrack->nat.info;
4123 + int in_hashes = info->initialized;
4125 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
4126 + IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
4127 + || hooknum == NF_IP_POST_ROUTING
4128 + || hooknum == NF_IP_LOCAL_OUT);
4129 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
4130 + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
4132 + /* What we've got will look like inverse of reply. Normally
4133 + this is what is in the conntrack, except for prior
4134 + manipulations (future optimization: if num_manips == 0,
4136 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
4137 + invert_tuplepr(&orig_tp,
4138 + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
4144 + DEBUGP("Hook %u (%s), ", hooknum,
4145 + HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");
4146 + DUMP_TUPLE(&orig_tp);
4147 + DEBUGP("Range %p: ", mr);
4148 + for (i = 0; i < mr->rangesize; i++) {
4149 + DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",
4151 + (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)
4152 + ? " MAP_IPS" : "",
4153 + (mr->range[i].flags
4154 + & IP_NAT_RANGE_PROTO_SPECIFIED)
4155 + ? " PROTO_SPECIFIED" : "",
4156 + (mr->range[i].flags & IP_NAT_RANGE_FULL)
4158 + NIPQUAD(mr->range[i].min_ip),
4159 + NIPQUAD(mr->range[i].max_ip),
4160 + mr->range[i].min.all,
4161 + mr->range[i].max.all);
4167 + if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
4169 + DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
4175 + DEBUGP("Hook %u (%s) %p\n", hooknum,
4176 + HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
4178 + DEBUGP("Original: ");
4179 + DUMP_TUPLE(&orig_tp);
4181 + DUMP_TUPLE(&new_tuple);
4184 + /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
4185 + the original (A/B/C/D') and the mangled one (E/F/G/H').
4187 + We're only allowed to work with the SRC per-proto
4188 + part, so we create inverses of both to start, then
4189 + derive the other fields we need. */
4191 + /* Reply connection: simply invert the new tuple
4193 + invert_tuplepr(&reply, &new_tuple);
4195 + /* Alter conntrack table so it recognizes replies.
4196 + If fail this race (reply tuple now used), repeat. */
4197 + } while (!ip_conntrack_alter_reply(conntrack, &reply));
4199 + /* FIXME: We can simply used existing conntrack reply tuple
4201 + /* Create inverse of original: C/D/A/B' */
4202 + invert_tuplepr(&inv_tuple, &orig_tp);
4204 + /* Has source changed?. */
4205 + if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {
4206 + /* In this direction, a source manip. */
4207 + info->manips[info->num_manips++] =
4208 + ((struct ip_nat_info_manip)
4209 + { IP_CT_DIR_ORIGINAL, hooknum,
4210 + IP_NAT_MANIP_SRC, new_tuple.src });
4212 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
4214 + /* In the reverse direction, a destination manip. */
4215 + info->manips[info->num_manips++] =
4216 + ((struct ip_nat_info_manip)
4217 + { IP_CT_DIR_REPLY, opposite_hook[hooknum],
4218 + IP_NAT_MANIP_DST, orig_tp.src });
4219 + IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
4222 + /* Has destination changed? */
4223 + if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {
4224 + /* In this direction, a destination manip */
4225 + info->manips[info->num_manips++] =
4226 + ((struct ip_nat_info_manip)
4227 + { IP_CT_DIR_ORIGINAL, hooknum,
4228 + IP_NAT_MANIP_DST, reply.src });
4230 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
4232 + /* In the reverse direction, a source manip. */
4233 + info->manips[info->num_manips++] =
4234 + ((struct ip_nat_info_manip)
4235 + { IP_CT_DIR_REPLY, opposite_hook[hooknum],
4236 + IP_NAT_MANIP_SRC, inv_tuple.src });
4237 + IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
4240 + /* If there's a helper, assign it; based on new tuple. */
4241 + if (!conntrack->master)
4242 + info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
4246 + info->initialized |= (1 << HOOK2MANIP(hooknum));
4249 + IP_NF_ASSERT(info->bysource.conntrack);
4250 + replace_in_hashes(conntrack, info);
4252 + place_in_hashes(conntrack, info);
4258 +void replace_in_hashes(struct ip_conntrack *conntrack,
4259 + struct ip_nat_info *info)
4261 + /* Source has changed, so replace in hashes. */
4262 + unsigned int srchash
4263 + = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4265 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4266 + .tuple.dst.protonum);
4267 + /* We place packet as seen OUTGOUNG in byips_proto hash
4268 + (ie. reverse dst and src of reply packet. */
4269 + unsigned int ipsprotohash
4270 + = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
4272 + conntrack->tuplehash[IP_CT_DIR_REPLY]
4274 + conntrack->tuplehash[IP_CT_DIR_REPLY]
4275 + .tuple.dst.protonum);
4277 + IP_NF_ASSERT(info->bysource.conntrack == conntrack);
4278 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
4280 + list_del(&info->bysource.list);
4281 + list_del(&info->byipsproto.list);
4283 + list_prepend(&bysource[srchash], &info->bysource);
4284 + list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
4287 +void place_in_hashes(struct ip_conntrack *conntrack,
4288 + struct ip_nat_info *info)
4290 + unsigned int srchash
4291 + = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4293 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4294 + .tuple.dst.protonum);
4295 + /* We place packet as seen OUTGOUNG in byips_proto hash
4296 + (ie. reverse dst and src of reply packet. */
4297 + unsigned int ipsprotohash
4298 + = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
4300 + conntrack->tuplehash[IP_CT_DIR_REPLY]
4302 + conntrack->tuplehash[IP_CT_DIR_REPLY]
4303 + .tuple.dst.protonum);
4305 + IP_NF_ASSERT(!info->bysource.conntrack);
4307 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
4308 + info->byipsproto.conntrack = conntrack;
4309 + info->bysource.conntrack = conntrack;
4311 + list_prepend(&bysource[srchash], &info->bysource);
4312 + list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
4315 +/* Returns true if succeeded. */
4317 +manip_pkt(u_int16_t proto,
4318 + struct sk_buff **pskb,
4319 + unsigned int iphdroff,
4320 + const struct ip_conntrack_manip *manip,
4321 + enum ip_nat_manip_type maniptype)
4323 + struct iphdr *iph;
4325 + (*pskb)->nfcache |= NFC_ALTERED;
4326 + if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph)))
4329 + iph = (void *)(*pskb)->data + iphdroff;
4331 + /* Manipulate protcol part. */
4332 + if (!find_nat_proto(proto)->manip_pkt(pskb,
4333 + iphdroff + iph->ihl*4,
4334 + manip, maniptype))
4337 + iph = (void *)(*pskb)->data + iphdroff;
4339 + if (maniptype == IP_NAT_MANIP_SRC) {
4340 + iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
4342 + iph->saddr = manip->ip;
4344 + iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
4346 + iph->daddr = manip->ip;
4351 +static inline int exp_for_packet(struct ip_conntrack_expect *exp,
4352 + struct sk_buff *skb)
4354 + struct ip_conntrack_protocol *proto;
4357 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
4358 + proto = __ip_ct_find_proto(skb->nh.iph->protocol);
4359 + if (proto->exp_matches_pkt)
4360 + ret = proto->exp_matches_pkt(exp, skb);
4365 +/* Do packet manipulations according to binding. */
4367 +do_bindings(struct ip_conntrack *ct,
4368 + enum ip_conntrack_info ctinfo,
4369 + struct ip_nat_info *info,
4370 + unsigned int hooknum,
4371 + struct sk_buff **pskb)
4374 + struct ip_nat_helper *helper;
4375 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
4376 + int proto = (*pskb)->nh.iph->protocol;
4378 + /* Need nat lock to protect against modification, but neither
4379 + conntrack (referenced) and helper (deleted with
4380 + synchronize_bh()) can vanish. */
4381 + READ_LOCK(&ip_nat_lock);
4382 + for (i = 0; i < info->num_manips; i++) {
4383 + if (info->manips[i].direction == dir
4384 + && info->manips[i].hooknum == hooknum) {
4385 + DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
4387 + info->manips[i].maniptype == IP_NAT_MANIP_SRC
4389 + NIPQUAD(info->manips[i].manip.ip),
4390 + htons(info->manips[i].manip.u.all));
4391 + if (!manip_pkt(proto, pskb, 0,
4392 + &info->manips[i].manip,
4393 + info->manips[i].maniptype)) {
4394 + READ_UNLOCK(&ip_nat_lock);
4399 + helper = info->helper;
4400 + READ_UNLOCK(&ip_nat_lock);
4403 + struct ip_conntrack_expect *exp = NULL;
4404 + struct list_head *cur_item;
4405 + int ret = NF_ACCEPT;
4406 + int helper_called = 0;
4408 + DEBUGP("do_bindings: helper existing for (%p)\n", ct);
4410 + /* Always defragged for helpers */
4411 + IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
4412 + & htons(IP_MF|IP_OFFSET)));
4414 + /* Have to grab read lock before sibling_list traversal */
4415 + READ_LOCK(&ip_conntrack_lock);
4416 + list_for_each(cur_item, &ct->sibling_list) {
4417 + exp = list_entry(cur_item, struct ip_conntrack_expect,
4420 + /* if this expectation is already established, skip */
4424 + if (exp_for_packet(exp, *pskb)) {
4425 + /* FIXME: May be true multiple times in the
4426 + * case of UDP!! */
4427 + DEBUGP("calling nat helper (exp=%p) for packet\n", exp);
4428 + ret = helper->help(ct, exp, info, ctinfo,
4430 + if (ret != NF_ACCEPT) {
4431 + READ_UNLOCK(&ip_conntrack_lock);
4434 + helper_called = 1;
4437 + /* Helper might want to manip the packet even when there is no
4438 + * matching expectation for this packet */
4439 + if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
4440 + DEBUGP("calling nat helper for packet without expectation\n");
4441 + ret = helper->help(ct, NULL, info, ctinfo,
4443 + if (ret != NF_ACCEPT) {
4444 + READ_UNLOCK(&ip_conntrack_lock);
4448 + READ_UNLOCK(&ip_conntrack_lock);
4450 + /* Adjust sequence number only once per packet
4451 + * (helper is called at all hooks) */
4452 + if (proto == IPPROTO_TCP
4453 + && (hooknum == NF_IP_POST_ROUTING
4454 + || hooknum == NF_IP_LOCAL_IN)) {
4455 + DEBUGP("ip_nat_core: adjusting sequence number\n");
4456 + /* future: put this in a l4-proto specific function,
4457 + * and call this function here. */
4458 + if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
4471 +icmp_reply_translation(struct sk_buff **pskb,
4472 + struct ip_conntrack *conntrack,
4473 + unsigned int hooknum,
4477 + struct icmphdr icmp;
4481 + struct ip_nat_info *info = &conntrack->nat.info;
4484 + if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside)))
4486 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
4488 + /* We're actually going to mangle it beyond trivial checksum
4489 + adjustment, so make sure the current checksum is correct. */
4490 + if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) {
4491 + hdrlen = (*pskb)->nh.iph->ihl * 4;
4492 + if ((u16)csum_fold(skb_checksum(*pskb, hdrlen,
4493 + (*pskb)->len - hdrlen, 0)))
4497 + /* Must be RELATED */
4498 + IP_NF_ASSERT((*pskb)->nfct
4499 + - (struct ip_conntrack *)(*pskb)->nfct->master
4502 + - (struct ip_conntrack *)(*pskb)->nfct->master
4503 + == IP_CT_RELATED+IP_CT_IS_REPLY);
4505 + /* Redirects on non-null nats must be dropped, else they'll
4506 + start talking to each other without our translation, and be
4507 + confused... --RR */
4508 + if (inside->icmp.type == ICMP_REDIRECT) {
4509 + /* Don't care about races here. */
4510 + if (info->initialized
4511 + != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
4512 + || info->num_manips != 0)
4516 + DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
4517 + *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
4518 + /* Note: May not be from a NAT'd host, but probably safest to
4519 + do translation always as if it came from the host itself
4520 + (even though a "host unreachable" coming from the host
4521 + itself is a bit weird).
4523 + More explanation: some people use NAT for anonymizing.
4524 + Also, CERT recommends dropping all packets from private IP
4525 + addresses (although ICMP errors from internal links with
4526 + such addresses are not too uncommon, as Alan Cox points
4529 + READ_LOCK(&ip_nat_lock);
4530 + for (i = 0; i < info->num_manips; i++) {
4531 + DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
4532 + i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?
4533 + "ORIG" : "REPLY", info->manips[i].hooknum);
4535 + if (info->manips[i].direction != dir)
4538 + /* Mapping the inner packet is just like a normal
4539 + packet, except it was never src/dst reversed, so
4540 + where we would normally apply a dst manip, we apply
4541 + a src, and vice versa. */
4542 + if (info->manips[i].hooknum == hooknum) {
4543 + DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
4544 + info->manips[i].maniptype == IP_NAT_MANIP_SRC
4546 + NIPQUAD(info->manips[i].manip.ip),
4547 + ntohs(info->manips[i].manip.u.udp.port));
4548 + if (!manip_pkt(inside->ip.protocol, pskb,
4549 + (*pskb)->nh.iph->ihl*4
4550 + + sizeof(inside->icmp),
4551 + &info->manips[i].manip,
4552 + !info->manips[i].maniptype))
4555 + /* Outer packet needs to have IP header NATed like
4558 + /* Use mapping to map outer packet: 0 give no
4559 + per-proto mapping */
4560 + DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
4561 + info->manips[i].maniptype == IP_NAT_MANIP_SRC
4563 + NIPQUAD(info->manips[i].manip.ip));
4564 + if (!manip_pkt(0, pskb, 0,
4565 + &info->manips[i].manip,
4566 + info->manips[i].maniptype))
4570 + READ_UNLOCK(&ip_nat_lock);
4572 + hdrlen = (*pskb)->nh.iph->ihl * 4;
4574 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
4576 + inside->icmp.checksum = 0;
4577 + inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
4578 + (*pskb)->len - hdrlen,
4583 + READ_UNLOCK(&ip_nat_lock);
4587 +int __init ip_nat_init(void)
4591 + /* Leave them the same for the moment. */
4592 + ip_nat_htable_size = ip_conntrack_htable_size;
4594 + /* One vmalloc for both hash tables */
4595 + bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
4599 + byipsproto = bysource + ip_nat_htable_size;
4601 + /* Sew in builtin protocols. */
4602 + WRITE_LOCK(&ip_nat_lock);
4603 + list_append(&protos, &ip_nat_protocol_tcp);
4604 + list_append(&protos, &ip_nat_protocol_udp);
4605 + list_append(&protos, &ip_nat_protocol_icmp);
4606 + WRITE_UNLOCK(&ip_nat_lock);
4608 + for (i = 0; i < ip_nat_htable_size; i++) {
4609 + INIT_LIST_HEAD(&bysource[i]);
4610 + INIT_LIST_HEAD(&byipsproto[i]);
4613 + /* FIXME: Man, this is a hack. <SIGH> */
4614 + IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
4615 + ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
4620 +/* Clear NAT section of all conntracks, in case we're loaded again. */
4621 +static int clean_nat(const struct ip_conntrack *i, void *data)
4623 + memset((void *)&i->nat, 0, sizeof(i->nat));
4627 +/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
4628 +void ip_nat_cleanup(void)
4630 + ip_ct_selective_cleanup(&clean_nat, NULL);
4631 + ip_conntrack_destroyed = NULL;
4634 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/iptable_raw.c linux-2.6.3/net/ipv4/netfilter/iptable_raw.c
4635 --- linux-2.6.3.org/net/ipv4/netfilter/iptable_raw.c 1970-01-01 01:00:00.000000000 +0100
4636 +++ linux-2.6.3/net/ipv4/netfilter/iptable_raw.c 2004-02-27 00:03:14.470028400 +0100
4639 + * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
4641 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
4643 +#include <linux/module.h>
4644 +#include <linux/netfilter_ipv4/ip_tables.h>
4646 +#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
4648 +/* Standard entry. */
4649 +struct ipt_standard
4651 + struct ipt_entry entry;
4652 + struct ipt_standard_target target;
4655 +struct ipt_error_target
4657 + struct ipt_entry_target target;
4658 + char errorname[IPT_FUNCTION_MAXNAMELEN];
4663 + struct ipt_entry entry;
4664 + struct ipt_error_target target;
4669 + struct ipt_replace repl;
4670 + struct ipt_standard entries[2];
4671 + struct ipt_error term;
4672 +} initial_table __initdata
4673 += { { "raw", RAW_VALID_HOOKS, 3,
4674 + sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
4675 + { [NF_IP_PRE_ROUTING] 0,
4676 + [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
4677 + { [NF_IP_PRE_ROUTING] 0,
4678 + [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
4682 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
4684 + sizeof(struct ipt_entry),
4685 + sizeof(struct ipt_standard),
4686 + 0, { 0, 0 }, { } },
4687 + { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
4688 + -NF_ACCEPT - 1 } },
4690 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
4692 + sizeof(struct ipt_entry),
4693 + sizeof(struct ipt_standard),
4694 + 0, { 0, 0 }, { } },
4695 + { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
4696 + -NF_ACCEPT - 1 } }
4699 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
4701 + sizeof(struct ipt_entry),
4702 + sizeof(struct ipt_error),
4703 + 0, { 0, 0 }, { } },
4704 + { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
4711 +static struct ipt_table packet_raw = {
4713 + .table = &initial_table.repl,
4714 + .valid_hooks = RAW_VALID_HOOKS,
4715 + .lock = RW_LOCK_UNLOCKED,
4719 +/* The work comes in here from netfilter.c. */
4720 +static unsigned int
4721 +ipt_hook(unsigned int hook,
4722 + struct sk_buff **pskb,
4723 + const struct net_device *in,
4724 + const struct net_device *out,
4725 + int (*okfn)(struct sk_buff *))
4727 + return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
4730 +/* 'raw' is the very first table. */
4731 +static struct nf_hook_ops ipt_ops[] = {
4735 + .hooknum = NF_IP_PRE_ROUTING,
4736 + .priority = NF_IP_PRI_RAW
4741 + .hooknum = NF_IP_LOCAL_OUT,
4742 + .priority = NF_IP_PRI_RAW
4746 +static int __init init(void)
4750 + /* Register table */
4751 + ret = ipt_register_table(&packet_raw);
4755 + /* Register hooks */
4756 + ret = nf_register_hook(&ipt_ops[0]);
4758 + goto cleanup_table;
4760 + ret = nf_register_hook(&ipt_ops[1]);
4762 + goto cleanup_hook0;
4767 + nf_unregister_hook(&ipt_ops[0]);
4769 + ipt_unregister_table(&packet_raw);
4774 +static void __exit fini(void)
4778 + for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
4779 + nf_unregister_hook(&ipt_ops[i]);
4781 + ipt_unregister_table(&packet_raw);
4786 +MODULE_LICENSE("GPL");
4787 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.3/net/ipv4/netfilter/ipt_connlimit.c
4788 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100
4789 +++ linux-2.6.3/net/ipv4/netfilter/ipt_connlimit.c 2004-02-27 00:03:07.981014880 +0100
4792 + * netfilter module to limit the number of parallel tcp
4793 + * connections per IP address.
4794 + * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
4795 + * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
4796 + * only ignore TIME_WAIT or gone connections
4800 + * Kernel module to match connection tracking information.
4801 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
4803 +#include <linux/module.h>
4804 +#include <linux/skbuff.h>
4805 +#include <linux/list.h>
4806 +#include <linux/netfilter_ipv4/ip_conntrack.h>
4807 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
4808 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
4809 +#include <linux/netfilter_ipv4/ip_tables.h>
4810 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
4814 +MODULE_LICENSE("GPL");
4816 +/* we'll save the tuples of all connections we care about */
4817 +struct ipt_connlimit_conn
4819 + struct list_head list;
4820 + struct ip_conntrack_tuple tuple;
4823 +struct ipt_connlimit_data {
4825 + struct list_head iphash[256];
4828 +static int ipt_iphash(u_int32_t addr)
4832 + hash = addr & 0xff;
4833 + hash ^= (addr >> 8) & 0xff;
4834 + hash ^= (addr >> 16) & 0xff;
4835 + hash ^= (addr >> 24) & 0xff;
4839 +static int count_them(struct ipt_connlimit_data *data,
4840 + u_int32_t addr, u_int32_t mask,
4841 + struct ip_conntrack *ct)
4844 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
4845 + "fin_wait", "time_wait", "close", "close_wait",
4846 + "last_ack", "listen" };
4848 + int addit = 1, matches = 0;
4849 + struct ip_conntrack_tuple tuple;
4850 + struct ip_conntrack_tuple_hash *found;
4851 + struct ipt_connlimit_conn *conn;
4852 + struct list_head *hash,*lh;
4854 + spin_lock(&data->lock);
4855 + tuple = ct->tuplehash[0].tuple;
4856 + hash = &data->iphash[ipt_iphash(addr & mask)];
4858 + /* check the saved connections */
4859 + for (lh = hash->next; lh != hash; lh = lh->next) {
4860 + conn = list_entry(lh,struct ipt_connlimit_conn,list);
4861 + found = ip_conntrack_find_get(&conn->tuple,ct);
4862 + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
4864 + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
4865 + /* Just to be sure we have it only once in the list.
4866 + We should'nt see tuples twice unless someone hooks this
4867 + into a table without "-p tcp --syn" */
4871 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
4872 + ipt_iphash(addr & mask),
4873 + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
4874 + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
4875 + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
4877 + if (NULL == found) {
4878 + /* this one is gone */
4880 + list_del(lh->next);
4884 + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
4885 + /* we don't care about connections which are
4886 + closed already -> ditch it */
4888 + list_del(lh->next);
4890 + nf_conntrack_put(&found->ctrack->infos[0]);
4893 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
4894 + /* same source IP address -> be counted! */
4897 + nf_conntrack_put(&found->ctrack->infos[0]);
4900 + /* save the new connection in our list */
4902 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
4903 + ipt_iphash(addr & mask),
4904 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
4905 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
4907 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
4910 + memset(conn,0,sizeof(*conn));
4911 + INIT_LIST_HEAD(&conn->list);
4912 + conn->tuple = tuple;
4913 + list_add(&conn->list,hash);
4916 + spin_unlock(&data->lock);
4921 +match(const struct sk_buff *skb,
4922 + const struct net_device *in,
4923 + const struct net_device *out,
4924 + const void *matchinfo,
4928 + const struct ipt_connlimit_info *info = matchinfo;
4929 + int connections, match;
4930 + struct ip_conntrack *ct;
4931 + enum ip_conntrack_info ctinfo;
4933 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
4935 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
4939 + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
4940 + if (-1 == connections) {
4941 + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
4942 + *hotdrop = 1; /* let's free some memory :-) */
4945 + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
4947 + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
4948 + "connections=%d limit=%d match=%s\n",
4949 + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
4950 + connections, info->limit, match ? "yes" : "no");
4956 +static int check(const char *tablename,
4957 + const struct ipt_ip *ip,
4959 + unsigned int matchsize,
4960 + unsigned int hook_mask)
4962 + struct ipt_connlimit_info *info = matchinfo;
4966 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
4969 + /* refuse anything but tcp */
4970 + if (ip->proto != IPPROTO_TCP)
4973 + /* init private data */
4974 + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
4975 + spin_lock_init(&(info->data->lock));
4976 + for (i = 0; i < 256; i++)
4977 + INIT_LIST_HEAD(&(info->data->iphash[i]));
4982 +static void destroy(void *matchinfo, unsigned int matchinfosize)
4984 + struct ipt_connlimit_info *info = matchinfo;
4985 + struct ipt_connlimit_conn *conn;
4986 + struct list_head *hash;
4990 + for (i = 0; i < 256; i++) {
4991 + hash = &(info->data->iphash[i]);
4992 + while (hash != hash->next) {
4993 + conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
4994 + list_del(hash->next);
4998 + kfree(info->data);
5001 +static struct ipt_match connlimit_match = {
5002 + .name = "connlimit",
5004 + .checkentry = &check,
5005 + .destroy = &destroy,
5009 +static int __init init(void)
5011 + return ipt_register_match(&connlimit_match);
5014 +static void __exit fini(void)
5016 + ipt_unregister_match(&connlimit_match);
5021 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.3/net/ipv4/netfilter/ipt_conntrack.c
5022 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_conntrack.c 2004-02-18 04:59:26.000000000 +0100
5023 +++ linux-2.6.3/net/ipv4/netfilter/ipt_conntrack.c 2004-02-27 00:03:14.483026424 +0100
5026 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
5029 - statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
5031 - statebit = IPT_CONNTRACK_STATE_INVALID;
5033 + if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
5034 + statebit = IPT_CONNTRACK_STATE_UNTRACKED;
5036 + statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
5038 + statebit = IPT_CONNTRACK_STATE_INVALID;
5040 if(sinfo->flags & IPT_CONNTRACK_STATE) {
5042 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
5043 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_conntrack.c.orig linux-2.6.3/net/ipv4/netfilter/ipt_conntrack.c.orig
5044 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_conntrack.c.orig 1970-01-01 01:00:00.000000000 +0100
5045 +++ linux-2.6.3/net/ipv4/netfilter/ipt_conntrack.c.orig 2004-02-18 04:59:26.000000000 +0100
5047 +/* Kernel module to match connection tracking information.
5048 + * Superset of Rusty's minimalistic state match.
5050 + * (C) 2001 Marc Boucher (marc@mbsi.ca).
5052 + * This program is free software; you can redistribute it and/or modify
5053 + * it under the terms of the GNU General Public License version 2 as
5054 + * published by the Free Software Foundation.
5057 +#include <linux/module.h>
5058 +#include <linux/skbuff.h>
5059 +#include <linux/netfilter_ipv4/ip_conntrack.h>
5060 +#include <linux/netfilter_ipv4/ip_tables.h>
5061 +#include <linux/netfilter_ipv4/ipt_conntrack.h>
5063 +MODULE_LICENSE("GPL");
5064 +MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
5065 +MODULE_DESCRIPTION("iptables connection tracking match module");
5068 +match(const struct sk_buff *skb,
5069 + const struct net_device *in,
5070 + const struct net_device *out,
5071 + const void *matchinfo,
5075 + const struct ipt_conntrack_info *sinfo = matchinfo;
5076 + struct ip_conntrack *ct;
5077 + enum ip_conntrack_info ctinfo;
5078 + unsigned int statebit;
5080 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
5082 +#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
5085 + statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
5087 + statebit = IPT_CONNTRACK_STATE_INVALID;
5089 + if(sinfo->flags & IPT_CONNTRACK_STATE) {
5091 + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
5092 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
5093 + statebit |= IPT_CONNTRACK_STATE_SNAT;
5095 + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
5096 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
5097 + statebit |= IPT_CONNTRACK_STATE_DNAT;
5100 + if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
5104 + if(sinfo->flags & IPT_CONNTRACK_PROTO) {
5105 + if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
5109 + if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
5110 + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
5114 + if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
5115 + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
5119 + if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
5120 + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
5124 + if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
5125 + if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
5129 + if(sinfo->flags & IPT_CONNTRACK_STATUS) {
5130 + if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
5134 + if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
5135 + unsigned long expires;
5140 + expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
5142 + if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
5149 +static int check(const char *tablename,
5150 + const struct ipt_ip *ip,
5152 + unsigned int matchsize,
5153 + unsigned int hook_mask)
5155 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
5161 +static struct ipt_match conntrack_match = {
5162 + .name = "conntrack",
5164 + .checkentry = &check,
5165 + .me = THIS_MODULE,
5168 +static int __init init(void)
5170 + need_ip_conntrack();
5171 + return ipt_register_match(&conntrack_match);
5174 +static void __exit fini(void)
5176 + ipt_unregister_match(&conntrack_match);
5181 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.3/net/ipv4/netfilter/ipt_dstlimit.c
5182 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 01:00:00.000000000 +0100
5183 +++ linux-2.6.3/net/ipv4/netfilter/ipt_dstlimit.c 2004-02-27 00:03:08.652912736 +0100
5185 +/* iptables match extension to limit the number of packets per second
5186 + * seperately for each destination.
5188 + * (C) 2003 by Harald Welte <laforge@netfilter.org>
5190 + * ipt_dstlimit.c,v 1.3 2004/02/23 00:15:45 laforge Exp
5192 + * Development of this code was funded by Astaro AG, http://www.astaro.com/
5194 + * based on ipt_limit.c by:
5195 + * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
5196 + * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
5197 + * Rusty Russell <rusty@rustcorp.com.au>
5199 + * The general idea is to create a hash table for every dstip and have a
5200 + * seperate limit counter per tuple. This way you can do something like 'limit
5201 + * the number of syn packets for each of my internal addresses.
5203 + * Ideally this would just be implemented as a general 'hash' match, which would
5204 + * allow us to attach any iptables target to it's hash buckets. But this is
5205 + * not possible in the current iptables architecture. As always, pkttables for
5206 + * 2.7.x will help ;)
5208 +#include <linux/module.h>
5209 +#include <linux/skbuff.h>
5210 +#include <linux/spinlock.h>
5211 +#include <linux/random.h>
5212 +#include <linux/jhash.h>
5213 +#include <linux/slab.h>
5214 +#include <linux/vmalloc.h>
5215 +#include <linux/tcp.h>
5216 +#include <linux/udp.h>
5217 +#include <linux/proc_fs.h>
5218 +#include <linux/seq_file.h>
5220 +#define ASSERT_READ_LOCK(x)
5221 +#define ASSERT_WRITE_LOCK(x)
5222 +#include <linux/netfilter_ipv4/lockhelp.h>
5223 +#include <linux/netfilter_ipv4/listhelp.h>
5225 +#include <linux/netfilter_ipv4/ip_tables.h>
5226 +#include <linux/netfilter_ipv4/ipt_dstlimit.h>
5228 +/* FIXME: this is just for IP_NF_ASSERRT */
5229 +#include <linux/netfilter_ipv4/ip_conntrack.h>
5231 +#define MS2JIFFIES(x) ((x*HZ)/1000)
5233 +MODULE_LICENSE("GPL");
5234 +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
5235 +MODULE_DESCRIPTION("iptables match for limiting per destination");
5237 +/* need to declare this at the top */
5238 +static struct proc_dir_entry *dstlimit_procdir;
5239 +static struct file_operations dl_file_ops;
5241 +/* hash table crap */
5243 +struct dsthash_dst {
5249 +struct dsthash_ent {
5250 + /* static / read-only parts in the beginning */
5251 + struct list_head list;
5252 + struct dsthash_dst dst;
5254 + /* modified structure members in the end */
5255 + unsigned long expires; /* precalculated expiry time */
5257 + unsigned long prev; /* last modification */
5259 + u_int32_t credit_cap, cost;
5263 +struct ipt_dstlimit_htable {
5264 + struct list_head list; /* global list of all htables */
5267 + struct dstlimit_cfg cfg; /* config */
5269 + /* used internally */
5270 + spinlock_t lock; /* lock for list_head */
5271 + u_int32_t rnd; /* random seed for hash */
5272 + struct timer_list timer; /* timer for gc */
5273 + atomic_t count; /* number entries in table */
5275 + /* seq_file stuff */
5276 + struct proc_dir_entry *pde;
5278 + struct list_head hash[0]; /* hashtable itself */
5281 +DECLARE_RWLOCK(dstlimit_lock); /* protects htables list */
5282 +static LIST_HEAD(dstlimit_htables);
5283 +static kmem_cache_t *dstlimit_cachep;
5285 +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
5287 + return (ent->dst.dst_ip == b->dst_ip
5288 + && ent->dst.port == b->port
5289 + && ent->dst.src_ip == b->src_ip);
5292 +static inline u_int32_t
5293 +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
5295 + return (jhash_3words(dst->dst_ip, dst->port,
5296 + dst->src_ip, ht->rnd) % ht->cfg.size);
5299 +static inline struct dsthash_ent *
5300 +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
5302 + struct dsthash_ent *ent;
5303 + u_int32_t hash = hash_dst(ht, dst);
5304 + MUST_BE_LOCKED(&ht->lock);
5305 + ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
5309 +/* allocate dsthash_ent, initialize dst, put in htable and lock it */
5310 +static struct dsthash_ent *
5311 +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
5313 + struct dsthash_ent *ent;
5315 + /* initialize hash with random val at the time we allocate
5316 + * the first hashtable entry */
5318 + get_random_bytes(&ht->rnd, 4);
5320 + if (ht->cfg.max &&
5321 + atomic_read(&ht->count) >= ht->cfg.max) {
5322 + /* FIXME: do something. question is what.. */
5323 + if (net_ratelimit())
5324 + printk(KERN_WARNING
5325 + "ipt_dstlimit: max count of %u reached\n",
5330 + ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
5332 + if (net_ratelimit())
5334 + "ipt_dstlimit: can't allocate dsthash_ent\n");
5338 + atomic_inc(&ht->count);
5340 + ent->dst.dst_ip = dst->dst_ip;
5341 + ent->dst.port = dst->port;
5342 + ent->dst.src_ip = dst->src_ip;
5344 + list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
5350 +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
5352 + MUST_BE_LOCKED(&ht->lock);
5354 + list_del(&ent->list);
5355 + kmem_cache_free(dstlimit_cachep, ent);
5356 + atomic_dec(&ht->count);
5358 +static void htable_gc(unsigned long htlong);
5360 +static int htable_create(struct ipt_dstlimit_info *minfo)
5363 + unsigned int size;
5364 + struct ipt_dstlimit_htable *hinfo;
5366 + if (minfo->cfg.size)
5367 + size = minfo->cfg.size;
5369 + size = (((num_physpages << PAGE_SHIFT) / 16384)
5370 + / sizeof(struct list_head));
5371 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
5376 + /* FIXME: don't use vmalloc() here or anywhere else -HW */
5377 + hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
5378 + + (sizeof(struct list_head) * size));
5380 + printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
5383 + minfo->hinfo = hinfo;
5385 + /* copy match config into hashtable config */
5386 + memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
5387 + hinfo->cfg.size = size;
5388 + if (!hinfo->cfg.max)
5389 + hinfo->cfg.max = 8 * hinfo->cfg.size;
5390 + else if (hinfo->cfg.max < hinfo->cfg.size)
5391 + hinfo->cfg.max = hinfo->cfg.size;
5393 + for (i = 0; i < hinfo->cfg.size; i++)
5394 + INIT_LIST_HEAD(&hinfo->hash[i]);
5396 + atomic_set(&hinfo->count, 0);
5397 + atomic_set(&hinfo->use, 1);
5399 + hinfo->lock = SPIN_LOCK_UNLOCKED;
5400 + hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
5401 + if (!hinfo->pde) {
5405 + hinfo->pde->proc_fops = &dl_file_ops;
5406 + hinfo->pde->data = hinfo;
5408 + init_timer(&hinfo->timer);
5409 + hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
5410 + hinfo->timer.data = (unsigned long )hinfo;
5411 + hinfo->timer.function = htable_gc;
5412 + add_timer(&hinfo->timer);
5414 + WRITE_LOCK(&dstlimit_lock);
5415 + list_add(&hinfo->list, &dstlimit_htables);
5416 + WRITE_UNLOCK(&dstlimit_lock);
5421 +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
5426 +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
5428 + return (jiffies >= he->expires);
5431 +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
5432 + int (*select)(struct ipt_dstlimit_htable *ht,
5433 + struct dsthash_ent *he))
5437 + IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
5439 + /* lock hash table and iterate over it */
5440 + LOCK_BH(&ht->lock);
5441 + for (i = 0; i < ht->cfg.size; i++) {
5442 + struct dsthash_ent *dh, *n;
5443 + list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
5444 + if ((*select)(ht, dh))
5445 + __dsthash_free(ht, dh);
5448 + UNLOCK_BH(&ht->lock);
5451 +/* hash table garbage collector, run by timer */
5452 +static void htable_gc(unsigned long htlong)
5454 + struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
5456 + htable_selective_cleanup(ht, select_gc);
5458 + /* re-add the timer accordingly */
5459 + ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
5460 + add_timer(&ht->timer);
5463 +static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
5465 + /* remove timer, if it is pending */
5466 + if (timer_pending(&hinfo->timer))
5467 + del_timer(&hinfo->timer);
5469 + /* remove proc entry */
5470 + remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
5472 + htable_selective_cleanup(hinfo, select_all);
5476 +static struct ipt_dstlimit_htable *htable_find_get(char *name)
5478 + struct ipt_dstlimit_htable *hinfo;
5480 + READ_LOCK(&dstlimit_lock);
5481 + list_for_each_entry(hinfo, &dstlimit_htables, list) {
5482 + if (!strcmp(name, hinfo->pde->name)) {
5483 + atomic_inc(&hinfo->use);
5484 + READ_UNLOCK(&dstlimit_lock);
5488 + READ_UNLOCK(&dstlimit_lock);
5493 +static void htable_put(struct ipt_dstlimit_htable *hinfo)
5495 + if (atomic_dec_and_test(&hinfo->use)) {
5496 + WRITE_LOCK(&dstlimit_lock);
5497 + list_del(&hinfo->list);
5498 + WRITE_UNLOCK(&dstlimit_lock);
5499 + htable_destroy(hinfo);
5504 +/* The algorithm used is the Simple Token Bucket Filter (TBF)
5505 + * see net/sched/sch_tbf.c in the linux source tree
5508 +/* Rusty: This is my (non-mathematically-inclined) understanding of
5509 + this algorithm. The `average rate' in jiffies becomes your initial
5510 + amount of credit `credit' and the most credit you can ever have
5511 + `credit_cap'. The `peak rate' becomes the cost of passing the
5514 + `prev' tracks the last packet hit: you gain one credit per jiffy.
5515 + If you get credit balance more than this, the extra credit is
5516 + discarded. Every time the match passes, you lose `cost' credits;
5517 + if you don't have that many, the test fails.
5519 + See Alexey's formal explanation in net/sched/sch_tbf.c.
5521 + To get the maximum range, we multiply by this factor (ie. you get N
5522 + credits per jiffy). We want to allow a rate as low as 1 per day
5523 + (slowest userspace tool allows), which means
5524 + CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
5526 +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
5528 +/* Repeated shift and or gives us all 1s, final shift and add 1 gives
5529 + * us the power of 2 below the theoretical max, so GCC simply does a
5531 +#define _POW2_BELOW2(x) ((x)|((x)>>1))
5532 +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
5533 +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
5534 +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
5535 +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
5536 +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
5538 +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
5540 +/* Precision saver. */
5541 +static inline u_int32_t
5542 +user2credits(u_int32_t user)
5544 + /* If multiplying would overflow... */
5545 + if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
5546 + /* Divide first. */
5547 + return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
5549 + return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
5552 +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
5554 + dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now))
5555 + * CREDITS_PER_JIFFY;
5556 + if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
5557 + dh->rateinfo.credit = dh->rateinfo.credit_cap;
5561 +dstlimit_match(const struct sk_buff *skb,
5562 + const struct net_device *in,
5563 + const struct net_device *out,
5564 + const void *matchinfo,
5568 + struct ipt_dstlimit_info *r =
5569 + ((struct ipt_dstlimit_info *)matchinfo)->u.master;
5570 + struct ipt_dstlimit_htable *hinfo = r->hinfo;
5571 + unsigned long now = jiffies;
5572 + struct dsthash_ent *dh;
5573 + struct dsthash_dst dst;
5575 + memset(&dst, 0, sizeof(dst));
5577 + /* dest ip is always in hash */
5578 + dst.dst_ip = skb->nh.iph->daddr;
5580 + /* source ip only if respective hashmode, otherwise set to
5582 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
5583 + dst.src_ip = skb->nh.iph->saddr;
5585 + /* dest port only if respective mode */
5586 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
5589 + /* Must not be a fragment. */
5593 + /* Must be big enough to read ports (both UDP and TCP have
5594 + them at the start). */
5595 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
5596 + /* We've been asked to examine this packet, and we
5597 + can't. Hence, no choice but to drop. */
5602 + switch (skb->nh.iph->protocol) {
5603 + struct tcphdr *th;
5604 + struct udphdr *uh;
5606 + th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
5607 + dst.port = th->dest;
5610 + uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
5611 + dst.port = uh->dest;
5618 + LOCK_BH(&hinfo->lock);
5619 + dh = __dsthash_find(hinfo, &dst);
5621 + dh = __dsthash_alloc_init(hinfo, &dst);
5624 + /* enomem... don't match == DROP */
5625 + if (net_ratelimit())
5626 + printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
5627 + UNLOCK_BH(&hinfo->lock);
5631 + dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
5633 + dh->rateinfo.prev = jiffies;
5634 + dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
5635 + hinfo->cfg.burst);
5636 + dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
5637 + hinfo->cfg.burst);
5638 + dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
5640 + UNLOCK_BH(&hinfo->lock);
5644 + /* update expiration timeout */
5645 + dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
5647 + rateinfo_recalc(dh, now);
5648 + if (dh->rateinfo.credit >= dh->rateinfo.cost) {
5649 + /* We're underlimit. */
5650 + dh->rateinfo.credit -= dh->rateinfo.cost;
5651 + UNLOCK_BH(&hinfo->lock);
5655 + UNLOCK_BH(&hinfo->lock);
5657 + /* default case: we're overlimit, thus don't match */
5662 +dstlimit_checkentry(const char *tablename,
5663 + const struct ipt_ip *ip,
5665 + unsigned int matchsize,
5666 + unsigned int hook_mask)
5668 + struct ipt_dstlimit_info *r = matchinfo;
5670 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
5673 + /* Check for overflow. */
5674 + if (r->cfg.burst == 0
5675 + || user2credits(r->cfg.avg * r->cfg.burst) <
5676 + user2credits(r->cfg.avg)) {
5677 + printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
5678 + r->cfg.avg, r->cfg.burst);
5682 + if (r->cfg.mode == 0
5683 + || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
5684 + |IPT_DSTLIMIT_HASH_DIP
5685 + |IPT_DSTLIMIT_HASH_SIP))
5688 + if (!r->cfg.gc_interval)
5691 + if (!r->cfg.expire)
5694 + r->hinfo = htable_find_get(r->name);
5695 + if (!r->hinfo && (htable_create(r) != 0)) {
5699 + /* Ugly hack: For SMP, we only want to use one set */
5706 +dstlimit_destroy(void *matchinfo, unsigned int matchsize)
5708 + struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
5710 + htable_put(r->hinfo);
5713 +static struct ipt_match ipt_dstlimit = {
5714 + .list = { .prev = NULL, .next = NULL },
5715 + .name = "dstlimit",
5716 + .match = dstlimit_match,
5717 + .checkentry = dstlimit_checkentry,
5718 + .destroy = dstlimit_destroy,
5724 +static void *dl_seq_start(struct seq_file *s, loff_t *pos)
5726 + struct proc_dir_entry *pde = s->private;
5727 + struct ipt_dstlimit_htable *htable = pde->data;
5728 + unsigned int *bucket;
5730 + LOCK_BH(&htable->lock);
5731 + if (*pos >= htable->cfg.size)
5734 + bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
5736 + return ERR_PTR(-ENOMEM);
5742 +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
5744 + struct proc_dir_entry *pde = s->private;
5745 + struct ipt_dstlimit_htable *htable = pde->data;
5746 + unsigned int *bucket = (unsigned int *)v;
5748 + *pos = ++(*bucket);
5749 + if (*pos >= htable->cfg.size) {
5756 +static void dl_seq_stop(struct seq_file *s, void *v)
5758 + struct proc_dir_entry *pde = s->private;
5759 + struct ipt_dstlimit_htable *htable = pde->data;
5760 + unsigned int *bucket = (unsigned int *)v;
5764 + UNLOCK_BH(&htable->lock);
5767 +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
5769 + /* recalculate to show accurate numbers */
5770 + rateinfo_recalc(ent, jiffies);
5772 + return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
5773 + (ent->expires - jiffies)/HZ,
5774 + NIPQUAD(ent->dst.src_ip),
5775 + NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
5776 + ent->rateinfo.credit, ent->rateinfo.credit_cap,
5777 + ent->rateinfo.cost);
5780 +static int dl_seq_show(struct seq_file *s, void *v)
5782 + struct proc_dir_entry *pde = s->private;
5783 + struct ipt_dstlimit_htable *htable = pde->data;
5784 + unsigned int *bucket = (unsigned int *)v;
5786 + if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
5787 + struct dsthash_ent *, s)) {
5788 + /* buffer was filled and unable to print that tuple */
5794 +static struct seq_operations dl_seq_ops = {
5795 + .start = dl_seq_start,
5796 + .next = dl_seq_next,
5797 + .stop = dl_seq_stop,
5798 + .show = dl_seq_show
5801 +static int dl_proc_open(struct inode *inode, struct file *file)
5803 + int ret = seq_open(file, &dl_seq_ops);
5806 + struct seq_file *sf = file->private_data;
5807 + sf->private = PDE(inode);
5812 +static struct file_operations dl_file_ops = {
5813 + .owner = THIS_MODULE,
5814 + .open = dl_proc_open,
5816 + .llseek = seq_lseek,
5817 + .release = seq_release
5820 +static int init_or_fini(int fini)
5827 + if (ipt_register_match(&ipt_dstlimit)) {
5829 + goto cleanup_nothing;
5832 + /* FIXME: do we really want HWCACHE_ALIGN since our objects are
5833 + * quite small ? */
5834 + dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
5835 + sizeof(struct dsthash_ent), 0,
5836 + SLAB_HWCACHE_ALIGN, NULL, NULL);
5837 + if (!dstlimit_cachep) {
5838 + printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
5840 + goto cleanup_unreg_match;
5843 + dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
5844 + if (!dstlimit_procdir) {
5845 + printk(KERN_ERR "Unable to create proc dir entry\n");
5847 + goto cleanup_free_slab;
5853 + remove_proc_entry("ipt_dstlimit", proc_net);
5855 + kmem_cache_destroy(dstlimit_cachep);
5856 +cleanup_unreg_match:
5857 + ipt_unregister_match(&ipt_dstlimit);
5863 +static int __init init(void)
5865 + return init_or_fini(0);
5868 +static void __exit fini(void)
5875 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.3/net/ipv4/netfilter/ipt_fuzzy.c
5876 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
5877 +++ linux-2.6.3/net/ipv4/netfilter/ipt_fuzzy.c 2004-02-27 00:03:09.360805120 +0100
5880 + * This module implements a simple TSK FLC
5881 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
5882 + * to limit , in an adaptive and flexible way , the packet rate crossing
5883 + * a given stream . It serves as an initial and very simple (but effective)
5884 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
5885 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
5886 + * into our code in a precise , adaptive and efficient manner.
5887 + * The goal is very similar to that of "limit" match , but using techniques of
5888 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
5889 + * avoiding over and undershoots - and stuff like that .
5892 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
5893 + * 2002-08-17 : Changed to eliminate floating point operations .
5894 + * 2002-08-23 : Coding style changes .
5897 +#include <linux/module.h>
5898 +#include <linux/skbuff.h>
5899 +#include <linux/ip.h>
5900 +#include <linux/random.h>
5901 +#include <net/tcp.h>
5902 +#include <linux/spinlock.h>
5903 +#include <linux/netfilter_ipv4/ip_tables.h>
5904 +#include <linux/netfilter_ipv4/ipt_fuzzy.h>
5907 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
5908 + Expressed in percentage
5911 +#define PAR_LOW 1/100
5914 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
5916 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
5917 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
5918 +MODULE_LICENSE("GPL");
5920 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
5928 + return ( (100*(tx-mini)) / (maxi-mini) );
5931 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
5939 + return ( (100*( maxi - tx )) / ( maxi - mini ) );
5943 +ipt_fuzzy_match(const struct sk_buff *pskb,
5944 + const struct net_device *in,
5945 + const struct net_device *out,
5946 + const void *matchinfo,
5950 + /* From userspace */
5952 + struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
5954 + u_int8_t random_number;
5955 + unsigned long amount;
5956 + u_int8_t howhigh, howlow;
5959 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
5961 + info->bytes_total += pskb->len;
5962 + info->packets_total++;
5964 + info->present_time = jiffies;
5966 + if (info->present_time >= info->previous_time)
5967 + amount = info->present_time - info->previous_time;
5969 + /* There was a transition : I choose to re-sample
5970 + and keep the old acceptance rate...
5974 + info->previous_time = info->present_time;
5975 + info->bytes_total = info->packets_total = 0;
5978 + if (amount > HZ/10) /* More than 100 ms elapsed ... */
5981 + info->mean_rate = (u_int32_t) ((HZ*info->packets_total) \
5984 + info->previous_time = info->present_time;
5985 + info->bytes_total = info->packets_total = 0;
5987 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
5988 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
5990 + info->acceptance_rate = (u_int8_t) \
5991 + (howhigh*PAR_LOW + PAR_HIGH*howlow);
5993 + /* In fact , the above defuzzification would require a denominator
5994 + proportional to (howhigh+howlow) but , in this particular case ,
5995 + that expression is constant .
5996 + An imediate consequence is that it isn't necessary to call
5997 + both mf_high and mf_low - but to keep things understandable ,
6002 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
6005 + if ( info->acceptance_rate < 100 )
6007 + get_random_bytes((void *)(&random_number), 1);
6009 + /* If within the acceptance , it can pass => don't match */
6010 + if (random_number <= (255 * info->acceptance_rate) / 100)
6013 + return 1; /* It can't pass ( It matches ) */
6016 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
6021 +ipt_fuzzy_checkentry(const char *tablename,
6022 + const struct ipt_ip *e,
6024 + unsigned int matchsize,
6025 + unsigned int hook_mask)
6028 + const struct ipt_fuzzy_info *info = matchinfo;
6030 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
6031 + printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
6032 + IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
6036 + if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
6037 + || (info->minimum_rate >= info->maximum_rate )) {
6038 + printk("ipt_fuzzy: BAD limits , please verify !!!\n");
6045 +static struct ipt_match ipt_fuzzy_reg = {
6047 + .match = ipt_fuzzy_match,
6048 + .checkentry = ipt_fuzzy_checkentry,
6052 +static int __init init(void)
6054 + return ipt_register_match(&ipt_fuzzy_reg);
6057 +static void __exit fini(void)
6059 + ipt_unregister_match(&ipt_fuzzy_reg);
6064 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.3/net/ipv4/netfilter/ipt_ipv4options.c
6065 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_ipv4options.c 1970-01-01 01:00:00.000000000 +0100
6066 +++ linux-2.6.3/net/ipv4/netfilter/ipt_ipv4options.c 2004-02-27 00:03:10.065697960 +0100
6069 + This is a module which is used to match ipv4 options.
6070 + This file is distributed under the terms of the GNU General Public
6071 + License (GPL). Copies of the GPL can be obtained from:
6072 + ftp://prep.ai.mit.edu/pub/gnu/GPL
6074 + 11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
6075 + 12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
6076 + 12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
6077 + 18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
6078 + 19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
6081 +#include <linux/module.h>
6082 +#include <linux/skbuff.h>
6083 +#include <net/ip.h>
6085 +#include <linux/netfilter_ipv4/ip_tables.h>
6086 +#include <linux/netfilter_ipv4/ipt_ipv4options.h>
6088 +MODULE_LICENSE("GPL");
6089 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
6092 +match(const struct sk_buff *skb,
6093 + const struct net_device *in,
6094 + const struct net_device *out,
6095 + const void *matchinfo,
6099 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
6100 + const struct iphdr *iph = skb->nh.iph;
6101 + const struct ip_options *opt;
6103 + if (iph->ihl * 4 == sizeof(struct iphdr)) {
6104 + /* No options, so we match only the "DONTs" and the "IGNOREs" */
6106 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
6107 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
6108 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
6109 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
6110 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
6111 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
6116 + if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
6117 + /* there are options, and we don't need to care which one */
6120 + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
6121 + /* there are options but we don't want any ! */
6126 + opt = &(IPCB(skb)->opt);
6128 + /* source routing */
6129 + if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
6130 + if (!((opt->srr) & (opt->is_strictroute)))
6133 + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
6134 + if (!((opt->srr) & (!opt->is_strictroute)))
6137 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
6141 + /* record route */
6142 + if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
6146 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
6151 + if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
6155 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
6159 + /* router-alert option */
6160 + if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
6161 + if (!opt->router_alert)
6164 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
6165 + if (opt->router_alert)
6174 +checkentry(const char *tablename,
6175 + const struct ipt_ip *ip,
6177 + unsigned int matchsize,
6178 + unsigned int hook_mask)
6180 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
6181 + /* Check the size */
6182 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
6184 + /* Now check the coherence of the data ... */
6185 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
6186 + (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
6187 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
6188 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
6189 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
6190 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
6191 + return 0; /* opposites */
6192 + if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
6193 + (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
6194 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
6195 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
6196 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
6197 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
6198 + ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
6199 + return 0; /* opposites */
6200 + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
6201 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
6202 + return 0; /* cannot match in the same time loose and strict source routing */
6203 + if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
6204 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
6205 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
6206 + return 0; /* opposites */
6207 + if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
6208 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
6209 + return 0; /* opposites */
6210 + if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
6211 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
6212 + return 0; /* opposites */
6213 + if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
6214 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
6215 + return 0; /* opposites */
6217 + /* everything looks ok. */
6221 +static struct ipt_match ipv4options_match = {
6222 + .name = "ipv4options",
6224 + .checkentry = checkentry,
6228 +static int __init init(void)
6230 + return ipt_register_match(&ipv4options_match);
6233 +static void __exit fini(void)
6235 + ipt_unregister_match(&ipv4options_match);
6240 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.3/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
6241 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 01:00:00.000000000 +0100
6242 +++ linux-2.6.3/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-02-27 00:03:05.931326480 +0100
6245 + * Strip all IP options in the IP packet header.
6247 + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
6248 + * This software is distributed under GNU GPL v2, 1991
6251 +#include <linux/module.h>
6252 +#include <linux/skbuff.h>
6253 +#include <linux/ip.h>
6254 +#include <net/checksum.h>
6256 +#include <linux/netfilter_ipv4/ip_tables.h>
6258 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
6259 +MODULE_DESCRIPTION("Strip all options in IPv4 packets");
6260 +MODULE_LICENSE("GPL");
6262 +static unsigned int
6263 +target(struct sk_buff **pskb,
6264 + const struct net_device *in,
6265 + const struct net_device *out,
6266 + unsigned int hooknum,
6267 + const void *targinfo,
6270 + struct iphdr *iph;
6271 + struct sk_buff *skb;
6272 + struct ip_options *opt;
6273 + unsigned char *optiph;
6276 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
6280 + iph = (*pskb)->nh.iph;
6281 + optiph = skb->nh.raw;
6282 + l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
6284 + /* if no options in packet then nothing to clear. */
6285 + if (iph->ihl * 4 == sizeof(struct iphdr))
6286 + return IPT_CONTINUE;
6288 + /* else clear all options */
6289 + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
6290 + memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
6291 + opt = &(IPCB(skb)->opt);
6295 + skb->nfcache |= NFC_ALTERED;
6297 + return IPT_CONTINUE;
6301 +checkentry(const char *tablename,
6302 + const struct ipt_entry *e,
6304 + unsigned int targinfosize,
6305 + unsigned int hook_mask)
6307 + if (strcmp(tablename, "mangle")) {
6308 + printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
6311 + /* nothing else to check because no parameters */
6315 +static struct ipt_target ipt_ipv4optsstrip_reg = {
6316 + .name = "IPV4OPTSSTRIP",
6318 + .checkentry = checkentry,
6319 + .me = THIS_MODULE };
6321 +static int __init init(void)
6323 + return ipt_register_target(&ipt_ipv4optsstrip_reg);
6326 +static void __exit fini(void)
6328 + ipt_unregister_target(&ipt_ipv4optsstrip_reg);
6333 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_LOG.c linux-2.6.3/net/ipv4/netfilter/ipt_LOG.c
6334 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_LOG.c 2004-02-18 04:59:20.000000000 +0100
6335 +++ linux-2.6.3/net/ipv4/netfilter/ipt_LOG.c 2004-02-27 00:03:00.002227840 +0100
6337 #include <net/tcp.h>
6338 #include <net/route.h>
6340 +#include <linux/netfilter.h>
6341 #include <linux/netfilter_ipv4/ip_tables.h>
6342 #include <linux/netfilter_ipv4/ipt_LOG.h>
6345 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6346 MODULE_DESCRIPTION("iptables syslog logging module");
6348 +static unsigned int nflog = 1;
6349 +MODULE_PARM(nflog, "i");
6350 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
6353 #define DEBUGP printk
6355 @@ -324,28 +329,25 @@
6356 /* maxlen = 230+ 91 + 230 + 252 = 803 */
6359 -static unsigned int
6360 -ipt_log_target(struct sk_buff **pskb,
6362 +ipt_log_packet(unsigned int hooknum,
6363 + const struct sk_buff *skb,
6364 const struct net_device *in,
6365 const struct net_device *out,
6366 - unsigned int hooknum,
6367 - const void *targinfo,
6369 + const struct ipt_log_info *loginfo,
6370 + const char *level_string,
6371 + const char *prefix)
6373 - const struct ipt_log_info *loginfo = targinfo;
6374 - char level_string[4] = "< >";
6376 - level_string[1] = '0' + (loginfo->level % 8);
6377 spin_lock_bh(&log_lock);
6378 printk(level_string);
6379 printk("%sIN=%s OUT=%s ",
6381 + prefix == NULL ? loginfo->prefix : prefix,
6383 out ? out->name : "");
6384 #ifdef CONFIG_BRIDGE_NETFILTER
6385 - if ((*pskb)->nf_bridge) {
6386 - struct net_device *physindev = (*pskb)->nf_bridge->physindev;
6387 - struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
6388 + if (skb->nf_bridge) {
6389 + struct net_device *physindev = skb->nf_bridge->physindev;
6390 + struct net_device *physoutdev = skb->nf_bridge->physoutdev;
6392 if (physindev && in != physindev)
6393 printk("PHYSIN=%s ", physindev->name);
6394 @@ -357,25 +359,56 @@
6396 /* MAC logging for input chain only. */
6398 - if ((*pskb)->dev && (*pskb)->dev->hard_header_len
6399 - && (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
6400 + if (skb->dev && skb->dev->hard_header_len
6401 + && skb->mac.raw != (void*)skb->nh.iph) {
6403 - unsigned char *p = (*pskb)->mac.raw;
6404 - for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
6405 + unsigned char *p = skb->mac.raw;
6406 + for (i = 0; i < skb->dev->hard_header_len; i++,p++)
6407 printk("%02x%c", *p,
6408 - i==(*pskb)->dev->hard_header_len - 1
6409 + i==skb->dev->hard_header_len - 1
6415 - dump_packet(loginfo, *pskb, 0);
6416 + dump_packet(loginfo, skb, 0);
6418 spin_unlock_bh(&log_lock);
6421 +static unsigned int
6422 +ipt_log_target(struct sk_buff **pskb,
6423 + const struct net_device *in,
6424 + const struct net_device *out,
6425 + unsigned int hooknum,
6426 + const void *targinfo,
6429 + const struct ipt_log_info *loginfo = targinfo;
6430 + char level_string[4] = "< >";
6432 + level_string[1] = '0' + (loginfo->level % 8);
6433 + ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
6435 return IPT_CONTINUE;
6439 +ipt_logfn(unsigned int hooknum,
6440 + const struct sk_buff *skb,
6441 + const struct net_device *in,
6442 + const struct net_device *out,
6443 + const char *prefix)
6445 + struct ipt_log_info loginfo = {
6447 + .logflags = IPT_LOG_MASK,
6451 + ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
6454 static int ipt_log_checkentry(const char *tablename,
6455 const struct ipt_entry *e,
6457 @@ -413,11 +446,16 @@
6459 static int __init init(void)
6462 + nf_log_register(PF_INET, &ipt_logfn);
6463 return ipt_register_target(&ipt_log_reg);
6466 static void __exit fini(void)
6469 + nf_log_unregister(PF_INET, &ipt_logfn);
6471 ipt_unregister_target(&ipt_log_reg);
6474 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_LOG.c.orig linux-2.6.3/net/ipv4/netfilter/ipt_LOG.c.orig
6475 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_LOG.c.orig 1970-01-01 01:00:00.000000000 +0100
6476 +++ linux-2.6.3/net/ipv4/netfilter/ipt_LOG.c.orig 2004-02-18 04:59:20.000000000 +0100
6479 + * This is a module which is used for logging packets.
6482 +/* (C) 1999-2001 Paul `Rusty' Russell
6483 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
6485 + * This program is free software; you can redistribute it and/or modify
6486 + * it under the terms of the GNU General Public License version 2 as
6487 + * published by the Free Software Foundation.
6490 +#include <linux/module.h>
6491 +#include <linux/spinlock.h>
6492 +#include <linux/skbuff.h>
6493 +#include <linux/ip.h>
6494 +#include <net/icmp.h>
6495 +#include <net/udp.h>
6496 +#include <net/tcp.h>
6497 +#include <net/route.h>
6499 +#include <linux/netfilter_ipv4/ip_tables.h>
6500 +#include <linux/netfilter_ipv4/ipt_LOG.h>
6502 +MODULE_LICENSE("GPL");
6503 +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6504 +MODULE_DESCRIPTION("iptables syslog logging module");
6507 +#define DEBUGP printk
6509 +#define DEBUGP(format, args...)
6512 +/* Use lock to serialize, so printks don't overlap */
6513 +static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
6515 +/* One level of recursion won't kill us */
6516 +static void dump_packet(const struct ipt_log_info *info,
6517 + const struct sk_buff *skb,
6518 + unsigned int iphoff)
6522 + if (skb_copy_bits(skb, iphoff, &iph, sizeof(iph)) < 0) {
6523 + printk("TRUNCATED");
6527 + /* Important fields:
6528 + * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
6529 + /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
6530 + printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ",
6531 + NIPQUAD(iph.saddr), NIPQUAD(iph.daddr));
6533 + /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
6534 + printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
6535 + ntohs(iph.tot_len), iph.tos & IPTOS_TOS_MASK,
6536 + iph.tos & IPTOS_PREC_MASK, iph.ttl, ntohs(iph.id));
6538 + /* Max length: 6 "CE DF MF " */
6539 + if (ntohs(iph.frag_off) & IP_CE)
6541 + if (ntohs(iph.frag_off) & IP_DF)
6543 + if (ntohs(iph.frag_off) & IP_MF)
6546 + /* Max length: 11 "FRAG:65535 " */
6547 + if (ntohs(iph.frag_off) & IP_OFFSET)
6548 + printk("FRAG:%u ", ntohs(iph.frag_off) & IP_OFFSET);
6550 + if ((info->logflags & IPT_LOG_IPOPT)
6551 + && iph.ihl * 4 != sizeof(struct iphdr)) {
6552 + unsigned char opt[4 * 15 - sizeof(struct iphdr)];
6553 + unsigned int i, optsize;
6555 + optsize = iph.ihl * 4 - sizeof(struct iphdr);
6556 + if (skb_copy_bits(skb, iphoff+sizeof(iph), opt, optsize) < 0) {
6557 + printk("TRUNCATED");
6561 + /* Max length: 127 "OPT (" 15*4*2chars ") " */
6563 + for (i = 0; i < optsize; i++)
6564 + printk("%02X", opt[i]);
6568 + switch (iph.protocol) {
6569 + case IPPROTO_TCP: {
6570 + struct tcphdr tcph;
6572 + /* Max length: 10 "PROTO=TCP " */
6573 + printk("PROTO=TCP ");
6575 + if (ntohs(iph.frag_off) & IP_OFFSET)
6578 + /* Max length: 25 "INCOMPLETE [65535 bytes] " */
6579 + if (skb_copy_bits(skb, iphoff+iph.ihl*4, &tcph, sizeof(tcph))
6581 + printk("INCOMPLETE [%u bytes] ",
6582 + skb->len - iphoff - iph.ihl*4);
6586 + /* Max length: 20 "SPT=65535 DPT=65535 " */
6587 + printk("SPT=%u DPT=%u ",
6588 + ntohs(tcph.source), ntohs(tcph.dest));
6589 + /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
6590 + if (info->logflags & IPT_LOG_TCPSEQ)
6591 + printk("SEQ=%u ACK=%u ",
6592 + ntohl(tcph.seq), ntohl(tcph.ack_seq));
6593 + /* Max length: 13 "WINDOW=65535 " */
6594 + printk("WINDOW=%u ", ntohs(tcph.window));
6595 + /* Max length: 9 "RES=0x3F " */
6596 + printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(&tcph) & TCP_RESERVED_BITS) >> 22));
6597 + /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
6614 + /* Max length: 11 "URGP=65535 " */
6615 + printk("URGP=%u ", ntohs(tcph.urg_ptr));
6617 + if ((info->logflags & IPT_LOG_TCPOPT)
6618 + && tcph.doff * 4 != sizeof(struct tcphdr)) {
6619 + unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
6620 + unsigned int i, optsize;
6622 + optsize = tcph.doff * 4 - sizeof(struct tcphdr);
6623 + if (skb_copy_bits(skb, iphoff+iph.ihl*4 + sizeof(tcph),
6624 + opt, optsize) < 0) {
6625 + printk("TRUNCATED");
6629 + /* Max length: 127 "OPT (" 15*4*2chars ") " */
6631 + for (i = 0; i < optsize; i++)
6632 + printk("%02X", opt[i]);
6637 + case IPPROTO_UDP: {
6638 + struct udphdr udph;
6640 + /* Max length: 10 "PROTO=UDP " */
6641 + printk("PROTO=UDP ");
6643 + if (ntohs(iph.frag_off) & IP_OFFSET)
6646 + /* Max length: 25 "INCOMPLETE [65535 bytes] " */
6647 + if (skb_copy_bits(skb, iphoff+iph.ihl*4, &udph, sizeof(udph))
6649 + printk("INCOMPLETE [%u bytes] ",
6650 + skb->len - iphoff - iph.ihl*4);
6654 + /* Max length: 20 "SPT=65535 DPT=65535 " */
6655 + printk("SPT=%u DPT=%u LEN=%u ",
6656 + ntohs(udph.source), ntohs(udph.dest),
6660 + case IPPROTO_ICMP: {
6661 + struct icmphdr icmph;
6662 + static size_t required_len[NR_ICMP_TYPES+1]
6663 + = { [ICMP_ECHOREPLY] = 4,
6664 + [ICMP_DEST_UNREACH]
6665 + = 8 + sizeof(struct iphdr) + 8,
6666 + [ICMP_SOURCE_QUENCH]
6667 + = 8 + sizeof(struct iphdr) + 8,
6669 + = 8 + sizeof(struct iphdr) + 8,
6671 + [ICMP_TIME_EXCEEDED]
6672 + = 8 + sizeof(struct iphdr) + 8,
6673 + [ICMP_PARAMETERPROB]
6674 + = 8 + sizeof(struct iphdr) + 8,
6675 + [ICMP_TIMESTAMP] = 20,
6676 + [ICMP_TIMESTAMPREPLY] = 20,
6677 + [ICMP_ADDRESS] = 12,
6678 + [ICMP_ADDRESSREPLY] = 12 };
6680 + /* Max length: 11 "PROTO=ICMP " */
6681 + printk("PROTO=ICMP ");
6683 + if (ntohs(iph.frag_off) & IP_OFFSET)
6686 + /* Max length: 25 "INCOMPLETE [65535 bytes] " */
6687 + if (skb_copy_bits(skb, iphoff+iph.ihl*4, &icmph, sizeof(icmph))
6689 + printk("INCOMPLETE [%u bytes] ",
6690 + skb->len - iphoff - iph.ihl*4);
6694 + /* Max length: 18 "TYPE=255 CODE=255 " */
6695 + printk("TYPE=%u CODE=%u ", icmph.type, icmph.code);
6697 + /* Max length: 25 "INCOMPLETE [65535 bytes] " */
6698 + if (icmph.type <= NR_ICMP_TYPES
6699 + && required_len[icmph.type]
6700 + && skb->len-iphoff-iph.ihl*4 < required_len[icmph.type]) {
6701 + printk("INCOMPLETE [%u bytes] ",
6702 + skb->len - iphoff - iph.ihl*4);
6706 + switch (icmph.type) {
6707 + case ICMP_ECHOREPLY:
6709 + /* Max length: 19 "ID=65535 SEQ=65535 " */
6710 + printk("ID=%u SEQ=%u ",
6711 + ntohs(icmph.un.echo.id),
6712 + ntohs(icmph.un.echo.sequence));
6715 + case ICMP_PARAMETERPROB:
6716 + /* Max length: 14 "PARAMETER=255 " */
6717 + printk("PARAMETER=%u ",
6718 + ntohl(icmph.un.gateway) >> 24);
6720 + case ICMP_REDIRECT:
6721 + /* Max length: 24 "GATEWAY=255.255.255.255 " */
6722 + printk("GATEWAY=%u.%u.%u.%u ",
6723 + NIPQUAD(icmph.un.gateway));
6724 + /* Fall through */
6725 + case ICMP_DEST_UNREACH:
6726 + case ICMP_SOURCE_QUENCH:
6727 + case ICMP_TIME_EXCEEDED:
6728 + /* Max length: 3+maxlen */
6729 + if (!iphoff) { /* Only recurse once. */
6731 + dump_packet(info, skb,
6732 + iphoff + iph.ihl*4+sizeof(icmph));
6736 + /* Max length: 10 "MTU=65535 " */
6737 + if (icmph.type == ICMP_DEST_UNREACH
6738 + && icmph.code == ICMP_FRAG_NEEDED)
6739 + printk("MTU=%u ", ntohs(icmph.un.frag.mtu));
6744 + case IPPROTO_AH: {
6745 + struct ip_auth_hdr ah;
6747 + if (ntohs(iph.frag_off) & IP_OFFSET)
6750 + /* Max length: 9 "PROTO=AH " */
6751 + printk("PROTO=AH ");
6753 + /* Max length: 25 "INCOMPLETE [65535 bytes] " */
6754 + if (skb_copy_bits(skb, iphoff+iph.ihl*4, &ah, sizeof(ah)) < 0) {
6755 + printk("INCOMPLETE [%u bytes] ",
6756 + skb->len - iphoff - iph.ihl*4);
6760 + /* Length: 15 "SPI=0xF1234567 " */
6761 + printk("SPI=0x%x ", ntohl(ah.spi));
6764 + case IPPROTO_ESP: {
6765 + struct ip_esp_hdr esph;
6767 + /* Max length: 10 "PROTO=ESP " */
6768 + printk("PROTO=ESP ");
6770 + if (ntohs(iph.frag_off) & IP_OFFSET)
6773 + /* Max length: 25 "INCOMPLETE [65535 bytes] " */
6774 + if (skb_copy_bits(skb, iphoff+iph.ihl*4, &esph, sizeof(esph))
6776 + printk("INCOMPLETE [%u bytes] ",
6777 + skb->len - iphoff - iph.ihl*4);
6781 + /* Length: 15 "SPI=0xF1234567 " */
6782 + printk("SPI=0x%x ", ntohl(esph.spi));
6785 + /* Max length: 10 "PROTO 255 " */
6787 + printk("PROTO=%u ", iph.protocol);
6790 + /* Proto Max log string length */
6791 + /* IP: 40+46+6+11+127 = 230 */
6792 + /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */
6793 + /* UDP: 10+max(25,20) = 35 */
6794 + /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
6795 + /* ESP: 10+max(25)+15 = 50 */
6796 + /* AH: 9+max(25)+15 = 49 */
6799 + /* (ICMP allows recursion one level deep) */
6800 + /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */
6801 + /* maxlen = 230+ 91 + 230 + 252 = 803 */
6804 +static unsigned int
6805 +ipt_log_target(struct sk_buff **pskb,
6806 + const struct net_device *in,
6807 + const struct net_device *out,
6808 + unsigned int hooknum,
6809 + const void *targinfo,
6812 + const struct ipt_log_info *loginfo = targinfo;
6813 + char level_string[4] = "< >";
6815 + level_string[1] = '0' + (loginfo->level % 8);
6816 + spin_lock_bh(&log_lock);
6817 + printk(level_string);
6818 + printk("%sIN=%s OUT=%s ",
6820 + in ? in->name : "",
6821 + out ? out->name : "");
6822 +#ifdef CONFIG_BRIDGE_NETFILTER
6823 + if ((*pskb)->nf_bridge) {
6824 + struct net_device *physindev = (*pskb)->nf_bridge->physindev;
6825 + struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
6827 + if (physindev && in != physindev)
6828 + printk("PHYSIN=%s ", physindev->name);
6829 + if (physoutdev && out != physoutdev)
6830 + printk("PHYSOUT=%s ", physoutdev->name);
6835 + /* MAC logging for input chain only. */
6837 + if ((*pskb)->dev && (*pskb)->dev->hard_header_len
6838 + && (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
6840 + unsigned char *p = (*pskb)->mac.raw;
6841 + for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
6842 + printk("%02x%c", *p,
6843 + i==(*pskb)->dev->hard_header_len - 1
6849 + dump_packet(loginfo, *pskb, 0);
6851 + spin_unlock_bh(&log_lock);
6853 + return IPT_CONTINUE;
6856 +static int ipt_log_checkentry(const char *tablename,
6857 + const struct ipt_entry *e,
6859 + unsigned int targinfosize,
6860 + unsigned int hook_mask)
6862 + const struct ipt_log_info *loginfo = targinfo;
6864 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_log_info))) {
6865 + DEBUGP("LOG: targinfosize %u != %u\n",
6866 + targinfosize, IPT_ALIGN(sizeof(struct ipt_log_info)));
6870 + if (loginfo->level >= 8) {
6871 + DEBUGP("LOG: level %u >= 8\n", loginfo->level);
6875 + if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
6876 + DEBUGP("LOG: prefix term %i\n",
6877 + loginfo->prefix[sizeof(loginfo->prefix)-1]);
6884 +static struct ipt_target ipt_log_reg = {
6886 + .target = ipt_log_target,
6887 + .checkentry = ipt_log_checkentry,
6888 + .me = THIS_MODULE,
6891 +static int __init init(void)
6893 + return ipt_register_target(&ipt_log_reg);
6896 +static void __exit fini(void)
6898 + ipt_unregister_target(&ipt_log_reg);
6903 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.3/net/ipv4/netfilter/ipt_mport.c
6904 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 01:00:00.000000000 +0100
6905 +++ linux-2.6.3/net/ipv4/netfilter/ipt_mport.c 2004-02-27 00:03:10.772590496 +0100
6907 +/* Kernel module to match one of a list of TCP/UDP ports: ports are in
6908 + the same place so we can treat them as equal. */
6909 +#include <linux/module.h>
6910 +#include <linux/types.h>
6911 +#include <linux/udp.h>
6912 +#include <linux/skbuff.h>
6914 +#include <linux/netfilter_ipv4/ipt_mport.h>
6915 +#include <linux/netfilter_ipv4/ip_tables.h>
6917 +MODULE_LICENSE("GPL");
6920 +#define duprintf(format, args...) printk(format , ## args)
6922 +#define duprintf(format, args...)
6925 +/* Returns 1 if the port is matched by the test, 0 otherwise. */
6927 +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
6931 + u_int16_t pflags = minfo->pflags;
6932 + for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
6936 + && minfo->ports[i] == 65535)
6939 + s = minfo->ports[i];
6942 + e = minfo->ports[++i];
6947 + if (minfo->flags & IPT_MPORT_SOURCE
6948 + && src >= s && src <= e)
6951 + if (minfo->flags & IPT_MPORT_DESTINATION
6952 + && dst >= s && dst <= e)
6960 +match(const struct sk_buff *skb,
6961 + const struct net_device *in,
6962 + const struct net_device *out,
6963 + const void *matchinfo,
6968 + const struct ipt_mport *minfo = matchinfo;
6973 + /* Must be big enough to read ports (both UDP and TCP have
6974 + them at the start). */
6975 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
6976 + /* We've been asked to examine this packet, and we
6977 + can't. Hence, no choice but to drop. */
6978 + duprintf("ipt_multiport:"
6979 + " Dropping evil offset=0 tinygram.\n");
6984 + return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
6987 +/* Called when user tries to insert an entry of this type. */
6989 +checkentry(const char *tablename,
6990 + const struct ipt_ip *ip,
6992 + unsigned int matchsize,
6993 + unsigned int hook_mask)
6995 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
6998 + /* Must specify proto == TCP/UDP, no unknown flags or bad count */
6999 + return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
7000 + && !(ip->invflags & IPT_INV_PROTO)
7001 + && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
7004 +static struct ipt_match mport_match = {
7007 + .checkentry = &checkentry,
7011 +static int __init init(void)
7013 + return ipt_register_match(&mport_match);
7016 +static void __exit fini(void)
7018 + ipt_unregister_match(&mport_match);
7023 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_NOTRACK.c linux-2.6.3/net/ipv4/netfilter/ipt_NOTRACK.c
7024 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_NOTRACK.c 1970-01-01 01:00:00.000000000 +0100
7025 +++ linux-2.6.3/net/ipv4/netfilter/ipt_NOTRACK.c 2004-02-27 00:03:14.469028552 +0100
7027 +/* This is a module which is used for setting up fake conntracks
7028 + * on packets so that they are not seen by the conntrack/NAT code.
7030 +#include <linux/module.h>
7031 +#include <linux/skbuff.h>
7033 +#include <linux/netfilter_ipv4/ip_tables.h>
7034 +#include <linux/netfilter_ipv4/ip_conntrack.h>
7036 +static unsigned int
7037 +target(struct sk_buff **pskb,
7038 + const struct net_device *in,
7039 + const struct net_device *out,
7040 + unsigned int hooknum,
7041 + const void *targinfo,
7044 + /* Previously seen (loopback)? Ignore. */
7045 + if ((*pskb)->nfct != NULL)
7046 + return IPT_CONTINUE;
7048 + /* Attach fake conntrack entry.
7049 + If there is a real ct entry correspondig to this packet,
7050 + it'll hang aroun till timing out. We don't deal with it
7051 + for performance reasons. JK */
7052 + (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
7053 + nf_conntrack_get((*pskb)->nfct);
7055 + return IPT_CONTINUE;
7059 +checkentry(const char *tablename,
7060 + const struct ipt_entry *e,
7062 + unsigned int targinfosize,
7063 + unsigned int hook_mask)
7065 + if (targinfosize != 0) {
7066 + printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
7071 + if (strcmp(tablename, "raw") != 0) {
7072 + printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
7079 +static struct ipt_target ipt_notrack_reg = {
7080 + .name = "NOTRACK",
7082 + .checkentry = checkentry,
7086 +static int __init init(void)
7088 + if (ipt_register_target(&ipt_notrack_reg))
7094 +static void __exit fini(void)
7096 + ipt_unregister_target(&ipt_notrack_reg);
7101 +MODULE_LICENSE("GPL");
7102 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.3/net/ipv4/netfilter/ipt_nth.c
7103 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 01:00:00.000000000 +0100
7104 +++ linux-2.6.3/net/ipv4/netfilter/ipt_nth.c 2004-02-27 00:03:12.719294552 +0100
7107 + This is a module which is used for match support for every Nth packet
7108 + This file is distributed under the terms of the GNU General Public
7109 + License (GPL). Copies of the GPL can be obtained from:
7110 + ftp://prep.ai.mit.edu/pub/gnu/GPL
7112 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
7113 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
7114 + * added support for multiple counters
7115 + * added support for matching on individual packets
7116 + in the counter cycle
7117 + 2004-02-19 Harald Welte <laforge@netfilter.org>
7122 +#include <linux/module.h>
7123 +#include <linux/skbuff.h>
7124 +#include <linux/ip.h>
7125 +#include <net/tcp.h>
7126 +#include <linux/spinlock.h>
7127 +#include <linux/netfilter_ipv4/ip_tables.h>
7128 +#include <linux/netfilter_ipv4/ipt_nth.h>
7130 +MODULE_LICENSE("GPL");
7131 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
7134 + * State information.
7141 +static struct state states[IPT_NTH_NUM_COUNTERS];
7144 +ipt_nth_match(const struct sk_buff *pskb,
7145 + const struct net_device *in,
7146 + const struct net_device *out,
7147 + const void *matchinfo,
7151 + /* Parameters from userspace */
7152 + const struct ipt_nth_info *info = matchinfo;
7153 + unsigned counter = info->counter;
7154 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
7156 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
7160 + spin_lock(&states[counter].lock);
7162 + /* Are we matching every nth packet?*/
7163 + if (info->packet == 0xFF)
7165 + /* We're matching every nth packet and only every nth packet*/
7166 + /* Do we match or invert match? */
7167 + if (info->not == 0)
7169 + if (states[counter].number == 0)
7171 + ++states[counter].number;
7174 + if (states[counter].number >= info->every)
7175 + states[counter].number = 0; /* reset the counter */
7177 + ++states[counter].number;
7182 + if (states[counter].number == 0)
7184 + ++states[counter].number;
7187 + if (states[counter].number >= info->every)
7188 + states[counter].number = 0;
7190 + ++states[counter].number;
7196 + /* We're using the --packet, so there must be a rule for every value */
7197 + if (states[counter].number == info->packet)
7199 + /* only increment the counter when a match happens */
7200 + if (states[counter].number >= info->every)
7201 + states[counter].number = 0; /* reset the counter */
7203 + ++states[counter].number;
7212 + spin_unlock(&states[counter].lock);
7216 + spin_unlock(&states[counter].lock);
7221 +ipt_nth_checkentry(const char *tablename,
7222 + const struct ipt_ip *e,
7224 + unsigned int matchsize,
7225 + unsigned int hook_mask)
7227 + /* Parameters from userspace */
7228 + const struct ipt_nth_info *info = matchinfo;
7229 + unsigned counter = info->counter;
7230 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
7232 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
7236 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
7237 + printk("nth: matchsize %u != %u\n", matchsize,
7238 + IPT_ALIGN(sizeof(struct ipt_nth_info)));
7242 + states[counter].number = info->startat;
7247 +static struct ipt_match ipt_nth_reg = {
7249 + .match = ipt_nth_match,
7250 + .checkentry = ipt_nth_checkentry,
7254 +static int __init init(void)
7258 + memset(&states, 0, sizeof(states));
7259 + for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++)
7260 + spin_lock_init(&(states[counter].lock));
7262 + return ipt_register_match(&ipt_nth_reg);
7265 +static void __exit fini(void)
7267 + ipt_unregister_match(&ipt_nth_reg);
7272 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.3/net/ipv4/netfilter/ipt_quota.c
7273 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 01:00:00.000000000 +0100
7274 +++ linux-2.6.3/net/ipv4/netfilter/ipt_quota.c 2004-02-27 00:03:13.672149696 +0100
7277 + * netfilter module to enforce network quotas
7279 + * Sam Johnston <samj@samj.net>
7281 +#include <linux/module.h>
7282 +#include <linux/skbuff.h>
7283 +#include <linux/spinlock.h>
7284 +#include <linux/interrupt.h>
7286 +#include <linux/netfilter_ipv4/ip_tables.h>
7287 +#include <linux/netfilter_ipv4/ipt_quota.h>
7289 +MODULE_LICENSE("GPL");
7290 +MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
7292 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
7295 +match(const struct sk_buff *skb,
7296 + const struct net_device *in,
7297 + const struct net_device *out,
7298 + const void *matchinfo,
7299 + int offset, int *hotdrop)
7301 + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
7302 + unsigned int datalen;
7304 + if (skb->len < sizeof(struct iphdr))
7307 + datalen = skb->len - skb->nh.iph->ihl*4;
7309 + spin_lock_bh("a_lock);
7311 + if (q->quota >= datalen) {
7312 + /* we can afford this one */
7313 + q->quota -= datalen;
7314 + spin_unlock_bh("a_lock);
7316 +#ifdef DEBUG_IPT_QUOTA
7317 + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
7322 + /* so we do not allow even small packets from now on */
7325 +#ifdef DEBUG_IPT_QUOTA
7326 + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
7329 + spin_unlock_bh("a_lock);
7334 +checkentry(const char *tablename,
7335 + const struct ipt_ip *ip,
7336 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
7338 + /* TODO: spinlocks? sanity checks? */
7339 + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
7345 +static struct ipt_match quota_match = {
7348 + .checkentry = checkentry,
7355 + return ipt_register_match("a_match);
7361 + ipt_unregister_match("a_match);
7367 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.3/net/ipv4/netfilter/ipt_realm.c
7368 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 01:00:00.000000000 +0100
7369 +++ linux-2.6.3/net/ipv4/netfilter/ipt_realm.c 2004-02-27 00:03:15.262907864 +0100
7371 +/* Kernel module to match realm from routing. */
7372 +#include <linux/module.h>
7373 +#include <linux/skbuff.h>
7374 +#include <linux/netdevice.h>
7375 +#include <net/route.h>
7377 +#include <linux/netfilter_ipv4/ipt_realm.h>
7378 +#include <linux/netfilter_ipv4/ip_tables.h>
7380 +MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
7381 +MODULE_LICENSE("GPL");
7384 +match(const struct sk_buff *skb,
7385 + const struct net_device *in,
7386 + const struct net_device *out,
7387 + const void *matchinfo,
7391 + const struct ipt_realm_info *info = matchinfo;
7392 + struct dst_entry *dst = skb->dst;
7397 + id = dst->tclassid;
7399 + return (info->id == (id & info->mask)) ^ info->invert;
7402 +static int check(const char *tablename,
7403 + const struct ipt_ip *ip,
7405 + unsigned int matchsize,
7406 + unsigned int hook_mask)
7409 + & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
7410 + (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
7411 + printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
7412 + "LOCAL_IN or FORWARD.\n");
7416 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
7422 +static struct ipt_match realm_match = {
7425 + .checkentry = check,
7429 +static int __init init(void)
7431 + return ipt_register_match(&realm_match);
7434 +static void __exit fini(void)
7436 + ipt_unregister_match(&realm_match);
7441 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.3/net/ipv4/netfilter/ipt_sctp.c
7442 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 01:00:00.000000000 +0100
7443 +++ linux-2.6.3/net/ipv4/netfilter/ipt_sctp.c 2004-02-27 00:03:16.145773648 +0100
7445 +#include <linux/module.h>
7446 +#include <linux/skbuff.h>
7447 +#include <net/ip.h>
7448 +#include <linux/sctp.h>
7450 +#include <linux/netfilter_ipv4/ip_tables.h>
7451 +#include <linux/netfilter_ipv4/ipt_sctp.h>
7453 +MODULE_LICENSE("GPL");
7454 +MODULE_AUTHOR("Kiran Kumar Immidi");
7455 +MODULE_DESCRIPTION("Match for SCTP protocol packets");
7458 +#define duprintf(format, args...) printk(format , ## args)
7460 +#define duprintf(format, args...)
7463 +#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
7464 + || (!!((invflag) & (option)) ^ (cond)))
7466 +match_packet(const struct sk_buff *skb,
7467 + const u_int32_t *chunkmap,
7468 + int chunk_match_type,
7472 + u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
7473 + sctp_chunkhdr_t sch;
7477 + if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
7478 + SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
7481 + offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
7483 + if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
7484 + duprintf("Dropping invalid SCTP packet.\n");
7489 + duprintf("SCTP chunk num: %d\toffset: %d\ttype: %d\tlength: %d\n",
7490 + ++i, offset, sch.type, htons(sch.length));
7492 + offset += (htons(sch.length) + 3) & ~3;
7494 + duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
7496 + if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
7497 + switch (chunk_match_type) {
7498 + case SCTP_CHUNK_MATCH_ANY:
7501 + case SCTP_CHUNK_MATCH_ALL:
7502 + SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
7505 + switch (chunk_match_type) {
7506 + case SCTP_CHUNK_MATCH_ONLY:
7510 + } while (offset < skb->len);
7512 + switch (chunk_match_type) {
7513 + case SCTP_CHUNK_MATCH_ALL:
7514 + return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
7515 + case SCTP_CHUNK_MATCH_ANY:
7517 + case SCTP_CHUNK_MATCH_ONLY:
7521 + /* This will never be reached, but required to stop compiler whine */
7526 +match(const struct sk_buff *skb,
7527 + const struct net_device *in,
7528 + const struct net_device *out,
7529 + const void *matchinfo,
7533 + const struct ipt_sctp_info *info;
7534 + sctp_sctphdr_t sh;
7536 + info = (const struct ipt_sctp_info *)matchinfo;
7539 + duprintf("Dropping non-first fragment.. FIXME\n");
7543 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
7544 + duprintf("Dropping evil TCP offset=0 tinygram.\n");
7548 + duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
7550 + return SCCHECK(((ntohs(sh.source) >= info->spts[0])
7551 + && (ntohs(sh.source) <= info->spts[1])),
7552 + IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
7553 + && SCCHECK(((ntohs(sh.dest) >= info->dpts[0])
7554 + && (ntohs(sh.dest) <= info->dpts[1])),
7555 + IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
7556 + && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
7558 + IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
7562 +checkentry(const char *tablename,
7563 + const struct ipt_ip *ip,
7565 + unsigned int matchsize,
7566 + unsigned int hook_mask)
7568 + const struct ipt_sctp_info *info;
7570 + info = (const struct ipt_sctp_info *)matchinfo;
7572 + return ip->proto == IPPROTO_SCTP
7573 + && !(ip->invflags & IPT_INV_PROTO)
7574 + && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
7575 + && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
7576 + && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
7577 + && !(info->invflags & ~info->flags)
7578 + && !(info->invflags
7579 + & (SCTP_CHUNK_MATCH_ALL
7580 + | SCTP_CHUNK_MATCH_ANY
7581 + | SCTP_CHUNK_MATCH_ONLY));
7584 +static struct ipt_match sctp_match =
7586 + .list = { NULL, NULL},
7589 + .checkentry = &checkentry,
7594 +static int __init init(void)
7596 + return ipt_register_match(&sctp_match);
7599 +static void __exit fini(void)
7601 + ipt_unregister_match(&sctp_match);
7606 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_state.c linux-2.6.3/net/ipv4/netfilter/ipt_state.c
7607 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_state.c 2004-02-18 04:59:55.000000000 +0100
7608 +++ linux-2.6.3/net/ipv4/netfilter/ipt_state.c 2004-02-27 00:03:14.484026272 +0100
7610 enum ip_conntrack_info ctinfo;
7611 unsigned int statebit;
7613 - if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
7614 + if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
7615 + statebit = IPT_STATE_UNTRACKED;
7616 + else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
7617 statebit = IPT_STATE_INVALID;
7619 statebit = IPT_STATE_BIT(ctinfo);
7620 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_state.c.orig linux-2.6.3/net/ipv4/netfilter/ipt_state.c.orig
7621 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_state.c.orig 1970-01-01 01:00:00.000000000 +0100
7622 +++ linux-2.6.3/net/ipv4/netfilter/ipt_state.c.orig 2004-02-18 04:59:55.000000000 +0100
7624 +/* Kernel module to match connection tracking information. */
7626 +/* (C) 1999-2001 Paul `Rusty' Russell
7627 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
7629 + * This program is free software; you can redistribute it and/or modify
7630 + * it under the terms of the GNU General Public License version 2 as
7631 + * published by the Free Software Foundation.
7634 +#include <linux/module.h>
7635 +#include <linux/skbuff.h>
7636 +#include <linux/netfilter_ipv4/ip_conntrack.h>
7637 +#include <linux/netfilter_ipv4/ip_tables.h>
7638 +#include <linux/netfilter_ipv4/ipt_state.h>
7640 +MODULE_LICENSE("GPL");
7641 +MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
7642 +MODULE_DESCRIPTION("iptables connection tracking state match module");
7645 +match(const struct sk_buff *skb,
7646 + const struct net_device *in,
7647 + const struct net_device *out,
7648 + const void *matchinfo,
7652 + const struct ipt_state_info *sinfo = matchinfo;
7653 + enum ip_conntrack_info ctinfo;
7654 + unsigned int statebit;
7656 + if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
7657 + statebit = IPT_STATE_INVALID;
7659 + statebit = IPT_STATE_BIT(ctinfo);
7661 + return (sinfo->statemask & statebit);
7664 +static int check(const char *tablename,
7665 + const struct ipt_ip *ip,
7667 + unsigned int matchsize,
7668 + unsigned int hook_mask)
7670 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_state_info)))
7676 +static struct ipt_match state_match = {
7679 + .checkentry = &check,
7680 + .me = THIS_MODULE,
7683 +static int __init init(void)
7685 + need_ip_conntrack();
7686 + return ipt_register_match(&state_match);
7689 +static void __exit fini(void)
7691 + ipt_unregister_match(&state_match);
7696 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.3/net/ipv4/netfilter/ipt_TTL.c
7697 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100
7698 +++ linux-2.6.3/net/ipv4/netfilter/ipt_TTL.c 2004-02-27 00:03:07.345111552 +0100
7700 +/* TTL modification target for IP tables
7701 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
7705 + * This software is distributed under the terms of GNU GPL
7708 +#include <linux/module.h>
7709 +#include <linux/skbuff.h>
7710 +#include <linux/ip.h>
7711 +#include <net/checksum.h>
7713 +#include <linux/netfilter_ipv4/ip_tables.h>
7714 +#include <linux/netfilter_ipv4/ipt_TTL.h>
7716 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
7717 +MODULE_DESCRIPTION("IP tables TTL modification module");
7718 +MODULE_LICENSE("GPL");
7720 +static unsigned int
7721 +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
7722 + const struct net_device *out, unsigned int hooknum,
7723 + const void *targinfo, void *userinfo)
7725 + struct iphdr *iph;
7726 + const struct ipt_TTL_info *info = targinfo;
7727 + u_int16_t diffs[2];
7730 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
7733 + iph = (*pskb)->nh.iph;
7735 + switch (info->mode) {
7737 + new_ttl = info->ttl;
7740 + new_ttl = iph->ttl + info->ttl;
7741 + if (new_ttl > 255)
7745 + new_ttl = iph->ttl + info->ttl;
7750 + new_ttl = iph->ttl;
7754 + if (new_ttl != iph->ttl) {
7755 + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
7756 + iph->ttl = new_ttl;
7757 + diffs[1] = htons(((unsigned)iph->ttl) << 8);
7758 + iph->check = csum_fold(csum_partial((char *)diffs,
7760 + iph->check^0xFFFF));
7761 + (*pskb)->nfcache |= NFC_ALTERED;
7764 + return IPT_CONTINUE;
7767 +static int ipt_ttl_checkentry(const char *tablename,
7768 + const struct ipt_entry *e,
7770 + unsigned int targinfosize,
7771 + unsigned int hook_mask)
7773 + struct ipt_TTL_info *info = targinfo;
7775 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
7776 + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
7778 + IPT_ALIGN(sizeof(struct ipt_TTL_info)));
7782 + if (strcmp(tablename, "mangle")) {
7783 + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
7787 + if (info->mode > IPT_TTL_MAXMODE) {
7788 + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n",
7793 + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
7794 + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
7801 +static struct ipt_target ipt_TTL = {
7803 + .target = ipt_ttl_target,
7804 + .checkentry = ipt_ttl_checkentry,
7808 +static int __init init(void)
7810 + return ipt_register_target(&ipt_TTL);
7813 +static void __exit fini(void)
7815 + ipt_unregister_target(&ipt_TTL);
7820 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_ULOG.c linux-2.6.3/net/ipv4/netfilter/ipt_ULOG.c
7821 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_ULOG.c 2004-02-18 04:57:24.000000000 +0100
7822 +++ linux-2.6.3/net/ipv4/netfilter/ipt_ULOG.c 2004-02-27 00:03:00.002227840 +0100
7824 #include <linux/netlink.h>
7825 #include <linux/netdevice.h>
7826 #include <linux/mm.h>
7827 +#include <linux/netfilter.h>
7828 #include <linux/netfilter_ipv4/ip_tables.h>
7829 #include <linux/netfilter_ipv4/ipt_ULOG.h>
7830 #include <linux/netfilter_ipv4/lockhelp.h>
7832 MODULE_PARM(flushtimeout, "i");
7833 MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
7835 +static unsigned int nflog = 1;
7836 +MODULE_PARM(nflog, "i");
7837 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
7839 /* global data structures */
7842 @@ -157,17 +162,17 @@
7846 -static unsigned int ipt_ulog_target(struct sk_buff **pskb,
7847 - const struct net_device *in,
7848 - const struct net_device *out,
7849 - unsigned int hooknum,
7850 - const void *targinfo, void *userinfo)
7851 +static void ipt_ulog_packet(unsigned int hooknum,
7852 + const struct sk_buff *skb,
7853 + const struct net_device *in,
7854 + const struct net_device *out,
7855 + const struct ipt_ulog_info *loginfo,
7856 + const char *prefix)
7859 ulog_packet_msg_t *pm;
7860 size_t size, copy_len;
7861 struct nlmsghdr *nlh;
7862 - struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
7864 /* ffs == find first bit set, necessary because userspace
7865 * is already shifting groupnumber, but we need unshifted.
7868 /* calculate the size of the skb needed */
7869 if ((loginfo->copy_range == 0) ||
7870 - (loginfo->copy_range > (*pskb)->len)) {
7871 - copy_len = (*pskb)->len;
7872 + (loginfo->copy_range > skb->len)) {
7873 + copy_len = skb->len;
7875 copy_len = loginfo->copy_range;
7877 @@ -214,19 +219,21 @@
7879 /* copy hook, prefix, timestamp, payload, etc. */
7880 pm->data_len = copy_len;
7881 - pm->timestamp_sec = (*pskb)->stamp.tv_sec;
7882 - pm->timestamp_usec = (*pskb)->stamp.tv_usec;
7883 - pm->mark = (*pskb)->nfmark;
7884 + pm->timestamp_sec = skb->stamp.tv_sec;
7885 + pm->timestamp_usec = skb->stamp.tv_usec;
7886 + pm->mark = skb->nfmark;
7888 - if (loginfo->prefix[0] != '\0')
7889 + if (prefix != NULL)
7890 + strncpy(pm->prefix, prefix, sizeof(pm->prefix));
7891 + else if (loginfo->prefix[0] != '\0')
7892 strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
7894 *(pm->prefix) = '\0';
7896 if (in && in->hard_header_len > 0
7897 - && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
7898 + && skb->mac.raw != (void *) skb->nh.iph
7899 && in->hard_header_len <= ULOG_MAC_LEN) {
7900 - memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
7901 + memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
7902 pm->mac_len = in->hard_header_len;
7907 pm->outdev_name[0] = '\0';
7909 - /* copy_len <= (*pskb)->len, so can't fail. */
7910 - if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
7911 + /* copy_len <= skb->len, so can't fail. */
7912 + if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
7915 /* check if we are building multi-part messages */
7918 UNLOCK_BH(&ulog_lock);
7920 - return IPT_CONTINUE;
7925 PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
7926 @@ -276,8 +282,35 @@
7927 PRINTR("ipt_ULOG: Error building netlink message\n");
7929 UNLOCK_BH(&ulog_lock);
7932 +static unsigned int ipt_ulog_target(struct sk_buff **pskb,
7933 + const struct net_device *in,
7934 + const struct net_device *out,
7935 + unsigned int hooknum,
7936 + const void *targinfo, void *userinfo)
7938 + struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
7940 - return IPT_CONTINUE;
7941 + ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
7943 + return IPT_CONTINUE;
7946 +static void ipt_logfn(unsigned int hooknum,
7947 + const struct sk_buff *skb,
7948 + const struct net_device *in,
7949 + const struct net_device *out,
7950 + const char *prefix)
7952 + struct ipt_ulog_info loginfo = {
7953 + .nl_group = ULOG_DEFAULT_NLGROUP,
7955 + .qthreshold = ULOG_DEFAULT_QTHRESHOLD,
7959 + ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
7962 static int ipt_ulog_checkentry(const char *tablename,
7964 sock_release(nflognl->sk_socket);
7969 + nf_log_register(PF_INET, &ipt_logfn);
7976 DEBUGP("ipt_ULOG: cleanup_module\n");
7979 + nf_log_unregister(PF_INET, &ipt_logfn);
7980 ipt_unregister_target(&ipt_ulog_reg);
7981 sock_release(nflognl->sk_socket);
7983 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/ipt_ULOG.c.orig linux-2.6.3/net/ipv4/netfilter/ipt_ULOG.c.orig
7984 --- linux-2.6.3.org/net/ipv4/netfilter/ipt_ULOG.c.orig 1970-01-01 01:00:00.000000000 +0100
7985 +++ linux-2.6.3/net/ipv4/netfilter/ipt_ULOG.c.orig 2004-02-18 04:57:24.000000000 +0100
7988 + * netfilter module for userspace packet logging daemons
7990 + * (C) 2000-2002 by Harald Welte <laforge@netfilter.org>
7992 + * 2000/09/22 ulog-cprange feature added
7993 + * 2001/01/04 in-kernel queue as proposed by Sebastian Zander
7994 + * <zander@fokus.gmd.de>
7995 + * 2001/01/30 per-rule nlgroup conflicts with global queue.
7996 + * nlgroup now global (sysctl)
7997 + * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
7998 + * module loadtime -HW
7999 + * 2002/07/07 remove broken nflog_rcv() function -HW
8000 + * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
8001 + * 2002/10/30 fix uninitialized mac_len field - <Anders K. Pedersen>
8003 + * (C) 1999-2001 Paul `Rusty' Russell
8004 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
8006 + * This program is free software; you can redistribute it and/or modify
8007 + * it under the terms of the GNU General Public License version 2 as
8008 + * published by the Free Software Foundation.
8010 + * This module accepts two parameters:
8013 + * The parameter specifies how big the buffer for each netlink multicast
8014 + * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
8015 + * get accumulated in the kernel until they are sent to userspace. It is
8016 + * NOT possible to allocate more than 128kB, and it is strongly discouraged,
8017 + * because atomically allocating 128kB inside the network rx softirq is not
8018 + * reliable. Please also keep in mind that this buffer size is allocated for
8019 + * each nlgroup you are using, so the total kernel memory usage increases
8023 + * Specify, after how many clock ticks (intel: 100 per second) the queue
8024 + * should be flushed even if it is not full yet.
8026 + * ipt_ULOG.c,v 1.22 2002/10/30 09:07:31 laforge Exp
8029 +#include <linux/module.h>
8030 +#include <linux/config.h>
8031 +#include <linux/spinlock.h>
8032 +#include <linux/socket.h>
8033 +#include <linux/skbuff.h>
8034 +#include <linux/kernel.h>
8035 +#include <linux/timer.h>
8036 +#include <linux/netlink.h>
8037 +#include <linux/netdevice.h>
8038 +#include <linux/mm.h>
8039 +#include <linux/netfilter_ipv4/ip_tables.h>
8040 +#include <linux/netfilter_ipv4/ipt_ULOG.h>
8041 +#include <linux/netfilter_ipv4/lockhelp.h>
8042 +#include <net/sock.h>
8043 +#include <linux/bitops.h>
8045 +MODULE_LICENSE("GPL");
8046 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
8047 +MODULE_DESCRIPTION("iptables userspace logging module");
8049 +#define ULOG_NL_EVENT 111 /* Harald's favorite number */
8050 +#define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */
8053 +#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ":" \
8056 +#define DEBUGP(format, args...)
8059 +#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0)
8061 +static unsigned int nlbufsiz = 4096;
8062 +MODULE_PARM(nlbufsiz, "i");
8063 +MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
8065 +static unsigned int flushtimeout = 10 * HZ;
8066 +MODULE_PARM(flushtimeout, "i");
8067 +MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
8069 +/* global data structures */
8072 + unsigned int qlen; /* number of nlmsgs' in the skb */
8073 + struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */
8074 + struct sk_buff *skb; /* the pre-allocated skb */
8075 + struct timer_list timer; /* the timer function */
8078 +static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS]; /* array of buffers */
8080 +static struct sock *nflognl; /* our socket */
8081 +static size_t qlen; /* current length of multipart-nlmsg */
8082 +DECLARE_LOCK(ulog_lock); /* spinlock */
8084 +/* send one ulog_buff_t to userspace */
8085 +static void ulog_send(unsigned int nlgroupnum)
8087 + ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
8089 + if (timer_pending(&ub->timer)) {
8090 + DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
8091 + del_timer(&ub->timer);
8094 + /* last nlmsg needs NLMSG_DONE */
8096 + ub->lastnlh->nlmsg_type = NLMSG_DONE;
8098 + NETLINK_CB(ub->skb).dst_groups = (1 << nlgroupnum);
8099 + DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
8100 + ub->qlen, nlgroup);
8101 + netlink_broadcast(nflognl, ub->skb, 0, (1 << nlgroupnum), GFP_ATOMIC);
8105 + ub->lastnlh = NULL;
8110 +/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
8111 +static void ulog_timer(unsigned long data)
8113 + DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
8115 + /* lock to protect against somebody modifying our structure
8116 + * from ipt_ulog_target at the same time */
8117 + LOCK_BH(&ulog_lock);
8119 + UNLOCK_BH(&ulog_lock);
8122 +struct sk_buff *ulog_alloc_skb(unsigned int size)
8124 + struct sk_buff *skb;
8126 + /* alloc skb which should be big enough for a whole
8127 + * multipart message. WARNING: has to be <= 131000
8128 + * due to slab allocator restrictions */
8130 + skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
8132 + PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
8135 + /* try to allocate only as much as we need for
8136 + * current packet */
8138 + skb = alloc_skb(size, GFP_ATOMIC);
8140 + PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
8146 +static unsigned int ipt_ulog_target(struct sk_buff **pskb,
8147 + const struct net_device *in,
8148 + const struct net_device *out,
8149 + unsigned int hooknum,
8150 + const void *targinfo, void *userinfo)
8153 + ulog_packet_msg_t *pm;
8154 + size_t size, copy_len;
8155 + struct nlmsghdr *nlh;
8156 + struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
8158 + /* ffs == find first bit set, necessary because userspace
8159 + * is already shifting groupnumber, but we need unshifted.
8160 + * ffs() returns [1..32], we need [0..31] */
8161 + unsigned int groupnum = ffs(loginfo->nl_group) - 1;
8163 + /* calculate the size of the skb needed */
8164 + if ((loginfo->copy_range == 0) ||
8165 + (loginfo->copy_range > (*pskb)->len)) {
8166 + copy_len = (*pskb)->len;
8168 + copy_len = loginfo->copy_range;
8171 + size = NLMSG_SPACE(sizeof(*pm) + copy_len);
8173 + ub = &ulog_buffers[groupnum];
8175 + LOCK_BH(&ulog_lock);
8178 + if (!(ub->skb = ulog_alloc_skb(size)))
8179 + goto alloc_failure;
8180 + } else if (ub->qlen >= loginfo->qthreshold ||
8181 + size > skb_tailroom(ub->skb)) {
8182 + /* either the queue len is too high or we don't have
8183 + * enough room in nlskb left. send it to userspace. */
8185 + ulog_send(groupnum);
8187 + if (!(ub->skb = ulog_alloc_skb(size)))
8188 + goto alloc_failure;
8191 + DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen,
8192 + loginfo->qthreshold);
8194 + /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
8195 + nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT,
8196 + size - sizeof(*nlh));
8199 + pm = NLMSG_DATA(nlh);
8201 + /* copy hook, prefix, timestamp, payload, etc. */
8202 + pm->data_len = copy_len;
8203 + pm->timestamp_sec = (*pskb)->stamp.tv_sec;
8204 + pm->timestamp_usec = (*pskb)->stamp.tv_usec;
8205 + pm->mark = (*pskb)->nfmark;
8206 + pm->hook = hooknum;
8207 + if (loginfo->prefix[0] != '\0')
8208 + strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
8210 + *(pm->prefix) = '\0';
8212 + if (in && in->hard_header_len > 0
8213 + && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
8214 + && in->hard_header_len <= ULOG_MAC_LEN) {
8215 + memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
8216 + pm->mac_len = in->hard_header_len;
8221 + strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
8223 + pm->indev_name[0] = '\0';
8226 + strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
8228 + pm->outdev_name[0] = '\0';
8230 + /* copy_len <= (*pskb)->len, so can't fail. */
8231 + if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
8234 + /* check if we are building multi-part messages */
8235 + if (ub->qlen > 1) {
8236 + ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
8239 + /* if threshold is reached, send message to userspace */
8240 + if (qlen >= loginfo->qthreshold) {
8241 + if (loginfo->qthreshold > 1)
8242 + nlh->nlmsg_type = NLMSG_DONE;
8245 + ub->lastnlh = nlh;
8247 + /* if timer isn't already running, start it */
8248 + if (!timer_pending(&ub->timer)) {
8249 + ub->timer.expires = jiffies + flushtimeout;
8250 + add_timer(&ub->timer);
8253 + UNLOCK_BH(&ulog_lock);
8255 + return IPT_CONTINUE;
8259 + PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
8262 + PRINTR("ipt_ULOG: Error building netlink message\n");
8264 + UNLOCK_BH(&ulog_lock);
8266 + return IPT_CONTINUE;
8269 +static int ipt_ulog_checkentry(const char *tablename,
8270 + const struct ipt_entry *e,
8272 + unsigned int targinfosize,
8273 + unsigned int hookmask)
8275 + struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
8277 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
8278 + DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
8282 + if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
8283 + DEBUGP("ipt_ULOG: prefix term %i\n",
8284 + loginfo->prefix[sizeof(loginfo->prefix) - 1]);
8288 + if (loginfo->qthreshold > ULOG_MAX_QLEN) {
8289 + DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
8290 + loginfo->qthreshold);
8297 +static struct ipt_target ipt_ulog_reg = {
8299 + .target = ipt_ulog_target,
8300 + .checkentry = ipt_ulog_checkentry,
8301 + .me = THIS_MODULE,
8304 +static int __init init(void)
8308 + DEBUGP("ipt_ULOG: init module\n");
8310 + if (nlbufsiz >= 128*1024) {
8311 + printk("Netlink buffer has to be <= 128kB\n");
8315 + /* initialize ulog_buffers */
8316 + for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
8317 + init_timer(&ulog_buffers[i].timer);
8318 + ulog_buffers[i].timer.function = ulog_timer;
8319 + ulog_buffers[i].timer.data = i;
8322 + nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
8326 + if (ipt_register_target(&ipt_ulog_reg) != 0) {
8327 + sock_release(nflognl->sk_socket);
8334 +static void __exit fini(void)
8339 + DEBUGP("ipt_ULOG: cleanup_module\n");
8341 + ipt_unregister_target(&ipt_ulog_reg);
8342 + sock_release(nflognl->sk_socket);
8344 + /* remove pending timers and free allocated skb's */
8345 + for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
8346 + ub = &ulog_buffers[i];
8347 + if (timer_pending(&ub->timer)) {
8348 + DEBUGP("timer was pending, deleting\n");
8349 + del_timer(&ub->timer);
8353 + kfree_skb(ub->skb);
8362 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/Kconfig linux-2.6.3/net/ipv4/netfilter/Kconfig
8363 --- linux-2.6.3.org/net/ipv4/netfilter/Kconfig 2004-02-18 04:59:13.000000000 +0100
8364 +++ linux-2.6.3/net/ipv4/netfilter/Kconfig 2004-02-27 00:03:16.148773192 +0100
8365 @@ -579,5 +579,84 @@
8367 To compile it as a module, choose M here. If unsure, say N.
8369 +config IP_NF_TARGET_IPV4OPTSSTRIP
8370 + tristate 'IPV4OPTSSTRIP target support'
8371 + depends on IP_NF_MANGLE
8374 +config IP_NF_TARGET_TTL
8375 + tristate 'TTL target support'
8376 + depends on IP_NF_MANGLE
8379 +config IP_NF_MATCH_CONNLIMIT
8380 + tristate 'Connections/IP limit match support'
8381 + depends on IP_NF_IPTABLES
8384 +config IP_NF_MATCH_DSTLIMIT
8385 + tristate 'dstlimit match support'
8386 + depends on IP_NF_IPTABLES
8389 +config IP_NF_MATCH_FUZZY
8390 + tristate 'fuzzy match support'
8391 + depends on IP_NF_IPTABLES
8394 +config IP_NF_MATCH_IPV4OPTIONS
8395 + tristate 'IPV4OPTIONS match support'
8396 + depends on IP_NF_IPTABLES
8399 +config IP_NF_MATCH_MPORT
8400 + tristate 'Multiple port with ranges match support'
8401 + depends on IP_NF_IPTABLES
8404 +config IP_NF_MATCH_NTH
8405 + tristate 'Nth match support'
8406 + depends on IP_NF_IPTABLES
8409 +config IP_NF_MATCH_QUOTA
8410 + tristate 'quota match support'
8411 + depends on IP_NF_IPTABLES
8414 +config IP_NF_TARGET_NOTRACK
8415 + tristate 'NOTRACK target support'
8416 + depends on IP_NF_RAW
8418 + The NOTRACK target allows a select rule to specify
8419 + which packets *not* to enter the conntrack/NAT
8420 + subsystem with all the consequences (no ICMP error tracking,
8421 + no protocol helpers for the selected packets).
8423 + If you want to compile it as a module, say M here and read
8424 + <file:Documentation/modules.txt>. If unsure, say `N'.
8427 + tristate 'raw table support (required for NOTRACK/TRACE)'
8428 + depends on IP_NF_IPTABLES
8430 + This option adds a `raw' table to iptables. This table is the very
8431 + first in the netfilter framework and hooks in at the PREROUTING
8432 + and OUTPUT chains.
8434 + If you want to compile it as a module, say M here and read
8435 + <file:Documentation/modules.txt>. If unsure, say `N'.
8438 +config IP_NF_MATCH_REALM
8439 + tristate 'realm match support'
8440 + depends on IP_NF_IPTABLES && NET_CLS_ROUTE
8443 +config IP_NF_MATCH_SCTP
8444 + tristate 'SCTP protocol match support'
8445 + depends on IP_NF_IPTABLES
8450 diff -Nur linux-2.6.3.org/net/ipv4/netfilter/Makefile linux-2.6.3/net/ipv4/netfilter/Makefile
8451 --- linux-2.6.3.org/net/ipv4/netfilter/Makefile 2004-02-18 04:57:20.000000000 +0100
8452 +++ linux-2.6.3/net/ipv4/netfilter/Makefile 2004-02-27 00:03:16.148773192 +0100
8454 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
8455 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
8456 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
8457 +obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
8460 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
8461 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
8462 +obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
8463 +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
8464 +obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o
8465 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
8466 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
8467 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
8469 obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
8470 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
8472 +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
8474 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
8475 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
8477 +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
8479 +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
8482 +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
8484 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
8486 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
8489 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
8490 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
8491 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
8492 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
8493 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
8494 +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
8496 obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
8499 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
8500 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
8501 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
8502 +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
8503 +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
8504 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
8505 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
8506 +obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
8508 # generic ARP tables
8509 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
8510 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/ip6table_raw.c linux-2.6.3/net/ipv6/netfilter/ip6table_raw.c
8511 --- linux-2.6.3.org/net/ipv6/netfilter/ip6table_raw.c 1970-01-01 01:00:00.000000000 +0100
8512 +++ linux-2.6.3/net/ipv6/netfilter/ip6table_raw.c 2004-02-27 00:03:14.469028552 +0100
8515 + * IPv6 raw table, a port of the IPv4 raw table to IPv6
8517 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
8519 +#include <linux/module.h>
8520 +#include <linux/netfilter_ipv6/ip6_tables.h>
8522 +#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
8525 +#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
8527 +#define DEBUGP(x, args...)
8530 +/* Standard entry. */
8531 +struct ip6t_standard
8533 + struct ip6t_entry entry;
8534 + struct ip6t_standard_target target;
8537 +struct ip6t_error_target
8539 + struct ip6t_entry_target target;
8540 + char errorname[IP6T_FUNCTION_MAXNAMELEN];
8545 + struct ip6t_entry entry;
8546 + struct ip6t_error_target target;
8551 + struct ip6t_replace repl;
8552 + struct ip6t_standard entries[2];
8553 + struct ip6t_error term;
8554 +} initial_table __initdata
8555 += { { "raw", RAW_VALID_HOOKS, 3,
8556 + sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
8557 + { [NF_IP6_PRE_ROUTING] 0,
8558 + [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
8559 + { [NF_IP6_PRE_ROUTING] 0,
8560 + [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
8564 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8566 + sizeof(struct ip6t_entry),
8567 + sizeof(struct ip6t_standard),
8568 + 0, { 0, 0 }, { } },
8569 + { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
8570 + -NF_ACCEPT - 1 } },
8572 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8574 + sizeof(struct ip6t_entry),
8575 + sizeof(struct ip6t_standard),
8576 + 0, { 0, 0 }, { } },
8577 + { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
8578 + -NF_ACCEPT - 1 } },
8581 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8583 + sizeof(struct ip6t_entry),
8584 + sizeof(struct ip6t_error),
8585 + 0, { 0, 0 }, { } },
8586 + { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
8593 +static struct ip6t_table packet_raw = {
8595 + .table = &initial_table.repl,
8596 + .valid_hooks = RAW_VALID_HOOKS,
8597 + .lock = RW_LOCK_UNLOCKED,
8601 +/* The work comes in here from netfilter.c. */
8602 +static unsigned int
8603 +ip6t_hook(unsigned int hook,
8604 + struct sk_buff **pskb,
8605 + const struct net_device *in,
8606 + const struct net_device *out,
8607 + int (*okfn)(struct sk_buff *))
8609 + return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
8612 +static struct nf_hook_ops ip6t_ops[] = {
8614 + .hook = ip6t_hook,
8616 + .hooknum = NF_IP6_PRE_ROUTING,
8617 + .priority = NF_IP6_PRI_FIRST
8620 + .hook = ip6t_hook,
8622 + .hooknum = NF_IP6_LOCAL_OUT,
8623 + .priority = NF_IP6_PRI_FIRST
8627 +static int __init init(void)
8631 + /* Register table */
8632 + ret = ip6t_register_table(&packet_raw);
8636 + /* Register hooks */
8637 + ret = nf_register_hook(&ip6t_ops[0]);
8639 + goto cleanup_table;
8641 + ret = nf_register_hook(&ip6t_ops[1]);
8643 + goto cleanup_hook0;
8648 + nf_unregister_hook(&ip6t_ops[0]);
8650 + ip6t_unregister_table(&packet_raw);
8655 +static void __exit fini(void)
8659 + for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
8660 + nf_unregister_hook(&ip6t_ops[i]);
8662 + ip6t_unregister_table(&packet_raw);
8667 +MODULE_LICENSE("GPL");
8668 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.3/net/ipv6/netfilter/ip6t_fuzzy.c
8669 --- linux-2.6.3.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
8670 +++ linux-2.6.3/net/ipv6/netfilter/ip6t_fuzzy.c 2004-02-27 00:03:09.360805120 +0100
8673 + * This module implements a simple TSK FLC
8674 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
8675 + * to limit , in an adaptive and flexible way , the packet rate crossing
8676 + * a given stream . It serves as an initial and very simple (but effective)
8677 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
8678 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
8679 + * into our code in a precise , adaptive and efficient manner.
8680 + * The goal is very similar to that of "limit" match , but using techniques of
8681 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
8682 + * avoiding over and undershoots - and stuff like that .
8685 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
8686 + * 2002-08-17 : Changed to eliminate floating point operations .
8687 + * 2002-08-23 : Coding style changes .
8688 + * 2003-04-08 Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
8691 +#include <linux/module.h>
8692 +#include <linux/skbuff.h>
8693 +#include <linux/ipv6.h>
8694 +#include <linux/random.h>
8695 +#include <net/tcp.h>
8696 +#include <linux/spinlock.h>
8697 +#include <linux/netfilter_ipv6/ip6_tables.h>
8698 +#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
8701 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
8702 + Expressed in percentage
8705 +#define PAR_LOW 1/100
8708 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
8710 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
8711 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
8712 +MODULE_LICENSE("GPL");
8714 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
8716 + if (tx >= maxi) return 100;
8718 + if (tx <= mini) return 0;
8720 + return ((100 * (tx-mini)) / (maxi-mini));
8723 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
8725 + if (tx <= mini) return 100;
8727 + if (tx >= maxi) return 0;
8729 + return ((100 * (maxi - tx)) / (maxi - mini));
8734 +ip6t_fuzzy_match(const struct sk_buff *pskb,
8735 + const struct net_device *in,
8736 + const struct net_device *out,
8737 + const void *matchinfo,
8740 + u_int16_t datalen,
8743 + /* From userspace */
8745 + struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
8747 + u_int8_t random_number;
8748 + unsigned long amount;
8749 + u_int8_t howhigh, howlow;
8752 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
8754 + info->bytes_total += pskb->len;
8755 + info->packets_total++;
8757 + info->present_time = jiffies;
8759 + if (info->present_time >= info->previous_time)
8760 + amount = info->present_time - info->previous_time;
8762 + /* There was a transition : I choose to re-sample
8763 + and keep the old acceptance rate...
8767 + info->previous_time = info->present_time;
8768 + info->bytes_total = info->packets_total = 0;
8771 + if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
8773 + info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
8776 + info->previous_time = info->present_time;
8777 + info->bytes_total = info->packets_total = 0;
8779 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
8780 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
8782 + info->acceptance_rate = (u_int8_t) \
8783 + (howhigh * PAR_LOW + PAR_HIGH * howlow);
8785 + /* In fact, the above defuzzification would require a denominator
8786 + * proportional to (howhigh+howlow) but, in this particular case,
8787 + * that expression is constant.
8788 + * An imediate consequence is that it is not necessary to call
8789 + * both mf_high and mf_low - but to keep things understandable,
8795 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
8798 + if (info->acceptance_rate < 100)
8800 + get_random_bytes((void *)(&random_number), 1);
8802 + /* If within the acceptance , it can pass => don't match */
8803 + if (random_number <= (255 * info->acceptance_rate) / 100)
8806 + return 1; /* It can't pass (It matches) */
8809 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
8814 +ip6t_fuzzy_checkentry(const char *tablename,
8815 + const struct ip6t_ip6 *ip,
8817 + unsigned int matchsize,
8818 + unsigned int hook_mask)
8821 + const struct ip6t_fuzzy_info *info = matchinfo;
8823 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
8824 + printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
8825 + IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
8829 + if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
8830 + || (info->minimum_rate >= info->maximum_rate)) {
8831 + printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
8838 +static struct ip6t_match ip6t_fuzzy_reg = {
8842 + ip6t_fuzzy_checkentry,
8846 +static int __init init(void)
8848 + if (ip6t_register_match(&ip6t_fuzzy_reg))
8854 +static void __exit fini(void)
8856 + ip6t_unregister_match(&ip6t_fuzzy_reg);
8861 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.3/net/ipv6/netfilter/ip6t_HL.c
8862 --- linux-2.6.3.org/net/ipv6/netfilter/ip6t_HL.c 1970-01-01 01:00:00.000000000 +0100
8863 +++ linux-2.6.3/net/ipv6/netfilter/ip6t_HL.c 2004-02-27 00:03:05.118450056 +0100
8866 + * Hop Limit modification target for ip6tables
8867 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
8868 + * Based on HW's TTL module
8870 + * This software is distributed under the terms of GNU GPL
8873 +#include <linux/module.h>
8874 +#include <linux/skbuff.h>
8875 +#include <linux/ip.h>
8877 +#include <linux/netfilter_ipv6/ip6_tables.h>
8878 +#include <linux/netfilter_ipv6/ip6t_HL.h>
8880 +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
8881 +MODULE_DESCRIPTION("IP tables Hop Limit modification module");
8882 +MODULE_LICENSE("GPL");
8884 +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
8885 + const struct net_device *in, const struct net_device *out,
8886 + const void *targinfo, void *userinfo)
8888 + struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
8889 + const struct ip6t_HL_info *info = targinfo;
8890 + u_int16_t diffs[2];
8893 + switch (info->mode) {
8895 + new_hl = info->hop_limit;
8898 + new_hl = ip6h->hop_limit + info->hop_limit;
8903 + new_hl = ip6h->hop_limit + info->hop_limit;
8908 + new_hl = ip6h->hop_limit;
8912 + if (new_hl != ip6h->hop_limit) {
8913 + diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
8914 + ip6h->hop_limit = new_hl;
8915 + diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
8918 + return IP6T_CONTINUE;
8921 +static int ip6t_hl_checkentry(const char *tablename,
8922 + const struct ip6t_entry *e,
8924 + unsigned int targinfosize,
8925 + unsigned int hook_mask)
8927 + struct ip6t_HL_info *info = targinfo;
8929 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
8930 + printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
8932 + IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
8936 + if (strcmp(tablename, "mangle")) {
8937 + printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
8941 + if (info->mode > IP6T_HL_MAXMODE) {
8942 + printk(KERN_WARNING "HL: invalid or unknown Mode %u\n",
8947 + if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
8948 + printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
8955 +static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL",
8956 + ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
8958 +static int __init init(void)
8960 + return ip6t_register_target(&ip6t_HL);
8963 +static void __exit fini(void)
8965 + ip6t_unregister_target(&ip6t_HL);
8970 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/ip6t_LOG.c linux-2.6.3/net/ipv6/netfilter/ip6t_LOG.c
8971 --- linux-2.6.3.org/net/ipv6/netfilter/ip6t_LOG.c 2004-02-18 04:57:21.000000000 +0100
8972 +++ linux-2.6.3/net/ipv6/netfilter/ip6t_LOG.c 2004-02-27 00:03:00.003227688 +0100
8974 #include <net/udp.h>
8975 #include <net/tcp.h>
8976 #include <net/ipv6.h>
8977 +#include <linux/netfilter.h>
8978 #include <linux/netfilter_ipv6/ip6_tables.h>
8980 MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
8981 MODULE_DESCRIPTION("IP6 tables LOG target module");
8982 MODULE_LICENSE("GPL");
8984 +static unsigned int nflog = 1;
8985 +MODULE_PARM(nflog, "i");
8986 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
8989 #include <net/route.h>
8990 #include <linux/netfilter_ipv6/ip6t_LOG.h>
8991 @@ -265,40 +270,38 @@
8995 -static unsigned int
8996 -ip6t_log_target(struct sk_buff **pskb,
8997 - unsigned int hooknum,
8999 +ip6t_log_packet(unsigned int hooknum,
9000 + const struct sk_buff *skb,
9001 const struct net_device *in,
9002 const struct net_device *out,
9003 - const void *targinfo,
9005 + const struct ip6t_log_info *loginfo,
9006 + const char *level_string,
9007 + const char *prefix)
9009 - struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
9010 - const struct ip6t_log_info *loginfo = targinfo;
9011 - char level_string[4] = "< >";
9012 + struct ipv6hdr *ipv6h = skb->nh.ipv6h;
9014 - level_string[1] = '0' + (loginfo->level % 8);
9015 spin_lock_bh(&log_lock);
9016 printk(level_string);
9017 printk("%sIN=%s OUT=%s ",
9019 + prefix == NULL ? loginfo->prefix : prefix,
9021 out ? out->name : "");
9023 /* MAC logging for input chain only. */
9025 - if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
9026 - if ((*pskb)->dev->type != ARPHRD_SIT){
9027 + if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) {
9028 + if (skb->dev->type != ARPHRD_SIT){
9030 - unsigned char *p = (*pskb)->mac.raw;
9031 - for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
9032 + unsigned char *p = skb->mac.raw;
9033 + for (i = 0; i < skb->dev->hard_header_len; i++,p++)
9034 printk("%02x%c", *p,
9035 - i==(*pskb)->dev->hard_header_len - 1
9036 + i==skb->dev->hard_header_len - 1
9040 - unsigned char *p = (*pskb)->mac.raw;
9041 - if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
9042 + unsigned char *p = skb->mac.raw;
9043 + if ( p - (ETH_ALEN*2+2) > skb->head ){
9045 for (i = 0; i < (ETH_ALEN); i++,p++)
9046 printk("%02x%s", *p,
9047 @@ -309,10 +312,10 @@
9048 i == ETH_ALEN-1 ? ' ' : ':');
9051 - if (((*pskb)->dev->addr_len == 4) &&
9052 - (*pskb)->dev->hard_header_len > 20){
9053 + if ((skb->dev->addr_len == 4) &&
9054 + skb->dev->hard_header_len > 20){
9056 - p = (*pskb)->mac.raw + 12;
9057 + p = skb->mac.raw + 12;
9058 for (i = 0; i < 4; i++,p++)
9060 i == 3 ? "->" : ".");
9061 @@ -328,10 +331,41 @@
9062 dump_packet(loginfo, ipv6h, 1);
9064 spin_unlock_bh(&log_lock);
9067 +static unsigned int
9068 +ip6t_log_target(struct sk_buff **pskb,
9069 + unsigned int hooknum,
9070 + const struct net_device *in,
9071 + const struct net_device *out,
9072 + const void *targinfo,
9075 + const struct ip6t_log_info *loginfo = targinfo;
9076 + char level_string[4] = "< >";
9078 + level_string[1] = '0' + (loginfo->level % 8);
9079 + ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
9081 return IP6T_CONTINUE;
9085 +ip6t_logfn(unsigned int hooknum,
9086 + const struct sk_buff *skb,
9087 + const struct net_device *in,
9088 + const struct net_device *out,
9089 + const char *prefix)
9091 + struct ip6t_log_info loginfo = {
9093 + .logflags = IP6T_LOG_MASK,
9097 + ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
9100 static int ip6t_log_checkentry(const char *tablename,
9101 const struct ip6t_entry *e,
9103 @@ -368,12 +402,16 @@
9105 if (ip6t_register_target(&ip6t_log_reg))
9108 + nf_log_register(PF_INET, &ip6t_logfn);
9113 static void __exit fini(void)
9116 + nf_log_unregister(PF_INET, &ip6t_logfn);
9117 ip6t_unregister_target(&ip6t_log_reg);
9120 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/ip6t_LOG.c.orig linux-2.6.3/net/ipv6/netfilter/ip6t_LOG.c.orig
9121 --- linux-2.6.3.org/net/ipv6/netfilter/ip6t_LOG.c.orig 1970-01-01 01:00:00.000000000 +0100
9122 +++ linux-2.6.3/net/ipv6/netfilter/ip6t_LOG.c.orig 2004-02-18 04:57:21.000000000 +0100
9125 + * This is a module which is used for logging packets.
9128 +/* (C) 2001 Jan Rekorajski <baggins@pld.org.pl>
9129 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
9131 + * This program is free software; you can redistribute it and/or modify
9132 + * it under the terms of the GNU General Public License version 2 as
9133 + * published by the Free Software Foundation.
9136 +#include <linux/module.h>
9137 +#include <linux/skbuff.h>
9138 +#include <linux/ip.h>
9139 +#include <linux/spinlock.h>
9140 +#include <linux/icmpv6.h>
9141 +#include <net/udp.h>
9142 +#include <net/tcp.h>
9143 +#include <net/ipv6.h>
9144 +#include <linux/netfilter_ipv6/ip6_tables.h>
9146 +MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
9147 +MODULE_DESCRIPTION("IP6 tables LOG target module");
9148 +MODULE_LICENSE("GPL");
9151 +#include <net/route.h>
9152 +#include <linux/netfilter_ipv6/ip6t_LOG.h>
9155 +#define DEBUGP printk
9157 +#define DEBUGP(format, args...)
9162 +}; /* FIXME evil kludge */
9164 +/* Use lock to serialize, so printks don't overlap */
9165 +static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
9167 +/* takes in current header and pointer to the header */
9168 +/* if another header exists, sets hdrptr to the next header
9169 + and returns the new header value, else returns 0 */
9170 +static u_int8_t ip6_nexthdr(u_int8_t currenthdr, u_int8_t **hdrptr)
9172 + u_int8_t hdrlen, nexthdr = 0;
9174 + switch(currenthdr){
9176 + /* whoever decided to do the length of AUTH for ipv6
9177 + in 32bit units unlike other headers should be beaten...
9178 + repeatedly...with a large stick...no, an even LARGER
9179 + stick...no, you're still not thinking big enough */
9180 + nexthdr = **hdrptr;
9181 + hdrlen = *hdrptr[1] * 4 + 8;
9182 + *hdrptr = *hdrptr + hdrlen;
9184 + /*stupid rfc2402 */
9185 + case IPPROTO_DSTOPTS:
9186 + case IPPROTO_ROUTING:
9187 + case IPPROTO_HOPOPTS:
9188 + nexthdr = **hdrptr;
9189 + hdrlen = *hdrptr[1] * 8 + 8;
9190 + *hdrptr = *hdrptr + hdrlen;
9192 + case IPPROTO_FRAGMENT:
9193 + nexthdr = **hdrptr;
9194 + *hdrptr = *hdrptr + 8;
9201 +/* One level of recursion won't kill us */
9202 +static void dump_packet(const struct ip6t_log_info *info,
9203 + struct ipv6hdr *ipv6h, int recurse)
9205 + u_int8_t currenthdr = ipv6h->nexthdr;
9209 + /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */
9210 + printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->saddr));
9211 + printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
9213 + /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
9214 + printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
9215 + ntohs(ipv6h->payload_len) + sizeof(struct ipv6hdr),
9216 + (ntohl(*(u_int32_t *)ipv6h) & 0x0ff00000) >> 20,
9218 + (ntohl(*(u_int32_t *)ipv6h) & 0x000fffff));
9221 + hdrptr = (u_int8_t *)(ipv6h + 1);
9222 + while (currenthdr) {
9223 + if ((currenthdr == IPPROTO_TCP) ||
9224 + (currenthdr == IPPROTO_UDP) ||
9225 + (currenthdr == IPPROTO_ICMPV6))
9227 + /* Max length: 48 "OPT (...) " */
9229 + switch (currenthdr) {
9230 + case IPPROTO_FRAGMENT: {
9231 + struct frag_hdr *fhdr = (struct frag_hdr *)hdrptr;
9233 + /* Max length: 11 "FRAG:65535 " */
9234 + printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8);
9236 + /* Max length: 11 "INCOMPLETE " */
9237 + if (fhdr->frag_off & htons(0x0001))
9238 + printk("INCOMPLETE ");
9240 + printk("ID:%08x ", fhdr->identification);
9242 + if (ntohs(fhdr->frag_off) & 0xFFF8)
9247 + case IPPROTO_DSTOPTS:
9248 + case IPPROTO_ROUTING:
9249 + case IPPROTO_HOPOPTS:
9254 + if (info->logflags & IP6T_LOG_IPOPT) {
9255 + struct esphdr *esph = (struct esphdr *)hdrptr;
9256 + int esp = (currenthdr == IPPROTO_ESP);
9258 + /* Max length: 4 "ESP " */
9259 + printk("%s ",esp ? "ESP" : "AH");
9261 + /* Length: 15 "SPI=0xF1234567 " */
9262 + printk("SPI=0x%x ", ntohl(esph->spi) );
9269 + currenthdr = ip6_nexthdr(currenthdr, &hdrptr);
9272 + switch (currenthdr) {
9273 + case IPPROTO_TCP: {
9274 + struct tcphdr *tcph = (struct tcphdr *)hdrptr;
9276 + /* Max length: 10 "PROTO=TCP " */
9277 + printk("PROTO=TCP ");
9282 + /* Max length: 20 "SPT=65535 DPT=65535 " */
9283 + printk("SPT=%u DPT=%u ",
9284 + ntohs(tcph->source), ntohs(tcph->dest));
9285 + /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
9286 + if (info->logflags & IP6T_LOG_TCPSEQ)
9287 + printk("SEQ=%u ACK=%u ",
9288 + ntohl(tcph->seq), ntohl(tcph->ack_seq));
9289 + /* Max length: 13 "WINDOW=65535 " */
9290 + printk("WINDOW=%u ", ntohs(tcph->window));
9291 + /* Max length: 9 "RES=0x3F " */
9292 + printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22));
9293 + /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
9310 + /* Max length: 11 "URGP=65535 " */
9311 + printk("URGP=%u ", ntohs(tcph->urg_ptr));
9313 + if ((info->logflags & IP6T_LOG_TCPOPT)
9314 + && tcph->doff * 4 != sizeof(struct tcphdr)) {
9317 + /* Max length: 127 "OPT (" 15*4*2chars ") " */
9319 + for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++)
9320 + printk("%02X", ((u_int8_t *)tcph)[i]);
9325 + case IPPROTO_UDP: {
9326 + struct udphdr *udph = (struct udphdr *)hdrptr;
9328 + /* Max length: 10 "PROTO=UDP " */
9329 + printk("PROTO=UDP ");
9334 + /* Max length: 20 "SPT=65535 DPT=65535 " */
9335 + printk("SPT=%u DPT=%u LEN=%u ",
9336 + ntohs(udph->source), ntohs(udph->dest),
9337 + ntohs(udph->len));
9340 + case IPPROTO_ICMPV6: {
9341 + struct icmp6hdr *icmp6h = (struct icmp6hdr *)hdrptr;
9343 + /* Max length: 13 "PROTO=ICMPv6 " */
9344 + printk("PROTO=ICMPv6 ");
9349 + /* Max length: 18 "TYPE=255 CODE=255 " */
9350 + printk("TYPE=%u CODE=%u ", icmp6h->icmp6_type, icmp6h->icmp6_code);
9352 + switch (icmp6h->icmp6_type) {
9353 + case ICMPV6_ECHO_REQUEST:
9354 + case ICMPV6_ECHO_REPLY:
9355 + /* Max length: 19 "ID=65535 SEQ=65535 " */
9356 + printk("ID=%u SEQ=%u ",
9357 + ntohs(icmp6h->icmp6_identifier),
9358 + ntohs(icmp6h->icmp6_sequence));
9360 + case ICMPV6_MGM_QUERY:
9361 + case ICMPV6_MGM_REPORT:
9362 + case ICMPV6_MGM_REDUCTION:
9365 + case ICMPV6_PARAMPROB:
9366 + /* Max length: 17 "POINTER=ffffffff " */
9367 + printk("POINTER=%08x ", ntohl(icmp6h->icmp6_pointer));
9368 + /* Fall through */
9369 + case ICMPV6_DEST_UNREACH:
9370 + case ICMPV6_PKT_TOOBIG:
9371 + case ICMPV6_TIME_EXCEED:
9372 + /* Max length: 3+maxlen */
9375 + dump_packet(info, (struct ipv6hdr *)(icmp6h + 1), 0);
9379 + /* Max length: 10 "MTU=65535 " */
9380 + if (icmp6h->icmp6_type == ICMPV6_PKT_TOOBIG)
9381 + printk("MTU=%u ", ntohl(icmp6h->icmp6_mtu));
9385 + /* Max length: 10 "PROTO 255 " */
9387 + printk("PROTO=%u ", currenthdr);
9391 +static unsigned int
9392 +ip6t_log_target(struct sk_buff **pskb,
9393 + unsigned int hooknum,
9394 + const struct net_device *in,
9395 + const struct net_device *out,
9396 + const void *targinfo,
9399 + struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
9400 + const struct ip6t_log_info *loginfo = targinfo;
9401 + char level_string[4] = "< >";
9403 + level_string[1] = '0' + (loginfo->level % 8);
9404 + spin_lock_bh(&log_lock);
9405 + printk(level_string);
9406 + printk("%sIN=%s OUT=%s ",
9408 + in ? in->name : "",
9409 + out ? out->name : "");
9411 + /* MAC logging for input chain only. */
9413 + if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
9414 + if ((*pskb)->dev->type != ARPHRD_SIT){
9416 + unsigned char *p = (*pskb)->mac.raw;
9417 + for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
9418 + printk("%02x%c", *p,
9419 + i==(*pskb)->dev->hard_header_len - 1
9423 + unsigned char *p = (*pskb)->mac.raw;
9424 + if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
9425 + p -= (ETH_ALEN+2);
9426 + for (i = 0; i < (ETH_ALEN); i++,p++)
9427 + printk("%02x%s", *p,
9428 + i == ETH_ALEN-1 ? "->" : ":");
9429 + p -= (ETH_ALEN*2);
9430 + for (i = 0; i < (ETH_ALEN); i++,p++)
9431 + printk("%02x%c", *p,
9432 + i == ETH_ALEN-1 ? ' ' : ':');
9435 + if (((*pskb)->dev->addr_len == 4) &&
9436 + (*pskb)->dev->hard_header_len > 20){
9437 + printk("TUNNEL=");
9438 + p = (*pskb)->mac.raw + 12;
9439 + for (i = 0; i < 4; i++,p++)
9440 + printk("%3d%s", *p,
9441 + i == 3 ? "->" : ".");
9442 + for (i = 0; i < 4; i++,p++)
9443 + printk("%3d%c", *p,
9444 + i == 3 ? ' ' : '.');
9451 + dump_packet(loginfo, ipv6h, 1);
9453 + spin_unlock_bh(&log_lock);
9455 + return IP6T_CONTINUE;
9458 +static int ip6t_log_checkentry(const char *tablename,
9459 + const struct ip6t_entry *e,
9461 + unsigned int targinfosize,
9462 + unsigned int hook_mask)
9464 + const struct ip6t_log_info *loginfo = targinfo;
9466 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_log_info))) {
9467 + DEBUGP("LOG: targinfosize %u != %u\n",
9468 + targinfosize, IP6T_ALIGN(sizeof(struct ip6t_log_info)));
9472 + if (loginfo->level >= 8) {
9473 + DEBUGP("LOG: level %u >= 8\n", loginfo->level);
9477 + if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
9478 + DEBUGP("LOG: prefix term %i\n",
9479 + loginfo->prefix[sizeof(loginfo->prefix)-1]);
9486 +static struct ip6t_target ip6t_log_reg
9487 += { { NULL, NULL }, "LOG", ip6t_log_target, ip6t_log_checkentry, NULL,
9490 +static int __init init(void)
9492 + if (ip6t_register_target(&ip6t_log_reg))
9498 +static void __exit fini(void)
9500 + ip6t_unregister_target(&ip6t_log_reg);
9505 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.3/net/ipv6/netfilter/ip6t_nth.c
9506 --- linux-2.6.3.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 01:00:00.000000000 +0100
9507 +++ linux-2.6.3/net/ipv6/netfilter/ip6t_nth.c 2004-02-27 00:03:12.719294552 +0100
9510 + This is a module which is used for match support for every Nth packet
9511 + This file is distributed under the terms of the GNU General Public
9512 + License (GPL). Copies of the GPL can be obtained from:
9513 + ftp://prep.ai.mit.edu/pub/gnu/GPL
9515 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
9516 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
9517 + * added support for multiple counters
9518 + * added support for matching on individual packets
9519 + in the counter cycle
9520 + 2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
9524 +#include <linux/module.h>
9525 +#include <linux/skbuff.h>
9526 +#include <linux/ip.h>
9527 +#include <net/tcp.h>
9528 +#include <linux/spinlock.h>
9529 +#include <linux/netfilter_ipv6/ip6_tables.h>
9530 +#include <linux/netfilter_ipv6/ip6t_nth.h>
9532 +MODULE_LICENSE("GPL");
9535 + * State information.
9542 +static struct state states[IP6T_NTH_NUM_COUNTERS];
9545 +ip6t_nth_match(const struct sk_buff *pskb,
9546 + const struct net_device *in,
9547 + const struct net_device *out,
9548 + const void *matchinfo,
9551 + u_int16_t datalen,
9554 + /* Parameters from userspace */
9555 + const struct ip6t_nth_info *info = matchinfo;
9556 + unsigned counter = info->counter;
9557 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
9559 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
9563 + spin_lock(&states[counter].lock);
9565 + /* Are we matching every nth packet?*/
9566 + if (info->packet == 0xFF)
9568 + /* We're matching every nth packet and only every nth packet*/
9569 + /* Do we match or invert match? */
9570 + if (info->not == 0)
9572 + if (states[counter].number == 0)
9574 + ++states[counter].number;
9577 + if (states[counter].number >= info->every)
9578 + states[counter].number = 0; /* reset the counter */
9580 + ++states[counter].number;
9585 + if (states[counter].number == 0)
9587 + ++states[counter].number;
9590 + if (states[counter].number >= info->every)
9591 + states[counter].number = 0;
9593 + ++states[counter].number;
9599 + /* We're using the --packet, so there must be a rule for every value */
9600 + if (states[counter].number == info->packet)
9602 + /* only increment the counter when a match happens */
9603 + if (states[counter].number >= info->every)
9604 + states[counter].number = 0; /* reset the counter */
9606 + ++states[counter].number;
9615 + spin_unlock(&states[counter].lock);
9619 + spin_unlock(&states[counter].lock);
9624 +ip6t_nth_checkentry(const char *tablename,
9625 + const struct ip6t_ip6 *e,
9627 + unsigned int matchsize,
9628 + unsigned int hook_mask)
9630 + /* Parameters from userspace */
9631 + const struct ip6t_nth_info *info = matchinfo;
9632 + unsigned counter = info->counter;
9633 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
9635 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
9639 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
9640 + printk("nth: matchsize %u != %u\n", matchsize,
9641 + IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
9645 + states[counter].number = info->startat;
9650 +static struct ip6t_match ip6t_nth_reg = {
9654 + ip6t_nth_checkentry,
9658 +static int __init init(void)
9661 + memset(&states, 0, sizeof(states));
9662 + if (ip6t_register_match(&ip6t_nth_reg))
9665 + for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++)
9667 + spin_lock_init(&(states[counter].lock));
9670 + printk("ip6t_nth match loaded\n");
9674 +static void __exit fini(void)
9676 + ip6t_unregister_match(&ip6t_nth_reg);
9677 + printk("ip6t_nth match unloaded\n");
9682 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.3/net/ipv6/netfilter/ip6t_REJECT.c
9683 --- linux-2.6.3.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 01:00:00.000000000 +0100
9684 +++ linux-2.6.3/net/ipv6/netfilter/ip6t_REJECT.c 2004-02-27 00:03:06.643218256 +0100
9687 + * This is a module which is used for rejecting packets.
9688 + * Added support for customized reject packets (Jozsef Kadlecsik).
9690 + * Port to IPv6 / ip6tables (Harald Welte <laforge@gnumonks.org>)
9692 +#include <linux/config.h>
9693 +#include <linux/module.h>
9694 +#include <linux/skbuff.h>
9695 +#include <linux/icmpv6.h>
9696 +#include <net/tcp.h>
9697 +#include <linux/netfilter_ipv6/ip6_tables.h>
9698 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
9701 +#define DEBUGP printk
9703 +#define DEBUGP(format, args...)
9707 +/* Send RST reply */
9708 +static void send_reset(struct sk_buff *oldskb)
9710 + struct sk_buff *nskb;
9711 + struct tcphdr *otcph, *tcph;
9712 + struct rtable *rt;
9713 + unsigned int otcplen;
9716 + /* IP header checks: fragment, too short. */
9717 + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
9718 + || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
9721 + otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
9722 + otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
9724 + /* No RST for RST. */
9728 + /* Check checksum. */
9729 + if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
9730 + oldskb->nh.iph->daddr,
9731 + csum_partial((char *)otcph, otcplen, 0)) != 0)
9734 + /* Copy skb (even if skb is about to be dropped, we can't just
9735 + clone it because there may be other things, such as tcpdump,
9736 + interested in it) */
9737 + nskb = skb_copy(oldskb, GFP_ATOMIC);
9741 + /* This packet will not be the same as the other: clear nf fields */
9742 + nf_conntrack_put(nskb->nfct);
9743 + nskb->nfct = NULL;
9744 + nskb->nfcache = 0;
9745 +#ifdef CONFIG_NETFILTER_DEBUG
9746 + nskb->nf_debug = 0;
9749 + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
9751 + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
9752 + tcph->source = xchg(&tcph->dest, tcph->source);
9754 + /* Truncate to length (no data) */
9755 + tcph->doff = sizeof(struct tcphdr)/4;
9756 + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
9757 + nskb->nh.iph->tot_len = htons(nskb->len);
9761 + tcph->seq = otcph->ack_seq;
9762 + tcph->ack_seq = 0;
9765 + tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
9766 + + otcplen - (otcph->doff<<2));
9771 + ((u_int8_t *)tcph)[13] = 0;
9773 + tcph->ack = needs_ack;
9776 + tcph->urg_ptr = 0;
9778 + /* Adjust TCP checksum */
9780 + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
9781 + nskb->nh.iph->saddr,
9782 + nskb->nh.iph->daddr,
9783 + csum_partial((char *)tcph,
9784 + sizeof(struct tcphdr), 0));
9786 + /* Adjust IP TTL, DF */
9787 + nskb->nh.iph->ttl = MAXTTL;
9788 + /* Set DF, id = 0 */
9789 + nskb->nh.iph->frag_off = htons(IP_DF);
9790 + nskb->nh.iph->id = 0;
9792 + /* Adjust IP checksum */
9793 + nskb->nh.iph->check = 0;
9794 + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
9795 + nskb->nh.iph->ihl);
9798 + if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
9799 + RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
9803 + dst_release(nskb->dst);
9804 + nskb->dst = &rt->u.dst;
9806 + /* "Never happens" */
9807 + if (nskb->len > nskb->dst->pmtu)
9810 + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
9811 + ip_finish_output);
9819 +static unsigned int reject6_target(struct sk_buff **pskb,
9820 + unsigned int hooknum,
9821 + const struct net_device *in,
9822 + const struct net_device *out,
9823 + const void *targinfo,
9826 + const struct ip6t_reject_info *reject = targinfo;
9828 + /* WARNING: This code causes reentry within ip6tables.
9829 + This means that the ip6tables jump stack is now crap. We
9830 + must return an absolute verdict. --RR */
9831 + DEBUGP("REJECTv6: calling icmpv6_send\n");
9832 + switch (reject->with) {
9833 + case IP6T_ICMP6_NO_ROUTE:
9834 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out);
9836 + case IP6T_ICMP6_ADM_PROHIBITED:
9837 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out);
9839 + case IP6T_ICMP6_NOT_NEIGHBOUR:
9840 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out);
9842 + case IP6T_ICMP6_ADDR_UNREACH:
9843 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out);
9845 + case IP6T_ICMP6_PORT_UNREACH:
9846 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out);
9849 + case IPT_ICMP_ECHOREPLY: {
9850 + struct icmp6hdr *icmph = (struct icmphdr *)
9851 + ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
9852 + unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
9854 + /* Not non-head frags, or truncated */
9855 + if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0)
9856 + && datalen >= 4) {
9857 + /* Usually I don't like cut & pasting code,
9858 + but dammit, my party is starting in 45
9860 + struct icmp_bxm icmp_param;
9862 + icmp_param.icmph=*icmph;
9863 + icmp_param.icmph.type=ICMP_ECHOREPLY;
9864 + icmp_param.data_ptr=(icmph+1);
9865 + icmp_param.data_len=datalen;
9866 + icmp_reply(&icmp_param, *pskb);
9870 + case IPT_TCP_RESET:
9871 + send_reset(*pskb);
9875 + printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with);
9882 +static inline int find_ping_match(const struct ip6t_entry_match *m)
9884 + const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data;
9886 + if (strcmp(m->u.kernel.match->name, "icmp6") == 0
9887 + && icmpinfo->type == ICMPV6_ECHO_REQUEST
9888 + && !(icmpinfo->invflags & IP6T_ICMP_INV))
9894 +static int check(const char *tablename,
9895 + const struct ip6t_entry *e,
9897 + unsigned int targinfosize,
9898 + unsigned int hook_mask)
9900 + const struct ip6t_reject_info *rejinfo = targinfo;
9902 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
9903 + DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize);
9907 + /* Only allow these for packet filtering. */
9908 + if (strcmp(tablename, "filter") != 0) {
9909 + DEBUGP("REJECTv6: bad table `%s'.\n", tablename);
9912 + if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
9913 + | (1 << NF_IP6_FORWARD)
9914 + | (1 << NF_IP6_LOCAL_OUT))) != 0) {
9915 + DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask);
9919 + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
9920 + /* Must specify that it's an ICMP ping packet. */
9921 + if (e->ipv6.proto != IPPROTO_ICMPV6
9922 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
9923 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n");
9926 + /* Must contain ICMP match. */
9927 + if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) {
9928 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n");
9931 + } else if (rejinfo->with == IP6T_TCP_RESET) {
9932 + /* Must specify that it's a TCP packet */
9933 + if (e->ipv6.proto != IPPROTO_TCP
9934 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
9935 + DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n");
9943 +static struct ip6t_target ip6t_reject_reg
9944 += { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE };
9946 +static int __init init(void)
9948 + if (ip6t_register_target(&ip6t_reject_reg))
9953 +static void __exit fini(void)
9955 + ip6t_unregister_target(&ip6t_reject_reg);
9960 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/Kconfig linux-2.6.3/net/ipv6/netfilter/Kconfig
9961 --- linux-2.6.3.org/net/ipv6/netfilter/Kconfig 2004-02-18 04:59:20.000000000 +0100
9962 +++ linux-2.6.3/net/ipv6/netfilter/Kconfig 2004-02-27 00:03:14.474027792 +0100
9963 @@ -218,5 +218,37 @@
9964 To compile it as a module, choose M here. If unsure, say N.
9966 #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
9967 +config IP6_NF_TARGET_HL
9968 + tristate 'HOPLIMIT target support'
9969 + depends on IP6_NF_MANGLE
9972 +config IP6_NF_TARGET_REJECT
9973 + tristate 'REJECT target support'
9974 + depends on IP6_NF_FILTER
9977 +config IP6_NF_MATCH_FUZZY
9978 + tristate 'Fuzzy match support'
9979 + depends on IP6_NF_FILTER
9982 +config IP6_NF_MATCH_NTH
9983 + tristate 'Nth match support'
9984 + depends on IP6_NF_IPTABLES
9988 + tristate 'raw table support (required for TRACE)'
9989 + depends on IP6_NF_IPTABLES
9991 + This option adds a `raw' table to ip6tables. This table is the very
9992 + first in the netfilter framework and hooks in at the PREROUTING
9993 + and OUTPUT chains.
9995 + If you want to compile it as a module, say M here and read
9996 + <file:Documentation/modules.txt>. If unsure, say `N'.
10001 diff -Nur linux-2.6.3.org/net/ipv6/netfilter/Makefile linux-2.6.3/net/ipv6/netfilter/Makefile
10002 --- linux-2.6.3.org/net/ipv6/netfilter/Makefile 2004-02-18 04:58:26.000000000 +0100
10003 +++ linux-2.6.3/net/ipv6/netfilter/Makefile 2004-02-27 00:03:14.474027792 +0100
10005 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
10006 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
10007 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
10008 +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
10009 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
10010 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
10011 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
10013 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
10014 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
10015 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
10016 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
10017 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
10018 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
10019 +obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
10021 +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
10022 +obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
10023 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o