1 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter.h linux-2.6.4-rc2/include/linux/netfilter.h
2 --- linux-2.6.4-rc2.org/include/linux/netfilter.h 2004-03-04 06:16:47.000000000 +0000
3 +++ linux-2.6.4-rc2/include/linux/netfilter.h 2004-03-05 09:55:08.000000000 +0000
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.4-rc2.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ip_conntrack.h
30 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ip_conntrack.h 2004-03-04 06:17:04.000000000 +0000
31 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ip_conntrack.h 2004-03-05 09:55:23.000000000 +0000
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.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h
43 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 00:00:00.000000000 +0000
44 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h 2004-03-05 09:55:14.000000000 +0000
46 +/* TTL modification module for IP tables
47 + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
58 +#define IPT_TTL_MAXMODE IPT_TTL_DEC
60 +struct ipt_TTL_info {
67 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ULOG.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ULOG.h
68 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ULOG.h 2004-03-04 06:16:43.000000000 +0000
69 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ULOG.h 2004-03-05 09:55:08.000000000 +0000
71 #define NETLINK_NFLOG 5
74 +#define ULOG_DEFAULT_NLGROUP 1
75 +#define ULOG_DEFAULT_QTHRESHOLD 1
77 #define ULOG_MAC_LEN 80
78 #define ULOG_PREFIX_LEN 32
80 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h
81 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 00:00:00.000000000 +0000
82 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-03-05 09:55:15.000000000 +0000
84 +#ifndef _IPT_CONNLIMIT_H
85 +#define _IPT_CONNLIMIT_H
87 +struct ipt_connlimit_data;
89 +struct ipt_connlimit_info {
93 + struct ipt_connlimit_data *data;
95 +#endif /* _IPT_CONNLIMIT_H */
96 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_conntrack.h
97 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_conntrack.h 2004-03-04 06:16:55.000000000 +0000
98 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_conntrack.h 2004-03-05 09:55:23.000000000 +0000
101 #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
102 #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
103 +#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
105 /* flags, invflags: */
106 #define IPT_CONNTRACK_STATE 0x01
107 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h
108 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 00:00:00.000000000 +0000
109 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-03-05 09:55:17.000000000 +0000
111 +#ifndef _IPT_DSTLIMIT_H
112 +#define _IPT_DSTLIMIT_H
114 +/* timings are in milliseconds. */
115 +#define IPT_DSTLIMIT_SCALE 10000
116 +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
117 + seconds, or one every 59 hours. */
119 +/* details of this structure hidden by the implementation */
120 +struct ipt_dstlimit_htable;
122 +#define IPT_DSTLIMIT_HASH_DIP 0x0001
123 +#define IPT_DSTLIMIT_HASH_DPT 0x0002
124 +#define IPT_DSTLIMIT_HASH_SIP 0x0004
126 +struct dstlimit_cfg {
127 + u_int32_t mode; /* bitmask of IPT_DSTLIMIT_HASH_* */
128 + u_int32_t avg; /* Average secs between packets * scale */
129 + u_int32_t burst; /* Period multiplier for upper limit. */
131 + /* user specified */
132 + u_int32_t size; /* how many buckets */
133 + u_int32_t max; /* max number of entries */
134 + u_int32_t gc_interval; /* gc interval */
135 + u_int32_t expire; /* when do entries expire? */
138 +struct ipt_dstlimit_info {
139 + char name [IFNAMSIZ]; /* name */
140 + struct dstlimit_cfg cfg;
141 + struct ipt_dstlimit_htable *hinfo;
143 + /* Used internally by the kernel */
146 + struct ipt_dstlimit_info *master;
149 +#endif /*_IPT_DSTLIMIT_H*/
150 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h
151 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 00:00:00.000000000 +0000
152 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h 2004-03-05 09:55:18.000000000 +0000
154 +#ifndef _IPT_FUZZY_H
155 +#define _IPT_FUZZY_H
157 +#include <linux/param.h>
158 +#include <linux/types.h>
160 +#define MAXFUZZYRATE 10000000
161 +#define MINFUZZYRATE 3
163 +struct ipt_fuzzy_info {
164 + u_int32_t minimum_rate;
165 + u_int32_t maximum_rate;
166 + u_int32_t packets_total;
167 + u_int32_t bytes_total;
168 + u_int32_t previous_time;
169 + u_int32_t present_time;
170 + u_int32_t mean_rate;
171 + u_int8_t acceptance_rate;
174 +#endif /*_IPT_FUZZY_H*/
175 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h
176 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 00:00:00.000000000 +0000
177 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-03-05 09:55:19.000000000 +0000
179 +#ifndef __ipt_ipv4options_h_included__
180 +#define __ipt_ipv4options_h_included__
182 +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */
183 +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */
184 +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */
185 +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */
186 +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10
187 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */
188 +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40
189 +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */
190 +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100
191 +#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */
192 +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */
194 +struct ipt_ipv4options_info {
199 +#endif /* __ipt_ipv4options_h_included__ */
200 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h
201 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 00:00:00.000000000 +0000
202 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h 2004-03-05 09:55:20.000000000 +0000
204 +#ifndef _IPT_MPORT_H
205 +#define _IPT_MPORT_H
206 +#include <linux/netfilter_ipv4/ip_tables.h>
208 +#define IPT_MPORT_SOURCE (1<<0)
209 +#define IPT_MPORT_DESTINATION (1<<1)
210 +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION)
212 +#define IPT_MULTI_PORTS 15
214 +/* Must fit inside union ipt_matchinfo: 32 bytes */
215 +/* every entry in ports[] except for the last one has one bit in pflags
216 + * associated with it. If this bit is set, the port is the first port of
217 + * a portrange, with the next entry being the last.
218 + * End of list is marked with pflags bit set and port=65535.
219 + * If 14 ports are used (last one does not have a pflag), the last port
220 + * is repeated to fill the last entry in ports[] */
223 + u_int8_t flags:2; /* Type of comparison */
224 + u_int16_t pflags:14; /* Port flags */
225 + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
227 +#endif /*_IPT_MPORT_H*/
228 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h
229 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 00:00:00.000000000 +0000
230 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h 2004-03-05 09:55:21.000000000 +0000
235 +#include <linux/param.h>
236 +#include <linux/types.h>
238 +#ifndef IPT_NTH_NUM_COUNTERS
239 +#define IPT_NTH_NUM_COUNTERS 16
242 +struct ipt_nth_info {
250 +#endif /*_IPT_NTH_H*/
251 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h
252 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 00:00:00.000000000 +0000
253 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h 2004-03-05 09:55:22.000000000 +0000
255 +#ifndef _IPT_QUOTA_H
256 +#define _IPT_QUOTA_H
258 +/* print debug info in both kernel/netfilter module & iptable library */
259 +//#define DEBUG_IPT_QUOTA
261 +struct ipt_quota_info {
265 +#endif /*_IPT_QUOTA_H*/
266 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h
267 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 00:00:00.000000000 +0000
268 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h 2004-03-05 09:55:23.000000000 +0000
270 +#ifndef _IPT_REALM_H
271 +#define _IPT_REALM_H
273 +struct ipt_realm_info {
278 +#endif /*_IPT_REALM_H*/
279 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h
280 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 00:00:00.000000000 +0000
281 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h 2004-03-05 09:55:25.000000000 +0000
283 +#ifndef _IPT_SCTP_H_
284 +#define _IPT_SCTP_H_
286 +#define IPT_SCTP_SRC_PORTS 0x01
287 +#define IPT_SCTP_DEST_PORTS 0x02
288 +#define IPT_SCTP_CHUNK_TYPES 0x04
290 +#define IPT_SCTP_VALID_FLAGS 0x07
292 +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
295 +struct ipt_sctp_flag_info {
296 + u_int8_t chunktype;
298 + u_int8_t flag_mask;
301 +#define IPT_NUM_SCTP_FLAGS 4
303 +struct ipt_sctp_info {
304 + u_int16_t dpts[2]; /* Min, Max */
305 + u_int16_t spts[2]; /* Min, Max */
307 + u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */
309 +#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */
310 +#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */
311 +#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */
313 + u_int32_t chunk_match_type;
314 + struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
318 + u_int32_t invflags;
321 +#define bytes(type) (sizeof(type) * 8)
323 +#define SCTP_CHUNKMAP_SET(chunkmap, type) \
325 + chunkmap[type / bytes(u_int32_t)] |= \
326 + 1 << (type % bytes(u_int32_t)); \
329 +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
331 + chunkmap[type / bytes(u_int32_t)] &= \
332 + ~(1 << (type % bytes(u_int32_t))); \
335 +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
337 + (chunkmap[type / bytes (u_int32_t)] & \
338 + (1 << (type % bytes (u_int32_t)))) ? 1: 0; \
341 +#define SCTP_CHUNKMAP_RESET(chunkmap) \
344 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
348 +#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
351 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
352 + chunkmap[i] = ~0; \
355 +#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
358 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
359 + destmap[i] = srcmap[i]; \
362 +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
366 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
367 + if (chunkmap[i]) { \
375 +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
379 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
380 + if (chunkmap[i] != ~0) { \
388 +#endif /* _IPT_SCTP_H_ */
390 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_state.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_state.h
391 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_state.h 2004-03-04 06:17:00.000000000 +0000
392 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_state.h 2004-03-05 09:55:23.000000000 +0000
394 #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
395 #define IPT_STATE_INVALID (1 << 0)
397 +#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
399 struct ipt_state_info
401 unsigned int statemask;
402 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_u32.h
403 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 00:00:00.000000000 +0000
404 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_u32.h 2004-03-05 09:56:07.000000000 +0000
408 +#include <linux/netfilter_ipv4/ip_tables.h>
418 +struct ipt_u32_location_element
423 +struct ipt_u32_value_element
428 +/* *** any way to allow for an arbitrary number of elements?
429 + for now I settle for a limit of 10 of each */
430 +#define U32MAXSIZE 10
434 + struct ipt_u32_location_element location[U32MAXSIZE+1];
436 + struct ipt_u32_value_element value[U32MAXSIZE+1];
442 + struct ipt_u32_test tests[U32MAXSIZE+1];
445 +#endif /*_IPT_U32_H*/
446 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4.h linux-2.6.4-rc2/include/linux/netfilter_ipv4.h
447 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4.h 2004-03-04 06:16:58.000000000 +0000
448 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4.h 2004-03-05 09:55:23.000000000 +0000
451 enum nf_ip_hook_priorities {
452 NF_IP_PRI_FIRST = INT_MIN,
453 + NF_IP_PRI_CONNTRACK_DEFRAG = -400,
454 + NF_IP_PRI_RAW = -300,
455 NF_IP_PRI_SELINUX_FIRST = -225,
456 NF_IP_PRI_CONNTRACK = -200,
457 NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
458 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h
459 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 00:00:00.000000000 +0000
460 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h 2004-03-05 09:55:10.000000000 +0000
462 +/* Hop Limit modification module for ip6tables
463 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
464 + * Based on HW's TTL module */
475 +#define IP6T_HL_MAXMODE IP6T_HL_DEC
477 +struct ip6t_HL_info {
479 + u_int8_t hop_limit;
484 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h
485 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-04 06:16:34.000000000 +0000
486 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-05 09:55:13.000000000 +0000
488 #define _IP6T_REJECT_H
490 enum ip6t_reject_with {
491 - IP6T_ICMP_NET_UNREACHABLE,
492 - IP6T_ICMP_HOST_UNREACHABLE,
493 - IP6T_ICMP_PROT_UNREACHABLE,
494 - IP6T_ICMP_PORT_UNREACHABLE,
495 - IP6T_ICMP_ECHOREPLY
496 + IP6T_ICMP6_NO_ROUTE,
497 + IP6T_ICMP6_ADM_PROHIBITED,
498 + IP6T_ICMP6_NOT_NEIGHBOUR,
499 + IP6T_ICMP6_ADDR_UNREACH,
500 + IP6T_ICMP6_PORT_UNREACH,
501 + IP6T_ICMP6_ECHOREPLY,
505 struct ip6t_reject_info {
506 enum ip6t_reject_with with; /* reject type */
509 -#endif /*_IPT_REJECT_H*/
510 +#endif /*_IP6T_REJECT_H*/
511 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h
512 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 00:00:00.000000000 +0000
513 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2004-03-05 09:55:18.000000000 +0000
515 +#ifndef _IP6T_FUZZY_H
516 +#define _IP6T_FUZZY_H
518 +#include <linux/param.h>
519 +#include <linux/types.h>
521 +#define MAXFUZZYRATE 10000000
522 +#define MINFUZZYRATE 3
524 +struct ip6t_fuzzy_info {
525 + u_int32_t minimum_rate;
526 + u_int32_t maximum_rate;
527 + u_int32_t packets_total;
528 + u_int32_t bytes_total;
529 + u_int32_t previous_time;
530 + u_int32_t present_time;
531 + u_int32_t mean_rate;
532 + u_int8_t acceptance_rate;
535 +#endif /*_IP6T_FUZZY_H*/
536 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h
537 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 00:00:00.000000000 +0000
538 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h 2004-03-05 09:55:21.000000000 +0000
543 +#include <linux/param.h>
544 +#include <linux/types.h>
546 +#ifndef IP6T_NTH_NUM_COUNTERS
547 +#define IP6T_NTH_NUM_COUNTERS 16
550 +struct ip6t_nth_info {
558 +#endif /*_IP6T_NTH_H*/
559 diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c linux-2.6.4-rc2/net/core/netfilter.c
560 --- linux-2.6.4-rc2.org/net/core/netfilter.c 2004-03-04 06:16:45.000000000 +0000
561 +++ linux-2.6.4-rc2/net/core/netfilter.c 2004-03-05 09:55:08.000000000 +0000
564 * February 2000: Modified by James Morris to have 1 queue per protocol.
565 * 15-Mar-2000: Added NF_REPEAT --RR.
566 + * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
568 #include <linux/config.h>
569 +#include <linux/kernel.h>
570 #include <linux/netfilter.h>
571 #include <net/protocol.h>
572 #include <linux/init.h>
574 } queue_handler[NPROTO];
575 static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
578 + * nf_register_hook - Register with a netfilter hook
579 + * @reg: Hook operations to be registered
581 int nf_register_hook(struct nf_hook_ops *reg)
589 + * nf_unregister_hook - Unregister from a netfilter hook
590 + * @reg: hook operations to be unregistered
592 void nf_unregister_hook(struct nf_hook_ops *reg)
594 spin_lock_bh(&nf_hook_lock);
600 + * nf_register_queue_handler - Registere a queue handler with netfilter
601 + * @pf: protocol family
602 + * @outfn: function called by core to enqueue a packet
603 + * @data: opaque parameter, passed through
605 + * This function registers a queue handler with netfilter. There can only
606 + * be one queue handler for every protocol family.
608 + * A queue handler _must_ reinject every packet via nf_reinject, no
611 int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
618 -/* The caller must flush their queue before this */
620 + * nf_unregister_queue_handler - Unregister queue handler from netfilter
621 + * @pf: protocol family
623 + * The caller must flush their queue before unregistering
625 int nf_unregister_queue_handler(int pf)
627 write_lock_bh(&queue_handler_lock);
633 + * nf_reinject - Reinject a packet from a queue handler
634 + * @skb: the packet to be reinjected
635 + * @info: info which was passed to the outfn() of the queue handler
636 + * @verdict: verdict (NF_ACCEPT, ...) for this packet
638 + * This is the function called by a queue handler to reinject a
641 void nf_reinject(struct sk_buff *skb, struct nf_info *info,
642 unsigned int verdict)
645 EXPORT_SYMBOL(skb_ip_make_writable);
646 #endif /*CONFIG_INET*/
648 +/* Internal logging interface, which relies on the real
649 + LOG target modules */
651 +#define NF_LOG_PREFIXLEN 128
653 +static nf_logfn *nf_logging[NPROTO]; /* = NULL */
654 +static int reported = 0;
655 +static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
657 +int nf_log_register(int pf, nf_logfn *logfn)
661 + /* Any setup of logging members must be done before
662 + * substituting pointer. */
664 + spin_lock(&nf_log_lock);
665 + if (!nf_logging[pf]) {
666 + nf_logging[pf] = logfn;
669 + spin_unlock(&nf_log_lock);
673 +void nf_log_unregister(int pf, nf_logfn *logfn)
675 + spin_lock(&nf_log_lock);
676 + if (nf_logging[pf] == logfn)
677 + nf_logging[pf] = NULL;
678 + spin_unlock(&nf_log_lock);
680 + /* Give time to concurrent readers. */
684 +void nf_log_packet(int pf,
685 + unsigned int hooknum,
686 + const struct sk_buff *skb,
687 + const struct net_device *in,
688 + const struct net_device *out,
689 + const char *fmt, ...)
692 + char prefix[NF_LOG_PREFIXLEN];
696 + logfn = nf_logging[pf];
698 + va_start(args, fmt);
699 + vsnprintf(prefix, sizeof(prefix), fmt, args);
701 + /* We must read logging before nf_logfn[pf] */
702 + smp_read_barrier_depends();
703 + logfn(hooknum, skb, in, out, prefix);
704 + } else if (!reported) {
705 + printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
706 + "no backend logging module loaded in!\n");
711 +EXPORT_SYMBOL(nf_log_register);
712 +EXPORT_SYMBOL(nf_log_unregister);
713 +EXPORT_SYMBOL(nf_log_packet);
715 /* This does not belong here, but ipt_REJECT needs it if connection
716 tracking in use: without this, connection may not be in hash table,
717 diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c.orig linux-2.6.4-rc2/net/core/netfilter.c.orig
718 --- linux-2.6.4-rc2.org/net/core/netfilter.c.orig 1970-01-01 00:00:00.000000000 +0000
719 +++ linux-2.6.4-rc2/net/core/netfilter.c.orig 2004-03-05 09:55:06.000000000 +0000
721 +/* netfilter.c: look after the filters for various protocols.
722 + * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
724 + * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
727 + * Rusty Russell (C)2000 -- This code is GPL.
729 + * February 2000: Modified by James Morris to have 1 queue per protocol.
730 + * 15-Mar-2000: Added NF_REPEAT --RR.
732 +#include <linux/config.h>
733 +#include <linux/netfilter.h>
734 +#include <net/protocol.h>
735 +#include <linux/init.h>
736 +#include <linux/skbuff.h>
737 +#include <linux/wait.h>
738 +#include <linux/module.h>
739 +#include <linux/interrupt.h>
740 +#include <linux/if.h>
741 +#include <linux/netdevice.h>
742 +#include <linux/inetdevice.h>
743 +#include <linux/tcp.h>
744 +#include <linux/udp.h>
745 +#include <linux/icmp.h>
746 +#include <net/sock.h>
747 +#include <net/route.h>
748 +#include <linux/ip.h>
750 +/* In this code, we can be waiting indefinitely for userspace to
751 + * service a packet if a hook returns NF_QUEUE. We could keep a count
752 + * of skbuffs queued for userspace, and not deregister a hook unless
753 + * this is zero, but that sucks. Now, we simply check when the
754 + * packets come back: if the hook is gone, the packet is discarded. */
755 +#ifdef CONFIG_NETFILTER_DEBUG
756 +#define NFDEBUG(format, args...) printk(format , ## args)
758 +#define NFDEBUG(format, args...)
761 +/* Sockopts only registered and called from user context, so
762 + net locking would be overkill. Also, [gs]etsockopt calls may
764 +static DECLARE_MUTEX(nf_sockopt_mutex);
766 +struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
767 +static LIST_HEAD(nf_sockopts);
768 +static spinlock_t nf_hook_lock = SPIN_LOCK_UNLOCKED;
771 + * A queue handler may be registered for each protocol. Each is protected by
772 + * long term mutex. The handler must provide an an outfn() to accept packets
773 + * for queueing and must reinject all packets it receives, no matter what.
775 +static struct nf_queue_handler_t {
776 + nf_queue_outfn_t outfn;
778 +} queue_handler[NPROTO];
779 +static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
782 + * nf_register_hook - Register with a netfilter hook
783 + * @reg: Hook operations to be registered
785 +int nf_register_hook(struct nf_hook_ops *reg)
787 + struct list_head *i;
789 + spin_lock_bh(&nf_hook_lock);
790 + list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
791 + if (reg->priority < ((struct nf_hook_ops *)i)->priority)
794 + list_add_rcu(®->list, i->prev);
795 + spin_unlock_bh(&nf_hook_lock);
802 + * nf_unregister_hook - Unregister from a netfilter hook
803 + * @reg: hook operations to be unregistered
805 +void nf_unregister_hook(struct nf_hook_ops *reg)
807 + spin_lock_bh(&nf_hook_lock);
808 + list_del_rcu(®->list);
809 + spin_unlock_bh(&nf_hook_lock);
814 +/* Do exclusive ranges overlap? */
815 +static inline int overlap(int min1, int max1, int min2, int max2)
817 + return max1 > min2 && min1 < max2;
820 +/* Functions to register sockopt ranges (exclusive). */
821 +int nf_register_sockopt(struct nf_sockopt_ops *reg)
823 + struct list_head *i;
826 + if (down_interruptible(&nf_sockopt_mutex) != 0)
829 + list_for_each(i, &nf_sockopts) {
830 + struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
831 + if (ops->pf == reg->pf
832 + && (overlap(ops->set_optmin, ops->set_optmax,
833 + reg->set_optmin, reg->set_optmax)
834 + || overlap(ops->get_optmin, ops->get_optmax,
835 + reg->get_optmin, reg->get_optmax))) {
836 + NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
837 + ops->set_optmin, ops->set_optmax,
838 + ops->get_optmin, ops->get_optmax,
839 + reg->set_optmin, reg->set_optmax,
840 + reg->get_optmin, reg->get_optmax);
846 + list_add(®->list, &nf_sockopts);
848 + up(&nf_sockopt_mutex);
852 +void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
854 + /* No point being interruptible: we're probably in cleanup_module() */
856 + down(&nf_sockopt_mutex);
857 + if (reg->use != 0) {
858 + /* To be woken by nf_sockopt call... */
859 + /* FIXME: Stuart Young's name appears gratuitously. */
860 + set_current_state(TASK_UNINTERRUPTIBLE);
861 + reg->cleanup_task = current;
862 + up(&nf_sockopt_mutex);
866 + list_del(®->list);
867 + up(&nf_sockopt_mutex);
870 +#ifdef CONFIG_NETFILTER_DEBUG
872 +#include <net/tcp.h>
873 +#include <linux/netfilter_ipv4.h>
875 +static void debug_print_hooks_ip(unsigned int nf_debug)
877 + if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
878 + printk("PRE_ROUTING ");
879 + nf_debug ^= (1 << NF_IP_PRE_ROUTING);
881 + if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
882 + printk("LOCAL_IN ");
883 + nf_debug ^= (1 << NF_IP_LOCAL_IN);
885 + if (nf_debug & (1 << NF_IP_FORWARD)) {
886 + printk("FORWARD ");
887 + nf_debug ^= (1 << NF_IP_FORWARD);
889 + if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
890 + printk("LOCAL_OUT ");
891 + nf_debug ^= (1 << NF_IP_LOCAL_OUT);
893 + if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
894 + printk("POST_ROUTING ");
895 + nf_debug ^= (1 << NF_IP_POST_ROUTING);
898 + printk("Crap bits: 0x%04X", nf_debug);
902 +void nf_dump_skb(int pf, struct sk_buff *skb)
904 + printk("skb: pf=%i %s dev=%s len=%u\n",
906 + skb->sk ? "(owned)" : "(unowned)",
907 + skb->dev ? skb->dev->name : "(no dev)",
911 + const struct iphdr *ip = skb->nh.iph;
912 + __u32 *opt = (__u32 *) (ip + 1);
914 + __u16 src_port = 0, dst_port = 0;
916 + if (ip->protocol == IPPROTO_TCP
917 + || ip->protocol == IPPROTO_UDP) {
918 + struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
919 + src_port = ntohs(tcp->source);
920 + dst_port = ntohs(tcp->dest);
923 + printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
924 + " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
925 + ip->protocol, NIPQUAD(ip->saddr),
926 + src_port, NIPQUAD(ip->daddr),
928 + ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
929 + ntohs(ip->frag_off), ip->ttl);
931 + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
932 + printk(" O=0x%8.8X", *opt++);
938 +void nf_debug_ip_local_deliver(struct sk_buff *skb)
940 + /* If it's a loopback packet, it must have come through
941 + * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and
942 + * NF_IP_LOCAL_IN. Otherwise, must have gone through
943 + * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */
945 + printk("ip_local_deliver: skb->dev is NULL.\n");
947 + else if (strcmp(skb->dev->name, "lo") == 0) {
948 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
949 + | (1 << NF_IP_POST_ROUTING)
950 + | (1 << NF_IP_PRE_ROUTING)
951 + | (1 << NF_IP_LOCAL_IN))) {
952 + printk("ip_local_deliver: bad loopback skb: ");
953 + debug_print_hooks_ip(skb->nf_debug);
954 + nf_dump_skb(PF_INET, skb);
958 + if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)
959 + | (1<<NF_IP_LOCAL_IN))) {
960 + printk("ip_local_deliver: bad non-lo skb: ");
961 + debug_print_hooks_ip(skb->nf_debug);
962 + nf_dump_skb(PF_INET, skb);
967 +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb)
969 + if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
970 + | (1 << NF_IP_POST_ROUTING))) {
971 + printk("ip_dev_loopback_xmit: bad owned skb = %p: ",
973 + debug_print_hooks_ip(newskb->nf_debug);
974 + nf_dump_skb(PF_INET, newskb);
976 + /* Clear to avoid confusing input check */
977 + newskb->nf_debug = 0;
980 +void nf_debug_ip_finish_output2(struct sk_buff *skb)
982 + /* If it's owned, it must have gone through the
983 + * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING.
984 + * Otherwise, must have gone through
985 + * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING.
988 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
989 + | (1 << NF_IP_POST_ROUTING))) {
990 + printk("ip_finish_output: bad owned skb = %p: ", skb);
991 + debug_print_hooks_ip(skb->nf_debug);
992 + nf_dump_skb(PF_INET, skb);
995 + if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING)
996 + | (1 << NF_IP_FORWARD)
997 + | (1 << NF_IP_POST_ROUTING))) {
998 + /* Fragments, entunnelled packets, TCP RSTs
999 + generated by ipt_REJECT will have no
1000 + owners, but still may be local */
1001 + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
1002 + | (1 << NF_IP_POST_ROUTING))){
1003 + printk("ip_finish_output:"
1004 + " bad unowned skb = %p: ",skb);
1005 + debug_print_hooks_ip(skb->nf_debug);
1006 + nf_dump_skb(PF_INET, skb);
1011 +#endif /*CONFIG_NETFILTER_DEBUG*/
1013 +/* Call get/setsockopt() */
1014 +static int nf_sockopt(struct sock *sk, int pf, int val,
1015 + char *opt, int *len, int get)
1017 + struct list_head *i;
1018 + struct nf_sockopt_ops *ops;
1021 + if (down_interruptible(&nf_sockopt_mutex) != 0)
1024 + list_for_each(i, &nf_sockopts) {
1025 + ops = (struct nf_sockopt_ops *)i;
1026 + if (ops->pf == pf) {
1028 + if (val >= ops->get_optmin
1029 + && val < ops->get_optmax) {
1031 + up(&nf_sockopt_mutex);
1032 + ret = ops->get(sk, val, opt, len);
1036 + if (val >= ops->set_optmin
1037 + && val < ops->set_optmax) {
1039 + up(&nf_sockopt_mutex);
1040 + ret = ops->set(sk, val, opt, *len);
1046 + up(&nf_sockopt_mutex);
1047 + return -ENOPROTOOPT;
1050 + down(&nf_sockopt_mutex);
1052 + if (ops->cleanup_task)
1053 + wake_up_process(ops->cleanup_task);
1054 + up(&nf_sockopt_mutex);
1058 +int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
1061 + return nf_sockopt(sk, pf, val, opt, &len, 0);
1064 +int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
1066 + return nf_sockopt(sk, pf, val, opt, len, 1);
1069 +static unsigned int nf_iterate(struct list_head *head,
1070 + struct sk_buff **skb,
1072 + const struct net_device *indev,
1073 + const struct net_device *outdev,
1074 + struct list_head **i,
1075 + int (*okfn)(struct sk_buff *),
1079 + * The caller must not block between calls to this
1080 + * function because of risk of continuing from deleted element.
1082 + list_for_each_continue_rcu(*i, head) {
1083 + struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
1085 + if (hook_thresh > elem->priority)
1088 + /* Optimization: we don't need to hold module
1089 + reference here, since function can't sleep. --RR */
1090 + switch (elem->hook(hook, skb, indev, outdev, okfn)) {
1104 +#ifdef CONFIG_NETFILTER_DEBUG
1109 + NFDEBUG("Evil return from %p(%u).\n",
1110 + elem->hook, hook);
1118 + * nf_register_queue_handler - Registere a queue handler with netfilter
1119 + * @pf: protocol family
1120 + * @outfn: function called by core to enqueue a packet
1121 + * @data: opaque parameter, passed through
1123 + * This function registers a queue handler with netfilter. There can only
1124 + * be one queue handler for every protocol family.
1126 + * A queue handler _must_ reinject every packet via nf_reinject, no
1129 +int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
1133 + write_lock_bh(&queue_handler_lock);
1134 + if (queue_handler[pf].outfn)
1137 + queue_handler[pf].outfn = outfn;
1138 + queue_handler[pf].data = data;
1141 + write_unlock_bh(&queue_handler_lock);
1147 + * nf_unregister_queue_handler - Unregister queue handler from netfilter
1148 + * @pf: protocol family
1150 + * The caller must flush their queue before unregistering
1152 +int nf_unregister_queue_handler(int pf)
1154 + write_lock_bh(&queue_handler_lock);
1155 + queue_handler[pf].outfn = NULL;
1156 + queue_handler[pf].data = NULL;
1157 + write_unlock_bh(&queue_handler_lock);
1163 + * Any packet that leaves via this function must come back
1164 + * through nf_reinject().
1166 +static int nf_queue(struct sk_buff *skb,
1167 + struct list_head *elem,
1168 + int pf, unsigned int hook,
1169 + struct net_device *indev,
1170 + struct net_device *outdev,
1171 + int (*okfn)(struct sk_buff *))
1174 + struct nf_info *info;
1175 +#ifdef CONFIG_BRIDGE_NETFILTER
1176 + struct net_device *physindev = NULL;
1177 + struct net_device *physoutdev = NULL;
1180 + /* QUEUE == DROP if noone is waiting, to be safe. */
1181 + read_lock(&queue_handler_lock);
1182 + if (!queue_handler[pf].outfn) {
1183 + read_unlock(&queue_handler_lock);
1188 + info = kmalloc(sizeof(*info), GFP_ATOMIC);
1190 + if (net_ratelimit())
1191 + printk(KERN_ERR "OOM queueing packet %p\n",
1193 + read_unlock(&queue_handler_lock);
1198 + *info = (struct nf_info) {
1199 + (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
1201 + /* If it's going away, ignore hook. */
1202 + if (!try_module_get(info->elem->owner)) {
1203 + read_unlock(&queue_handler_lock);
1208 + /* Bump dev refs so they don't vanish while packet is out */
1209 + if (indev) dev_hold(indev);
1210 + if (outdev) dev_hold(outdev);
1212 +#ifdef CONFIG_BRIDGE_NETFILTER
1213 + if (skb->nf_bridge) {
1214 + physindev = skb->nf_bridge->physindev;
1215 + if (physindev) dev_hold(physindev);
1216 + physoutdev = skb->nf_bridge->physoutdev;
1217 + if (physoutdev) dev_hold(physoutdev);
1221 + status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
1222 + read_unlock(&queue_handler_lock);
1225 + /* James M doesn't say fuck enough. */
1226 + if (indev) dev_put(indev);
1227 + if (outdev) dev_put(outdev);
1228 +#ifdef CONFIG_BRIDGE_NETFILTER
1229 + if (physindev) dev_put(physindev);
1230 + if (physoutdev) dev_put(physoutdev);
1232 + module_put(info->elem->owner);
1240 +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
1241 + struct net_device *indev,
1242 + struct net_device *outdev,
1243 + int (*okfn)(struct sk_buff *),
1246 + struct list_head *elem;
1247 + unsigned int verdict;
1250 + if (skb->ip_summed == CHECKSUM_HW) {
1251 + if (outdev == NULL) {
1252 + skb->ip_summed = CHECKSUM_NONE;
1254 + skb_checksum_help(skb);
1258 + /* We may already have this, but read-locks nest anyway */
1261 +#ifdef CONFIG_NETFILTER_DEBUG
1262 + if (skb->nf_debug & (1 << hook)) {
1263 + printk("nf_hook: hook %i already set.\n", hook);
1264 + nf_dump_skb(pf, skb);
1266 + skb->nf_debug |= (1 << hook);
1269 + elem = &nf_hooks[pf][hook];
1271 + verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
1272 + outdev, &elem, okfn, hook_thresh);
1273 + if (verdict == NF_QUEUE) {
1274 + NFDEBUG("nf_hook: Verdict = QUEUE.\n");
1275 + if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn))
1279 + switch (verdict) {
1290 + rcu_read_unlock();
1295 + * nf_reinject - Reinject a packet from a queue handler
1296 + * @skb: the packet to be reinjected
1297 + * @info: info which was passed to the outfn() of the queue handler
1298 + * @verdict: verdict (NF_ACCEPT, ...) for this packet
1300 + * This is the function called by a queue handler to reinject a
1303 +void nf_reinject(struct sk_buff *skb, struct nf_info *info,
1304 + unsigned int verdict)
1306 + struct list_head *elem = &info->elem->list;
1307 + struct list_head *i;
1311 + /* Release those devices we held, or Alexey will kill me. */
1312 + if (info->indev) dev_put(info->indev);
1313 + if (info->outdev) dev_put(info->outdev);
1314 +#ifdef CONFIG_BRIDGE_NETFILTER
1315 + if (skb->nf_bridge) {
1316 + if (skb->nf_bridge->physindev)
1317 + dev_put(skb->nf_bridge->physindev);
1318 + if (skb->nf_bridge->physoutdev)
1319 + dev_put(skb->nf_bridge->physoutdev);
1323 + /* Drop reference to owner of hook which queued us. */
1324 + module_put(info->elem->owner);
1326 + list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
1331 + if (elem == &nf_hooks[info->pf][info->hook]) {
1332 + /* The module which sent it to userspace is gone. */
1333 + NFDEBUG("%s: module disappeared, dropping packet.\n",
1335 + verdict = NF_DROP;
1338 + /* Continue traversal iff userspace said ok... */
1339 + if (verdict == NF_REPEAT) {
1340 + elem = elem->prev;
1341 + verdict = NF_ACCEPT;
1344 + if (verdict == NF_ACCEPT) {
1346 + verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
1348 + info->indev, info->outdev, &elem,
1349 + info->okfn, INT_MIN);
1352 + switch (verdict) {
1358 + if (!nf_queue(skb, elem, info->pf, info->hook,
1359 + info->indev, info->outdev, info->okfn))
1363 + rcu_read_unlock();
1365 + if (verdict == NF_DROP)
1373 +/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
1374 +int ip_route_me_harder(struct sk_buff **pskb)
1376 + struct iphdr *iph = (*pskb)->nh.iph;
1377 + struct rtable *rt;
1378 + struct flowi fl = {};
1379 + struct dst_entry *odst;
1380 + unsigned int hh_len;
1382 + /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
1383 + * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
1385 + if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
1386 + fl.nl_u.ip4_u.daddr = iph->daddr;
1387 + fl.nl_u.ip4_u.saddr = iph->saddr;
1388 + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
1389 + fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
1390 +#ifdef CONFIG_IP_ROUTE_FWMARK
1391 + fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
1393 + if (ip_route_output_key(&rt, &fl) != 0)
1396 + /* Drop old route. */
1397 + dst_release((*pskb)->dst);
1398 + (*pskb)->dst = &rt->u.dst;
1400 + /* non-local src, find valid iif to satisfy
1401 + * rp-filter when calling ip_route_input. */
1402 + fl.nl_u.ip4_u.daddr = iph->saddr;
1403 + if (ip_route_output_key(&rt, &fl) != 0)
1406 + odst = (*pskb)->dst;
1407 + if (ip_route_input(*pskb, iph->daddr, iph->saddr,
1408 + RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
1409 + dst_release(&rt->u.dst);
1412 + dst_release(&rt->u.dst);
1413 + dst_release(odst);
1416 + if ((*pskb)->dst->error)
1419 + /* Change in oif may mean change in hh_len. */
1420 + hh_len = (*pskb)->dst->dev->hard_header_len;
1421 + if (skb_headroom(*pskb) < hh_len) {
1422 + struct sk_buff *nskb;
1424 + nskb = skb_realloc_headroom(*pskb, hh_len);
1428 + skb_set_owner_w(nskb, (*pskb)->sk);
1436 +int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
1438 + struct sk_buff *nskb;
1439 + unsigned int iplen;
1441 + if (writable_len > (*pskb)->len)
1444 + /* Not exclusive use of packet? Must copy. */
1445 + if (skb_shared(*pskb) || skb_cloned(*pskb))
1448 + /* Alexey says IP hdr is always modifiable and linear, so ok. */
1449 + if (writable_len <= (*pskb)->nh.iph->ihl*4)
1452 + iplen = writable_len - (*pskb)->nh.iph->ihl*4;
1454 + /* DaveM says protocol headers are also modifiable. */
1455 + switch ((*pskb)->nh.iph->protocol) {
1456 + case IPPROTO_TCP: {
1457 + struct tcphdr hdr;
1458 + if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
1459 + &hdr, sizeof(hdr)) != 0)
1461 + if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
1466 + if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
1469 + case IPPROTO_ICMP:
1471 + <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
1474 + /* Insert other cases here as desired */
1478 + nskb = skb_copy(*pskb, GFP_ATOMIC);
1481 + BUG_ON(skb_is_nonlinear(nskb));
1483 + /* Rest of kernel will get very unhappy if we pass it a
1484 + suddenly-orphaned skbuff */
1486 + skb_set_owner_w(nskb, (*pskb)->sk);
1492 + return pskb_may_pull(*pskb, writable_len);
1494 +EXPORT_SYMBOL(skb_ip_make_writable);
1495 +#endif /*CONFIG_INET*/
1498 +/* This does not belong here, but ipt_REJECT needs it if connection
1499 + tracking in use: without this, connection may not be in hash table,
1500 + and hence manufactured ICMP or RST packets will not be associated
1502 +void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
1504 +void __init netfilter_init(void)
1508 + for (i = 0; i < NPROTO; i++) {
1509 + for (h = 0; h < NF_MAX_HOOKS; h++)
1510 + INIT_LIST_HEAD(&nf_hooks[i][h]);
1514 +EXPORT_SYMBOL(ip_ct_attach);
1515 +EXPORT_SYMBOL(ip_route_me_harder);
1516 +EXPORT_SYMBOL(nf_getsockopt);
1517 +EXPORT_SYMBOL(nf_hook_slow);
1518 +EXPORT_SYMBOL(nf_hooks);
1519 +EXPORT_SYMBOL(nf_register_hook);
1520 +EXPORT_SYMBOL(nf_register_queue_handler);
1521 +EXPORT_SYMBOL(nf_register_sockopt);
1522 +EXPORT_SYMBOL(nf_reinject);
1523 +EXPORT_SYMBOL(nf_setsockopt);
1524 +EXPORT_SYMBOL(nf_unregister_hook);
1525 +EXPORT_SYMBOL(nf_unregister_queue_handler);
1526 +EXPORT_SYMBOL(nf_unregister_sockopt);
1527 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig
1528 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig 2004-03-04 06:16:58.000000000 +0000
1529 +++ linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig 2004-03-05 09:56:07.000000000 +0000
1530 @@ -579,5 +579,89 @@
1532 To compile it as a module, choose M here. If unsure, say N.
1534 +config IP_NF_TARGET_IPV4OPTSSTRIP
1535 + tristate 'IPV4OPTSSTRIP target support'
1536 + depends on IP_NF_MANGLE
1539 +config IP_NF_TARGET_TTL
1540 + tristate 'TTL target support'
1541 + depends on IP_NF_MANGLE
1544 +config IP_NF_MATCH_CONNLIMIT
1545 + tristate 'Connections/IP limit match support'
1546 + depends on IP_NF_IPTABLES
1549 +config IP_NF_MATCH_DSTLIMIT
1550 + tristate 'dstlimit match support'
1551 + depends on IP_NF_IPTABLES
1554 +config IP_NF_MATCH_FUZZY
1555 + tristate 'fuzzy match support'
1556 + depends on IP_NF_IPTABLES
1559 +config IP_NF_MATCH_IPV4OPTIONS
1560 + tristate 'IPV4OPTIONS match support'
1561 + depends on IP_NF_IPTABLES
1564 +config IP_NF_MATCH_MPORT
1565 + tristate 'Multiple port with ranges match support'
1566 + depends on IP_NF_IPTABLES
1569 +config IP_NF_MATCH_NTH
1570 + tristate 'Nth match support'
1571 + depends on IP_NF_IPTABLES
1574 +config IP_NF_MATCH_QUOTA
1575 + tristate 'quota match support'
1576 + depends on IP_NF_IPTABLES
1579 +config IP_NF_TARGET_NOTRACK
1580 + tristate 'NOTRACK target support'
1581 + depends on IP_NF_RAW
1583 + The NOTRACK target allows a select rule to specify
1584 + which packets *not* to enter the conntrack/NAT
1585 + subsystem with all the consequences (no ICMP error tracking,
1586 + no protocol helpers for the selected packets).
1588 + If you want to compile it as a module, say M here and read
1589 + <file:Documentation/modules.txt>. If unsure, say `N'.
1592 + tristate 'raw table support (required for NOTRACK/TRACE)'
1593 + depends on IP_NF_IPTABLES
1595 + This option adds a `raw' table to iptables. This table is the very
1596 + first in the netfilter framework and hooks in at the PREROUTING
1597 + and OUTPUT chains.
1599 + If you want to compile it as a module, say M here and read
1600 + <file:Documentation/modules.txt>. If unsure, say `N'.
1603 +config IP_NF_MATCH_REALM
1604 + tristate 'realm match support'
1605 + depends on IP_NF_IPTABLES && NET_CLS_ROUTE
1608 +config IP_NF_MATCH_SCTP
1609 + tristate 'SCTP protocol match support'
1610 + depends on IP_NF_IPTABLES
1613 +config IP_NF_MATCH_U32
1614 + tristate 'U32 match support'
1615 + depends on IP_NF_IPTABLES
1620 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.4-rc2/net/ipv4/netfilter/Makefile
1621 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile 2004-03-04 06:16:38.000000000 +0000
1622 +++ linux-2.6.4-rc2/net/ipv4/netfilter/Makefile 2004-03-05 09:56:07.000000000 +0000
1624 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
1625 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
1626 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
1627 +obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
1630 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
1631 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
1632 +obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
1633 +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
1634 +obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o
1635 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
1636 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
1637 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
1639 obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
1640 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
1642 +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
1644 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
1645 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
1647 +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
1649 +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
1652 +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
1654 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
1656 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
1659 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
1661 +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
1664 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
1665 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
1666 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
1667 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
1668 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
1669 +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
1671 obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
1674 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
1675 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
1676 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
1677 +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
1678 +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
1679 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
1680 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
1681 +obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
1683 # generic ARP tables
1684 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
1685 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c
1686 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-04 06:16:34.000000000 +0000
1687 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-05 09:55:23.000000000 +0000
1689 * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
1690 * - add usage/reference counts to ip_conntrack_expect
1691 * - export ip_conntrack[_expect]_{find_get,put} functions
1692 + * 05 Aug 2002: Harald Welte <laforge@gnumonks.org>
1693 + * - added DocBook-style comments for public API
1696 #include <linux/config.h>
1698 static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
1699 struct list_head *ip_conntrack_hash;
1700 static kmem_cache_t *ip_conntrack_cachep;
1701 +struct ip_conntrack ip_conntrack_untracked;
1703 extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
1710 + * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number
1711 + * @protocol: protocol number
1713 struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
1715 struct ip_conntrack_protocol *p;
1716 @@ -112,6 +119,11 @@
1717 static int ip_conntrack_hash_rnd_initted;
1718 static unsigned int ip_conntrack_hash_rnd;
1721 + * hash_conntrack - Calculate the position of an entry in the connection
1723 + * @tuple: conntrack tuple which we want to calculate the hash position
1726 hash_conntrack(const struct ip_conntrack_tuple *tuple)
1728 @@ -124,6 +136,19 @@
1729 ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
1733 + * get_tuple - set all the fields of a tuple which is passed as parameter
1734 + * given a network buffer.
1735 + * @iph:pointer an IP header.
1736 + * @skb:network buffer for which we want to generate the tuple
1737 + * @dataoff: FIXME: Deprecated?
1738 + * @tuple: tuple which will be generate. Used as return parameter.
1739 + * @protocol: structure which contains pointer to protocol specific functions.
1741 + * Note: This function doesn't allocate space for the tuple passed as
1742 + * parameter. The function pkt_to_packet which set all the protocol specific
1743 + * fields of a given tuple.
1746 get_tuple(const struct iphdr *iph,
1747 const struct sk_buff *skb,
1748 @@ -145,6 +170,15 @@
1749 return protocol->pkt_to_tuple(skb, dataoff, tuple);
1753 + * invert_tuple - Returns the inverse of a given tuple. It is used to
1754 + * calculate the tuple which represents the other sense of the flow
1755 + * of a connection.
1756 + * @inverse: the inverted tuple. Use as return value.
1757 + * @orig: the original tuple which will be inverted.
1758 + * @protocol: a pointer to the protocol structure which contains all the
1759 + * specifical functions available for this tuple.
1762 invert_tuple(struct ip_conntrack_tuple *inverse,
1763 const struct ip_conntrack_tuple *orig,
1764 @@ -160,7 +194,15 @@
1766 /* ip_conntrack_expect helper functions */
1768 -/* Compare tuple parts depending on mask. */
1770 + * expect_cmp - compare a tuple with a expectation depending on a mask
1771 + * @i: pointer to an expectation.
1772 + * @tuple: tuple which will be compared with the expectation tuple.
1774 + * Actually the tuple field of an expectation is compared with a tuple
1775 + * This function is used by LIST_FIND to find a expectation which match a te
1778 static inline int expect_cmp(const struct ip_conntrack_expect *i,
1779 const struct ip_conntrack_tuple *tuple)
1781 @@ -168,6 +210,10 @@
1782 return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1786 + * destroy_expect - Release all the resources allocated by an expectation.
1787 + * @exp: pointer to the expectation which we want to release.
1790 destroy_expect(struct ip_conntrack_expect *exp)
1792 @@ -178,7 +224,11 @@
1798 + * ip_conntrack_expect_put - it decrements the counter of use related
1799 + * associated to an expectation and it calls destroy_expect.
1800 + * @exp: pointer to the expectation which we want to release.
1802 inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
1805 @@ -198,7 +248,14 @@
1806 struct ip_conntrack_expect *, tuple);
1809 -/* Find a expectation corresponding to a tuple. */
1811 + * ip_conntrack_find_get - find conntrack according to tuple
1812 + * @tuple: conntrack tuple for which we search conntrack
1813 + * @ignored_conntrack: ignore this conntrack during search
1815 + * This function increments the reference count of the found
1816 + * conntrack (if any).
1818 struct ip_conntrack_expect *
1819 ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
1821 @@ -381,7 +438,14 @@
1825 -/* Find a connection corresponding to a tuple. */
1827 + * ip_conntrack_find_get - find conntrack according to tuple
1828 + * @tuple: conntrack tuple for which we search conntrack
1829 + * @ignored_conntrack: ignore this conntrack during search
1831 + * This function increments the reference count of the found
1832 + * conntrack (if any).
1834 struct ip_conntrack_tuple_hash *
1835 ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
1836 const struct ip_conntrack *ignored_conntrack)
1837 @@ -409,7 +473,14 @@
1841 -/* Return conntrack and conntrack_info given skb->nfct->master */
1843 + * ip_conntrack_get - Return conntrack and conntrack_info for given skb
1844 + * @skb: skb for which we want to find conntrack and conntrack_info
1845 + * @ctinfo: pointer to ctinfo, used as return value
1847 + * This function resolves the respective conntrack and conntrack_info
1848 + * structures for the connection this packet (skb) is part of.
1850 struct ip_conntrack *
1851 ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
1853 @@ -479,8 +550,14 @@
1857 -/* Returns true if a connection correspondings to the tuple (required
1860 + * ip_conntrack_tuple_taken - Find out if tuple is already in use
1861 + * @tuple: tuple to be used for this test
1862 + * @ignored_conntrack: conntrack which is excluded from result
1864 + * This function is called by the NAT code in order to find out if
1865 + * a particular tuple is already in use by some connection.
1868 ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
1869 const struct ip_conntrack *ignored_conntrack)
1870 @@ -606,7 +683,13 @@
1872 return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
1876 + * ip_ct_find_helper - Find application helper according to tuple
1877 + * @tuple: tuple for which helper needs to be found
1879 + * This function is used to determine if any registered conntrack helper
1880 + * is to be used for the given tuple.
1882 struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
1884 return LIST_FIND(&helpers, helper_cmp,
1885 @@ -691,42 +774,50 @@
1886 struct ip_conntrack_expect *, tuple);
1887 READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1889 - /* If master is not in hash table yet (ie. packet hasn't left
1890 - this machine yet), how can other end know about expected?
1891 - Hence these are not the droids you are looking for (if
1892 - master ct never got confirmed, we'd hold a reference to it
1893 - and weird things would happen to future packets). */
1894 - if (expected && !is_confirmed(expected->expectant))
1897 - /* Look up the conntrack helper for master connections only */
1899 - conntrack->helper = ip_ct_find_helper(&repl_tuple);
1901 - /* If the expectation is dying, then this is a loser. */
1903 - && expected->expectant->helper->timeout
1904 - && ! del_timer(&expected->timeout))
1908 - DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1909 - conntrack, expected);
1910 - /* Welcome, Mr. Bond. We've been expecting you... */
1911 - IP_NF_ASSERT(master_ct(conntrack));
1912 - __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1913 - conntrack->master = expected;
1914 - expected->sibling = conntrack;
1915 - LIST_DELETE(&ip_conntrack_expect_list, expected);
1916 - expected->expectant->expecting--;
1917 - nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1919 - atomic_inc(&ip_conntrack_count);
1920 + /* If master is not in hash table yet (ie. packet hasn't left
1921 + this machine yet), how can other end know about expected?
1922 + Hence these are not the droids you are looking for (if
1923 + master ct never got confirmed, we'd hold a reference to it
1924 + and weird things would happen to future packets). */
1925 + if (!is_confirmed(expected->expectant)) {
1927 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
1931 + /* Expectation is dying... */
1932 + if (expected->expectant->helper->timeout
1933 + && ! del_timer(&expected->timeout)) {
1937 + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1938 + conntrack, expected);
1939 + /* Welcome, Mr. Bond. We've been expecting you... */
1940 + IP_NF_ASSERT(master_ct(conntrack));
1941 + __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1942 + conntrack->master = expected;
1943 + expected->sibling = conntrack;
1944 + LIST_DELETE(&ip_conntrack_expect_list, expected);
1945 + expected->expectant->expecting--;
1946 + nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1948 + /* this is a braindead... --pablo */
1949 + atomic_inc(&ip_conntrack_count);
1950 + WRITE_UNLOCK(&ip_conntrack_lock);
1952 + if (expected->expectfn)
1953 + expected->expectfn(conntrack);
1957 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
1959 +end: atomic_inc(&ip_conntrack_count);
1960 WRITE_UNLOCK(&ip_conntrack_lock);
1962 - if (expected && expected->expectfn)
1963 - expected->expectfn(conntrack);
1964 - return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1965 +ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1968 /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
1969 @@ -794,6 +885,15 @@
1973 + /* Never happen */
1974 + if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
1975 + if (net_ratelimit()) {
1976 + printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
1977 + (*pskb)->nh.iph->protocol, hooknum);
1982 /* FIXME: Do this right please. --RR */
1983 (*pskb)->nfcache |= NFC_UNKNOWN;
1985 @@ -812,18 +912,10 @@
1989 - /* Previously seen (loopback)? Ignore. Do this before
1990 - fragment check. */
1991 + /* Previously seen (loopback or untracked)? Ignore. */
1995 - /* Gather fragments. */
1996 - if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
1997 - *pskb = ip_ct_gather_frags(*pskb);
2002 proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2004 /* It may be an icmp error... */
2005 @@ -900,6 +992,14 @@
2006 return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
2010 + * ip_conntrack_unexpect_related - Unexpect a related connection
2011 + * @expect: expecattin to be removed
2013 + * This function removes an existing expectation, that has not yet been
2014 + * confirmed (i.e. expectation was issued, but expected connection didn't
2017 inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
2019 WRITE_LOCK(&ip_conntrack_lock);
2020 @@ -917,7 +1017,20 @@
2021 WRITE_UNLOCK(&ip_conntrack_lock);
2024 -/* Add a related connection. */
2026 + * ip_conntrack_expect_related - Expect a related connection
2027 + * @related_to: master conntrack
2028 + * @expect: expectation with all values filled in
2030 + * This function is called by conntrack application helpers who
2031 + * have detected that the control (master) connection is just about
2032 + * to negotiate a related slave connection.
2034 + * Note: This function allocates it's own struct ip_conntrack_expect,
2035 + * copying the values from the 'expect' parameter. Thus, 'expect' can
2036 + * be allocated on the stack and does not need to be valid after this
2037 + * function returns.
2039 int ip_conntrack_expect_related(struct ip_conntrack *related_to,
2040 struct ip_conntrack_expect *expect)
2042 @@ -1047,7 +1160,15 @@
2046 -/* Change tuple in an existing expectation */
2048 + * ip_conntrack_change_expect - Change tuple in existing expectation
2049 + * @expect: expectation which is to be changed
2050 + * @newtuple: new tuple for expect
2052 + * This function is mostly called by NAT application helpers, who want to
2053 + * change an expectation issued by their respective conntrack application
2054 + * helper counterpart.
2056 int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
2057 struct ip_conntrack_tuple *newtuple)
2059 @@ -1088,8 +1209,15 @@
2063 -/* Alter reply tuple (maybe alter helper). If it's already taken,
2064 - return 0 and don't do alteration. */
2066 + * ip_conntrack_alter_reply - Alter reply tuple of conntrack
2067 + * @conntrack: conntrack whose reply tuple we want to alter
2068 + * @newreply: designated reply tuple for this conntrack
2070 + * This function alters the reply tuple of a conntrack to the given
2071 + * newreply tuple. If this newreply tuple is already taken, return 0
2072 + * and don't do alteration
2074 int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
2075 const struct ip_conntrack_tuple *newreply)
2077 @@ -1114,6 +1242,13 @@
2082 + * ip_conntrack_helper_register - Register a conntrack application helper
2083 + * @me: structure describing the helper
2085 + * This function is called by conntrack application helpers to register
2086 + * themselves with the conntrack core.
2088 int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
2090 WRITE_LOCK(&ip_conntrack_lock);
2091 @@ -1135,6 +1270,13 @@
2096 + * ip_conntrack_helper_unregister - Unregister a conntrack application helper
2097 + * @me: structure describing the helper
2099 + * This function is called by conntrack application helpers to unregister
2100 + * themselvers from the conntrack core.
2102 void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
2105 @@ -1153,7 +1295,14 @@
2109 -/* Refresh conntrack for this many jiffies. */
2111 + * ip_ct_refresh - Refresh conntrack timer for given conntrack
2112 + * @ct: conntrack which we want to refresh
2113 + * @extra_jiffies: number of jiffies to add
2115 + * This function is called by protocol helpers and application helpers in
2116 + * order to change the expiration timer of a conntrack entry.
2118 void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
2120 IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
2121 @@ -1172,7 +1321,16 @@
2122 WRITE_UNLOCK(&ip_conntrack_lock);
2125 -/* Returns new sk_buff, or NULL */
2128 + * ip_ct_gather_frags - Gather fragments of a particular skb
2129 + * @skb: pointer to sk_buff of fragmented IP packet
2131 + * This code is just a wrapper around the defragmentation code in the core IPv4
2132 + * stack. It also takes care of nonlinear skb's.
2134 + * Returns new sk_buff, or NULL
2137 ip_ct_gather_frags(struct sk_buff *skb)
2139 @@ -1256,6 +1414,16 @@
2144 + * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries
2145 + * @kill: callback function selecting which entries to delete
2146 + * @data: opaque data pointer, becomes 2nd argument for kill function
2148 + * This function can be used to selectively delete elements of the conntrack
2149 + * hashtable. The function iterates over the list of conntrack entries and
2150 + * calls the 'kill' function for every entry. If the return value is true,
2151 + * the connection is deleted (death_by_timeout).
2154 ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
2156 @@ -1422,6 +1590,18 @@
2158 /* For use by ipt_REJECT */
2159 ip_ct_attach = ip_conntrack_attach;
2161 + /* Set up fake conntrack:
2162 + - to never be deleted, not in any hashes */
2163 + atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
2164 + /* - and look it like as a confirmed connection */
2165 + set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
2166 + /* - and prepare the ctinfo field for REJECT & NAT. */
2167 + ip_conntrack_untracked.infos[IP_CT_NEW].master =
2168 + ip_conntrack_untracked.infos[IP_CT_RELATED].master =
2169 + ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master =
2170 + &ip_conntrack_untracked.ct_general;
2175 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig
2176 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 00:00:00.000000000 +0000
2177 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-03-05 09:55:06.000000000 +0000
2179 +/* Connection state tracking for netfilter. This is separated from,
2180 + but required by, the NAT layer; it can also be used by an iptables
2183 +/* (C) 1999-2001 Paul `Rusty' Russell
2184 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
2186 + * This program is free software; you can redistribute it and/or modify
2187 + * it under the terms of the GNU General Public License version 2 as
2188 + * published by the Free Software Foundation.
2190 + * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
2191 + * - new API and handling of conntrack/nat helpers
2192 + * - now capable of multiple expectations for one master
2193 + * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
2194 + * - add usage/reference counts to ip_conntrack_expect
2195 + * - export ip_conntrack[_expect]_{find_get,put} functions
2196 + * 05 Aug 2002: Harald Welte <laforge@gnumonks.org>
2197 + * - added DocBook-style comments for public API
2200 +#include <linux/config.h>
2201 +#include <linux/types.h>
2202 +#include <linux/icmp.h>
2203 +#include <linux/ip.h>
2204 +#include <linux/netfilter.h>
2205 +#include <linux/netfilter_ipv4.h>
2206 +#include <linux/module.h>
2207 +#include <linux/skbuff.h>
2208 +#include <linux/proc_fs.h>
2209 +#include <linux/vmalloc.h>
2210 +#include <net/checksum.h>
2211 +#include <linux/stddef.h>
2212 +#include <linux/sysctl.h>
2213 +#include <linux/slab.h>
2214 +#include <linux/random.h>
2215 +#include <linux/jhash.h>
2216 +/* For ERR_PTR(). Yeah, I know... --RR */
2217 +#include <linux/fs.h>
2219 +/* This rwlock protects the main hash table, protocol/helper/expected
2220 + registrations, conntrack timers*/
2221 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
2222 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
2224 +#include <linux/netfilter_ipv4/ip_conntrack.h>
2225 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
2226 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
2227 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
2228 +#include <linux/netfilter_ipv4/listhelp.h>
2230 +#define IP_CONNTRACK_VERSION "2.1"
2233 +#define DEBUGP printk
2235 +#define DEBUGP(format, args...)
2238 +DECLARE_RWLOCK(ip_conntrack_lock);
2239 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
2241 +void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
2242 +LIST_HEAD(ip_conntrack_expect_list);
2243 +LIST_HEAD(protocol_list);
2244 +static LIST_HEAD(helpers);
2245 +unsigned int ip_conntrack_htable_size = 0;
2246 +int ip_conntrack_max;
2247 +static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
2248 +struct list_head *ip_conntrack_hash;
2249 +static kmem_cache_t *ip_conntrack_cachep;
2251 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
2253 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
2254 + u_int8_t protocol)
2256 + return protocol == curr->proto;
2259 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
2261 + struct ip_conntrack_protocol *p;
2263 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2264 + p = LIST_FIND(&protocol_list, proto_cmpfn,
2265 + struct ip_conntrack_protocol *, protocol);
2267 + p = &ip_conntrack_generic_protocol;
2273 + * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number
2274 + * @protocol: protocol number
2276 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
2278 + struct ip_conntrack_protocol *p;
2280 + READ_LOCK(&ip_conntrack_lock);
2281 + p = __ip_ct_find_proto(protocol);
2282 + READ_UNLOCK(&ip_conntrack_lock);
2287 +ip_conntrack_put(struct ip_conntrack *ct)
2290 + IP_NF_ASSERT(ct->infos[0].master);
2291 + /* nf_conntrack_put wants to go via an info struct, so feed it
2293 + nf_conntrack_put(&ct->infos[0]);
2296 +static int ip_conntrack_hash_rnd_initted;
2297 +static unsigned int ip_conntrack_hash_rnd;
2300 + * hash_conntrack - Calculate the position of an entry in the connection
2302 + * @tuple: conntrack tuple which we want to calculate the hash position
2305 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
2308 + dump_tuple(tuple);
2310 + return (jhash_3words(tuple->src.ip,
2311 + (tuple->dst.ip ^ tuple->dst.protonum),
2312 + (tuple->src.u.all | (tuple->dst.u.all << 16)),
2313 + ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
2317 + * get_tuple - set all the fields of a tuple which is passed as parameter
2318 + * given a network buffer.
2319 + * @iph:pointer an IP header.
2320 + * @skb:network buffer for which we want to generate the tuple
2321 + * @dataoff: FIXME: Deprecated?
2322 + * @tuple: tuple which will be generate. Used as return parameter.
2323 + * @protocol: structure which contains pointer to protocol specific functions.
2325 + * Note: This function doesn't allocate space for the tuple passed as
2326 + * parameter. The function pkt_to_packet which set all the protocol specific
2327 + * fields of a given tuple.
2330 +get_tuple(const struct iphdr *iph,
2331 + const struct sk_buff *skb,
2332 + unsigned int dataoff,
2333 + struct ip_conntrack_tuple *tuple,
2334 + const struct ip_conntrack_protocol *protocol)
2336 + /* Never happen */
2337 + if (iph->frag_off & htons(IP_OFFSET)) {
2338 + printk("ip_conntrack_core: Frag of proto %u.\n",
2343 + tuple->src.ip = iph->saddr;
2344 + tuple->dst.ip = iph->daddr;
2345 + tuple->dst.protonum = iph->protocol;
2347 + return protocol->pkt_to_tuple(skb, dataoff, tuple);
2351 + * invert_tuple - Returns the inverse of a given tuple. It is used to
2352 + * calculate the tuple which represents the other sense of the flow
2353 + * of a connection.
2354 + * @inverse: the inverted tuple. Use as return value.
2355 + * @orig: the original tuple which will be inverted.
2356 + * @protocol: a pointer to the protocol structure which contains all the
2357 + * specifical functions available for this tuple.
2360 +invert_tuple(struct ip_conntrack_tuple *inverse,
2361 + const struct ip_conntrack_tuple *orig,
2362 + const struct ip_conntrack_protocol *protocol)
2364 + inverse->src.ip = orig->dst.ip;
2365 + inverse->dst.ip = orig->src.ip;
2366 + inverse->dst.protonum = orig->dst.protonum;
2368 + return protocol->invert_tuple(inverse, orig);
2372 +/* ip_conntrack_expect helper functions */
2375 + * expect_cmp - compare a tuple with a expectation depending on a mask
2376 + * @i: pointer to an expectation.
2377 + * @tuple: tuple which will be compared with the expectation tuple.
2379 + * Actually the tuple field of an expectation is compared with a tuple
2380 + * This function is used by LIST_FIND to find a expectation which match a te
2383 +static inline int expect_cmp(const struct ip_conntrack_expect *i,
2384 + const struct ip_conntrack_tuple *tuple)
2386 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2387 + return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
2391 + * destroy_expect - Release all the resources allocated by an expectation.
2392 + * @exp: pointer to the expectation which we want to release.
2395 +destroy_expect(struct ip_conntrack_expect *exp)
2397 + DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
2398 + IP_NF_ASSERT(atomic_read(&exp->use));
2399 + IP_NF_ASSERT(!timer_pending(&exp->timeout));
2405 + * ip_conntrack_expect_put - it decrements the counter of use related
2406 + * associated to an expectation and it calls destroy_expect.
2407 + * @exp: pointer to the expectation which we want to release.
2409 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
2411 + IP_NF_ASSERT(exp);
2413 + if (atomic_dec_and_test(&exp->use)) {
2414 + /* usage count dropped to zero */
2415 + destroy_expect(exp);
2419 +static inline struct ip_conntrack_expect *
2420 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
2422 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2423 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2424 + return LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
2425 + struct ip_conntrack_expect *, tuple);
2429 + * ip_conntrack_find_get - find conntrack according to tuple
2430 + * @tuple: conntrack tuple for which we search conntrack
2431 + * @ignored_conntrack: ignore this conntrack during search
2433 + * This function increments the reference count of the found
2434 + * conntrack (if any).
2436 +struct ip_conntrack_expect *
2437 +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
2439 + struct ip_conntrack_expect *exp;
2441 + READ_LOCK(&ip_conntrack_lock);
2442 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
2443 + exp = __ip_ct_expect_find(tuple);
2445 + atomic_inc(&exp->use);
2446 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2447 + READ_UNLOCK(&ip_conntrack_lock);
2452 +/* remove one specific expectation from all lists and drop refcount,
2453 + * does _NOT_ delete the timer. */
2454 +static void __unexpect_related(struct ip_conntrack_expect *expect)
2456 + DEBUGP("unexpect_related(%p)\n", expect);
2457 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2459 + /* we're not allowed to unexpect a confirmed expectation! */
2460 + IP_NF_ASSERT(!expect->sibling);
2462 + /* delete from global and local lists */
2463 + list_del(&expect->list);
2464 + list_del(&expect->expected_list);
2466 + /* decrement expect-count of master conntrack */
2467 + if (expect->expectant)
2468 + expect->expectant->expecting--;
2470 + ip_conntrack_expect_put(expect);
2473 +/* remove one specific expecatation from all lists, drop refcount
2474 + * and expire timer.
2475 + * This function can _NOT_ be called for confirmed expects! */
2476 +static void unexpect_related(struct ip_conntrack_expect *expect)
2478 + IP_NF_ASSERT(expect->expectant);
2479 + IP_NF_ASSERT(expect->expectant->helper);
2480 + /* if we are supposed to have a timer, but we can't delete
2481 + * it: race condition. __unexpect_related will
2482 + * be calledd by timeout function */
2483 + if (expect->expectant->helper->timeout
2484 + && !del_timer(&expect->timeout))
2487 + __unexpect_related(expect);
2490 +/* delete all unconfirmed expectations for this conntrack */
2491 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
2493 + struct list_head *exp_entry, *next;
2494 + struct ip_conntrack_expect *exp;
2496 + DEBUGP("remove_expectations(%p)\n", ct);
2498 + list_for_each_safe(exp_entry, next, &ct->sibling_list) {
2499 + exp = list_entry(exp_entry, struct ip_conntrack_expect,
2502 + /* we skip established expectations, as we want to delete
2503 + * the un-established ones only */
2504 + if (exp->sibling) {
2505 + DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
2506 + if (drop_refcount) {
2507 + /* Indicate that this expectations parent is dead */
2508 + ip_conntrack_put(exp->expectant);
2509 + exp->expectant = NULL;
2514 + IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
2515 + IP_NF_ASSERT(exp->expectant == ct);
2517 + /* delete expectation from global and private lists */
2518 + unexpect_related(exp);
2523 +clean_from_lists(struct ip_conntrack *ct)
2525 + unsigned int ho, hr;
2527 + DEBUGP("clean_from_lists(%p)\n", ct);
2528 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2530 + ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
2531 + hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
2532 + LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
2533 + LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
2535 + /* Destroy all un-established, pending expectations */
2536 + remove_expectations(ct, 1);
2540 +destroy_conntrack(struct nf_conntrack *nfct)
2542 + struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
2543 + struct ip_conntrack_protocol *proto;
2545 + DEBUGP("destroy_conntrack(%p)\n", ct);
2546 + IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
2547 + IP_NF_ASSERT(!timer_pending(&ct->timeout));
2549 + /* To make sure we don't get any weird locking issues here:
2550 + * destroy_conntrack() MUST NOT be called with a write lock
2551 + * to ip_conntrack_lock!!! -HW */
2552 + proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
2553 + if (proto && proto->destroy)
2554 + proto->destroy(ct);
2556 + if (ip_conntrack_destroyed)
2557 + ip_conntrack_destroyed(ct);
2559 + WRITE_LOCK(&ip_conntrack_lock);
2560 + /* Delete us from our own list to prevent corruption later */
2561 + list_del(&ct->sibling_list);
2563 + /* Delete our master expectation */
2565 + if (ct->master->expectant) {
2566 + /* can't call __unexpect_related here,
2567 + * since it would screw up expect_list */
2568 + list_del(&ct->master->expected_list);
2569 + master = ct->master->expectant;
2571 + kfree(ct->master);
2573 + WRITE_UNLOCK(&ip_conntrack_lock);
2576 + ip_conntrack_put(master);
2578 + DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
2579 + kmem_cache_free(ip_conntrack_cachep, ct);
2580 + atomic_dec(&ip_conntrack_count);
2583 +static void death_by_timeout(unsigned long ul_conntrack)
2585 + struct ip_conntrack *ct = (void *)ul_conntrack;
2587 + WRITE_LOCK(&ip_conntrack_lock);
2588 + clean_from_lists(ct);
2589 + WRITE_UNLOCK(&ip_conntrack_lock);
2590 + ip_conntrack_put(ct);
2594 +conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
2595 + const struct ip_conntrack_tuple *tuple,
2596 + const struct ip_conntrack *ignored_conntrack)
2598 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2599 + return i->ctrack != ignored_conntrack
2600 + && ip_ct_tuple_equal(tuple, &i->tuple);
2603 +static struct ip_conntrack_tuple_hash *
2604 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
2605 + const struct ip_conntrack *ignored_conntrack)
2607 + struct ip_conntrack_tuple_hash *h;
2608 + unsigned int hash = hash_conntrack(tuple);
2610 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2611 + h = LIST_FIND(&ip_conntrack_hash[hash],
2612 + conntrack_tuple_cmp,
2613 + struct ip_conntrack_tuple_hash *,
2614 + tuple, ignored_conntrack);
2619 + * ip_conntrack_find_get - find conntrack according to tuple
2620 + * @tuple: conntrack tuple for which we search conntrack
2621 + * @ignored_conntrack: ignore this conntrack during search
2623 + * This function increments the reference count of the found
2624 + * conntrack (if any).
2626 +struct ip_conntrack_tuple_hash *
2627 +ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
2628 + const struct ip_conntrack *ignored_conntrack)
2630 + struct ip_conntrack_tuple_hash *h;
2632 + READ_LOCK(&ip_conntrack_lock);
2633 + h = __ip_conntrack_find(tuple, ignored_conntrack);
2635 + atomic_inc(&h->ctrack->ct_general.use);
2636 + READ_UNLOCK(&ip_conntrack_lock);
2641 +static inline struct ip_conntrack *
2642 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
2644 + struct ip_conntrack *ct
2645 + = (struct ip_conntrack *)nfct->master;
2647 + /* ctinfo is the index of the nfct inside the conntrack */
2648 + *ctinfo = nfct - ct->infos;
2649 + IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
2654 + * ip_conntrack_get - Return conntrack and conntrack_info for given skb
2655 + * @skb: skb for which we want to find conntrack and conntrack_info
2656 + * @ctinfo: pointer to ctinfo, used as return value
2658 + * This function resolves the respective conntrack and conntrack_info
2659 + * structures for the connection this packet (skb) is part of.
2661 +struct ip_conntrack *
2662 +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
2665 + return __ip_conntrack_get(skb->nfct, ctinfo);
2669 +/* Confirm a connection given skb->nfct; places it in hash table */
2671 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
2673 + unsigned int hash, repl_hash;
2674 + struct ip_conntrack *ct;
2675 + enum ip_conntrack_info ctinfo;
2677 + ct = __ip_conntrack_get(nfct, &ctinfo);
2679 + /* ipt_REJECT uses ip_conntrack_attach to attach related
2680 + ICMP/TCP RST packets in other direction. Actual packet
2681 + which created connection will be IP_CT_NEW or for an
2682 + expected connection, IP_CT_RELATED. */
2683 + if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
2686 + hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
2687 + repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
2689 + /* We're not in hash table, and we refuse to set up related
2690 + connections for unconfirmed conns. But packet copies and
2691 + REJECT will give spurious warnings here. */
2692 + /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
2694 + /* No external references means noone else could have
2696 + IP_NF_ASSERT(!is_confirmed(ct));
2697 + DEBUGP("Confirming conntrack %p\n", ct);
2699 + WRITE_LOCK(&ip_conntrack_lock);
2700 + /* See if there's one in the list already, including reverse:
2701 + NAT could have grabbed it without realizing, since we're
2702 + not in the hash. If there is, we lost race. */
2703 + if (!LIST_FIND(&ip_conntrack_hash[hash],
2704 + conntrack_tuple_cmp,
2705 + struct ip_conntrack_tuple_hash *,
2706 + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
2707 + && !LIST_FIND(&ip_conntrack_hash[repl_hash],
2708 + conntrack_tuple_cmp,
2709 + struct ip_conntrack_tuple_hash *,
2710 + &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
2711 + list_prepend(&ip_conntrack_hash[hash],
2712 + &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
2713 + list_prepend(&ip_conntrack_hash[repl_hash],
2714 + &ct->tuplehash[IP_CT_DIR_REPLY]);
2715 + /* Timer relative to confirmation time, not original
2716 + setting time, otherwise we'd get timer wrap in
2717 + weird delay cases. */
2718 + ct->timeout.expires += jiffies;
2719 + add_timer(&ct->timeout);
2720 + atomic_inc(&ct->ct_general.use);
2721 + set_bit(IPS_CONFIRMED_BIT, &ct->status);
2722 + WRITE_UNLOCK(&ip_conntrack_lock);
2726 + WRITE_UNLOCK(&ip_conntrack_lock);
2731 + * ip_conntrack_tuple_taken - Find out if tuple is already in use
2732 + * @tuple: tuple to be used for this test
2733 + * @ignored_conntrack: conntrack which is excluded from result
2735 + * This function is called by the NAT code in order to find out if
2736 + * a particular tuple is already in use by some connection.
2739 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
2740 + const struct ip_conntrack *ignored_conntrack)
2742 + struct ip_conntrack_tuple_hash *h;
2744 + READ_LOCK(&ip_conntrack_lock);
2745 + h = __ip_conntrack_find(tuple, ignored_conntrack);
2746 + READ_UNLOCK(&ip_conntrack_lock);
2751 +/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
2752 +struct ip_conntrack *
2753 +icmp_error_track(struct sk_buff *skb,
2754 + enum ip_conntrack_info *ctinfo,
2755 + unsigned int hooknum)
2757 + struct ip_conntrack_tuple innertuple, origtuple;
2759 + struct icmphdr icmp;
2762 + struct ip_conntrack_protocol *innerproto;
2763 + struct ip_conntrack_tuple_hash *h;
2766 + IP_NF_ASSERT(skb->nfct == NULL);
2768 + /* Not enough header? */
2769 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
2772 + if (inside.icmp.type != ICMP_DEST_UNREACH
2773 + && inside.icmp.type != ICMP_SOURCE_QUENCH
2774 + && inside.icmp.type != ICMP_TIME_EXCEEDED
2775 + && inside.icmp.type != ICMP_PARAMETERPROB
2776 + && inside.icmp.type != ICMP_REDIRECT)
2779 + /* Ignore ICMP's containing fragments (shouldn't happen) */
2780 + if (inside.ip.frag_off & htons(IP_OFFSET)) {
2781 + DEBUGP("icmp_error_track: fragment of proto %u\n",
2782 + inside.ip.protocol);
2786 + innerproto = ip_ct_find_proto(inside.ip.protocol);
2787 + dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
2788 + /* Are they talking about one of our connections? */
2789 + if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
2790 + DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
2794 + /* Ordinarily, we'd expect the inverted tupleproto, but it's
2795 + been preserved inside the ICMP. */
2796 + if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
2797 + DEBUGP("icmp_error_track: Can't invert tuple\n");
2801 + *ctinfo = IP_CT_RELATED;
2803 + h = ip_conntrack_find_get(&innertuple, NULL);
2805 + /* Locally generated ICMPs will match inverted if they
2806 + haven't been SNAT'ed yet */
2807 + /* FIXME: NAT code has to handle half-done double NAT --RR */
2808 + if (hooknum == NF_IP_LOCAL_OUT)
2809 + h = ip_conntrack_find_get(&origtuple, NULL);
2812 + DEBUGP("icmp_error_track: no match\n");
2815 + /* Reverse direction from that found */
2816 + if (DIRECTION(h) != IP_CT_DIR_REPLY)
2817 + *ctinfo += IP_CT_IS_REPLY;
2819 + if (DIRECTION(h) == IP_CT_DIR_REPLY)
2820 + *ctinfo += IP_CT_IS_REPLY;
2823 + /* Update skb to refer to this connection */
2824 + skb->nfct = &h->ctrack->infos[*ctinfo];
2828 +/* There's a small race here where we may free a just-assured
2829 + connection. Too bad: we're in trouble anyway. */
2830 +static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
2832 + return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
2835 +static int early_drop(struct list_head *chain)
2837 + /* Traverse backwards: gives us oldest, which is roughly LRU */
2838 + struct ip_conntrack_tuple_hash *h;
2841 + READ_LOCK(&ip_conntrack_lock);
2842 + h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
2844 + atomic_inc(&h->ctrack->ct_general.use);
2845 + READ_UNLOCK(&ip_conntrack_lock);
2850 + if (del_timer(&h->ctrack->timeout)) {
2851 + death_by_timeout((unsigned long)h->ctrack);
2854 + ip_conntrack_put(h->ctrack);
2858 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
2859 + const struct ip_conntrack_tuple *rtuple)
2861 + return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
2864 + * ip_ct_find_helper - Find application helper according to tuple
2865 + * @tuple: tuple for which helper needs to be found
2867 + * This function is used to determine if any registered conntrack helper
2868 + * is to be used for the given tuple.
2870 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
2872 + return LIST_FIND(&helpers, helper_cmp,
2873 + struct ip_conntrack_helper *,
2877 +/* Allocate a new conntrack: we return -ENOMEM if classification
2878 + failed due to stress. Otherwise it really is unclassifiable. */
2879 +static struct ip_conntrack_tuple_hash *
2880 +init_conntrack(const struct ip_conntrack_tuple *tuple,
2881 + struct ip_conntrack_protocol *protocol,
2882 + struct sk_buff *skb)
2884 + struct ip_conntrack *conntrack;
2885 + struct ip_conntrack_tuple repl_tuple;
2887 + struct ip_conntrack_expect *expected;
2889 + static unsigned int drop_next;
2891 + if (!ip_conntrack_hash_rnd_initted) {
2892 + get_random_bytes(&ip_conntrack_hash_rnd, 4);
2893 + ip_conntrack_hash_rnd_initted = 1;
2896 + hash = hash_conntrack(tuple);
2898 + if (ip_conntrack_max &&
2899 + atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
2900 + /* Try dropping from random chain, or else from the
2901 + chain about to put into (in case they're trying to
2902 + bomb one hash chain). */
2903 + unsigned int next = (drop_next++)%ip_conntrack_htable_size;
2905 + if (!early_drop(&ip_conntrack_hash[next])
2906 + && !early_drop(&ip_conntrack_hash[hash])) {
2907 + if (net_ratelimit())
2908 + printk(KERN_WARNING
2909 + "ip_conntrack: table full, dropping"
2911 + return ERR_PTR(-ENOMEM);
2915 + if (!invert_tuple(&repl_tuple, tuple, protocol)) {
2916 + DEBUGP("Can't invert tuple.\n");
2920 + conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
2922 + DEBUGP("Can't allocate conntrack.\n");
2923 + return ERR_PTR(-ENOMEM);
2926 + memset(conntrack, 0, sizeof(*conntrack));
2927 + atomic_set(&conntrack->ct_general.use, 1);
2928 + conntrack->ct_general.destroy = destroy_conntrack;
2929 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
2930 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
2931 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
2932 + conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
2933 + for (i=0; i < IP_CT_NUMBER; i++)
2934 + conntrack->infos[i].master = &conntrack->ct_general;
2936 + if (!protocol->new(conntrack, skb)) {
2937 + kmem_cache_free(ip_conntrack_cachep, conntrack);
2940 + /* Don't set timer yet: wait for confirmation */
2941 + init_timer(&conntrack->timeout);
2942 + conntrack->timeout.data = (unsigned long)conntrack;
2943 + conntrack->timeout.function = death_by_timeout;
2945 + INIT_LIST_HEAD(&conntrack->sibling_list);
2947 + WRITE_LOCK(&ip_conntrack_lock);
2948 + /* Need finding and deleting of expected ONLY if we win race */
2949 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
2950 + expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
2951 + struct ip_conntrack_expect *, tuple);
2952 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2955 + /* If master is not in hash table yet (ie. packet hasn't left
2956 + this machine yet), how can other end know about expected?
2957 + Hence these are not the droids you are looking for (if
2958 + master ct never got confirmed, we'd hold a reference to it
2959 + and weird things would happen to future packets). */
2960 + if (!is_confirmed(expected->expectant)) {
2962 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
2966 + /* Expectation is dying... */
2967 + if (expected->expectant->helper->timeout
2968 + && ! del_timer(&expected->timeout)) {
2972 + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
2973 + conntrack, expected);
2974 + /* Welcome, Mr. Bond. We've been expecting you... */
2975 + IP_NF_ASSERT(master_ct(conntrack));
2976 + __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
2977 + conntrack->master = expected;
2978 + expected->sibling = conntrack;
2979 + LIST_DELETE(&ip_conntrack_expect_list, expected);
2980 + expected->expectant->expecting--;
2981 + nf_conntrack_get(&master_ct(conntrack)->infos[0]);
2983 + /* this is a braindead... --pablo */
2984 + atomic_inc(&ip_conntrack_count);
2985 + WRITE_UNLOCK(&ip_conntrack_lock);
2987 + if (expected->expectfn)
2988 + expected->expectfn(conntrack);
2992 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
2994 +end: atomic_inc(&ip_conntrack_count);
2995 + WRITE_UNLOCK(&ip_conntrack_lock);
2997 +ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
3000 +/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
3001 +static inline struct ip_conntrack *
3002 +resolve_normal_ct(struct sk_buff *skb,
3003 + struct ip_conntrack_protocol *proto,
3005 + unsigned int hooknum,
3006 + enum ip_conntrack_info *ctinfo)
3008 + struct ip_conntrack_tuple tuple;
3009 + struct ip_conntrack_tuple_hash *h;
3011 + IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
3013 + if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
3016 + /* look for tuple match */
3017 + h = ip_conntrack_find_get(&tuple, NULL);
3019 + h = init_conntrack(&tuple, proto, skb);
3026 + /* It exists; we have (non-exclusive) reference. */
3027 + if (DIRECTION(h) == IP_CT_DIR_REPLY) {
3028 + *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
3029 + /* Please set reply bit if this packet OK */
3032 + /* Once we've had two way comms, always ESTABLISHED. */
3033 + if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
3034 + DEBUGP("ip_conntrack_in: normal packet for %p\n",
3036 + *ctinfo = IP_CT_ESTABLISHED;
3037 + } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
3038 + DEBUGP("ip_conntrack_in: related packet for %p\n",
3040 + *ctinfo = IP_CT_RELATED;
3042 + DEBUGP("ip_conntrack_in: new packet for %p\n",
3044 + *ctinfo = IP_CT_NEW;
3048 + skb->nfct = &h->ctrack->infos[*ctinfo];
3052 +/* Netfilter hook itself. */
3053 +unsigned int ip_conntrack_in(unsigned int hooknum,
3054 + struct sk_buff **pskb,
3055 + const struct net_device *in,
3056 + const struct net_device *out,
3057 + int (*okfn)(struct sk_buff *))
3059 + struct ip_conntrack *ct;
3060 + enum ip_conntrack_info ctinfo;
3061 + struct ip_conntrack_protocol *proto;
3065 + /* FIXME: Do this right please. --RR */
3066 + (*pskb)->nfcache |= NFC_UNKNOWN;
3068 +/* Doesn't cover locally-generated broadcast, so not worth it. */
3070 + /* Ignore broadcast: no `connection'. */
3071 + if ((*pskb)->pkt_type == PACKET_BROADCAST) {
3072 + printk("Broadcast packet!\n");
3074 + } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
3075 + == htonl(0x000000FF)) {
3076 + printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
3077 + NIPQUAD((*pskb)->nh.iph->saddr),
3078 + NIPQUAD((*pskb)->nh.iph->daddr),
3079 + (*pskb)->sk, (*pskb)->pkt_type);
3083 + /* Previously seen (loopback)? Ignore. Do this before
3084 + fragment check. */
3085 + if ((*pskb)->nfct)
3088 + /* Gather fragments. */
3089 + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
3090 + *pskb = ip_ct_gather_frags(*pskb);
3095 + proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
3097 + /* It may be an icmp error... */
3098 + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
3099 + && icmp_error_track(*pskb, &ctinfo, hooknum))
3102 + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
3103 + /* Not valid part of a connection */
3107 + /* Too stressed to deal. */
3110 + IP_NF_ASSERT((*pskb)->nfct);
3112 + ret = proto->packet(ct, *pskb, ctinfo);
3115 + nf_conntrack_put((*pskb)->nfct);
3116 + (*pskb)->nfct = NULL;
3120 + if (ret != NF_DROP && ct->helper) {
3121 + ret = ct->helper->help(*pskb, ct, ctinfo);
3124 + nf_conntrack_put((*pskb)->nfct);
3125 + (*pskb)->nfct = NULL;
3130 + set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
3135 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
3136 + const struct ip_conntrack_tuple *orig)
3138 + return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
3141 +static inline int resent_expect(const struct ip_conntrack_expect *i,
3142 + const struct ip_conntrack_tuple *tuple,
3143 + const struct ip_conntrack_tuple *mask)
3145 + DEBUGP("resent_expect\n");
3146 + DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
3147 + DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
3148 + DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
3149 + return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
3150 + || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
3151 + && ip_ct_tuple_equal(&i->mask, mask));
3154 +/* Would two expected things clash? */
3155 +static inline int expect_clash(const struct ip_conntrack_expect *i,
3156 + const struct ip_conntrack_tuple *tuple,
3157 + const struct ip_conntrack_tuple *mask)
3159 + /* Part covered by intersection of masks must be unequal,
3160 + otherwise they clash */
3161 + struct ip_conntrack_tuple intersect_mask
3162 + = { { i->mask.src.ip & mask->src.ip,
3163 + { i->mask.src.u.all & mask->src.u.all } },
3164 + { i->mask.dst.ip & mask->dst.ip,
3165 + { i->mask.dst.u.all & mask->dst.u.all },
3166 + i->mask.dst.protonum & mask->dst.protonum } };
3168 + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
3172 + * ip_conntrack_unexpect_related - Unexpect a related connection
3173 + * @expect: expecattin to be removed
3175 + * This function removes an existing expectation, that has not yet been
3176 + * confirmed (i.e. expectation was issued, but expected connection didn't
3179 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
3181 + WRITE_LOCK(&ip_conntrack_lock);
3182 + unexpect_related(expect);
3183 + WRITE_UNLOCK(&ip_conntrack_lock);
3186 +static void expectation_timed_out(unsigned long ul_expect)
3188 + struct ip_conntrack_expect *expect = (void *) ul_expect;
3190 + DEBUGP("expectation %p timed out\n", expect);
3191 + WRITE_LOCK(&ip_conntrack_lock);
3192 + __unexpect_related(expect);
3193 + WRITE_UNLOCK(&ip_conntrack_lock);
3197 + * ip_conntrack_expect_related - Expect a related connection
3198 + * @related_to: master conntrack
3199 + * @expect: expectation with all values filled in
3201 + * This function is called by conntrack application helpers who
3202 + * have detected that the control (master) connection is just about
3203 + * to negotiate a related slave connection.
3205 + * Note: This function allocates it's own struct ip_conntrack_expect,
3206 + * copying the values from the 'expect' parameter. Thus, 'expect' can
3207 + * be allocated on the stack and does not need to be valid after this
3208 + * function returns.
3210 +int ip_conntrack_expect_related(struct ip_conntrack *related_to,
3211 + struct ip_conntrack_expect *expect)
3213 + struct ip_conntrack_expect *old, *new;
3216 + WRITE_LOCK(&ip_conntrack_lock);
3217 + /* Because of the write lock, no reader can walk the lists,
3218 + * so there is no need to use the tuple lock too */
3220 + DEBUGP("ip_conntrack_expect_related %p\n", related_to);
3221 + DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
3222 + DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
3224 + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
3225 + struct ip_conntrack_expect *, &expect->tuple,
3228 + /* Helper private data may contain offsets but no pointers
3229 + pointing into the payload - otherwise we should have to copy
3230 + the data filled out by the helper over the old one */
3231 + DEBUGP("expect_related: resent packet\n");
3232 + if (related_to->helper->timeout) {
3233 + if (!del_timer(&old->timeout)) {
3234 + /* expectation is dying. Fall through */
3237 + old->timeout.expires = jiffies +
3238 + related_to->helper->timeout * HZ;
3239 + add_timer(&old->timeout);
3244 + WRITE_UNLOCK(&ip_conntrack_lock);
3247 + } else if (related_to->helper->max_expected &&
3248 + related_to->expecting >= related_to->helper->max_expected) {
3249 + struct list_head *cur_item;
3251 + if (!(related_to->helper->flags &
3252 + IP_CT_HELPER_F_REUSE_EXPECT)) {
3253 + WRITE_UNLOCK(&ip_conntrack_lock);
3254 + if (net_ratelimit())
3255 + printk(KERN_WARNING
3256 + "ip_conntrack: max number of expected "
3257 + "connections %i of %s reached for "
3258 + "%u.%u.%u.%u->%u.%u.%u.%u\n",
3259 + related_to->helper->max_expected,
3260 + related_to->helper->name,
3261 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
3262 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
3265 + DEBUGP("ip_conntrack: max number of expected "
3266 + "connections %i of %s reached for "
3267 + "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
3268 + related_to->helper->max_expected,
3269 + related_to->helper->name,
3270 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
3271 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
3273 + /* choose the the oldest expectation to evict */
3274 + list_for_each(cur_item, &related_to->sibling_list) {
3275 + struct ip_conntrack_expect *cur;
3277 + cur = list_entry(cur_item,
3278 + struct ip_conntrack_expect,
3280 + if (cur->sibling == NULL) {
3286 + /* (!old) cannot happen, since related_to->expecting is the
3287 + * number of unconfirmed expects */
3288 + IP_NF_ASSERT(old);
3290 + /* newnat14 does not reuse the real allocated memory
3291 + * structures but rather unexpects the old and
3292 + * allocates a new. unexpect_related will decrement
3293 + * related_to->expecting.
3295 + unexpect_related(old);
3297 + } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
3298 + struct ip_conntrack_expect *, &expect->tuple,
3300 + WRITE_UNLOCK(&ip_conntrack_lock);
3301 + DEBUGP("expect_related: busy!\n");
3305 + new = (struct ip_conntrack_expect *)
3306 + kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
3308 + WRITE_UNLOCK(&ip_conntrack_lock);
3309 + DEBUGP("expect_relaed: OOM allocating expect\n");
3313 + DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
3314 + memcpy(new, expect, sizeof(*expect));
3315 + new->expectant = related_to;
3316 + new->sibling = NULL;
3317 + atomic_set(&new->use, 1);
3319 + /* add to expected list for this connection */
3320 + list_add(&new->expected_list, &related_to->sibling_list);
3321 + /* add to global list of expectations */
3322 + list_prepend(&ip_conntrack_expect_list, &new->list);
3323 + /* add and start timer if required */
3324 + if (related_to->helper->timeout) {
3325 + init_timer(&new->timeout);
3326 + new->timeout.data = (unsigned long)new;
3327 + new->timeout.function = expectation_timed_out;
3328 + new->timeout.expires = jiffies +
3329 + related_to->helper->timeout * HZ;
3330 + add_timer(&new->timeout);
3332 + related_to->expecting++;
3334 + WRITE_UNLOCK(&ip_conntrack_lock);
3340 + * ip_conntrack_change_expect - Change tuple in existing expectation
3341 + * @expect: expectation which is to be changed
3342 + * @newtuple: new tuple for expect
3344 + * This function is mostly called by NAT application helpers, who want to
3345 + * change an expectation issued by their respective conntrack application
3346 + * helper counterpart.
3348 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
3349 + struct ip_conntrack_tuple *newtuple)
3353 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3354 + WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
3356 + DEBUGP("change_expect:\n");
3357 + DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
3358 + DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
3359 + DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
3360 + if (expect->ct_tuple.dst.protonum == 0) {
3361 + /* Never seen before */
3362 + DEBUGP("change expect: never seen before\n");
3363 + if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
3364 + && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
3365 + struct ip_conntrack_expect *, newtuple, &expect->mask)) {
3366 + /* Force NAT to find an unused tuple */
3369 + memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
3370 + memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
3374 + /* Resent packet */
3375 + DEBUGP("change expect: resent packet\n");
3376 + if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
3379 + /* Force NAT to choose again the same port */
3383 + WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
3389 + * ip_conntrack_alter_reply - Alter reply tuple of conntrack
3390 + * @conntrack: conntrack whose reply tuple we want to alter
3391 + * @newreply: designated reply tuple for this conntrack
3393 + * This function alters the reply tuple of a conntrack to the given
3394 + * newreply tuple. If this newreply tuple is already taken, return 0
3395 + * and don't do alteration
3397 +int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
3398 + const struct ip_conntrack_tuple *newreply)
3400 + WRITE_LOCK(&ip_conntrack_lock);
3401 + if (__ip_conntrack_find(newreply, conntrack)) {
3402 + WRITE_UNLOCK(&ip_conntrack_lock);
3405 + /* Should be unconfirmed, so not in hash table yet */
3406 + IP_NF_ASSERT(!is_confirmed(conntrack));
3408 + DEBUGP("Altering reply tuple of %p to ", conntrack);
3409 + DUMP_TUPLE(newreply);
3411 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
3412 + if (!conntrack->master)
3413 + conntrack->helper = LIST_FIND(&helpers, helper_cmp,
3414 + struct ip_conntrack_helper *,
3416 + WRITE_UNLOCK(&ip_conntrack_lock);
3422 + * ip_conntrack_helper_register - Register a conntrack application helper
3423 + * @me: structure describing the helper
3425 + * This function is called by conntrack application helpers to register
3426 + * themselves with the conntrack core.
3428 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
3430 + WRITE_LOCK(&ip_conntrack_lock);
3431 + list_prepend(&helpers, me);
3432 + WRITE_UNLOCK(&ip_conntrack_lock);
3437 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
3438 + const struct ip_conntrack_helper *me)
3440 + if (i->ctrack->helper == me) {
3441 + /* Get rid of any expected. */
3442 + remove_expectations(i->ctrack, 0);
3443 + /* And *then* set helper to NULL */
3444 + i->ctrack->helper = NULL;
3450 + * ip_conntrack_helper_unregister - Unregister a conntrack application helper
3451 + * @me: structure describing the helper
3453 + * This function is called by conntrack application helpers to unregister
3454 + * themselvers from the conntrack core.
3456 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
3460 + /* Need write lock here, to delete helper. */
3461 + WRITE_LOCK(&ip_conntrack_lock);
3462 + LIST_DELETE(&helpers, me);
3464 + /* Get rid of expecteds, set helpers to NULL. */
3465 + for (i = 0; i < ip_conntrack_htable_size; i++)
3466 + LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
3467 + struct ip_conntrack_tuple_hash *, me);
3468 + WRITE_UNLOCK(&ip_conntrack_lock);
3470 + /* Someone could be still looking at the helper in a bh. */
3471 + synchronize_net();
3475 + * ip_ct_refresh - Refresh conntrack timer for given conntrack
3476 + * @ct: conntrack which we want to refresh
3477 + * @extra_jiffies: number of jiffies to add
3479 + * This function is called by protocol helpers and application helpers in
3480 + * order to change the expiration timer of a conntrack entry.
3482 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
3484 + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
3486 + WRITE_LOCK(&ip_conntrack_lock);
3487 + /* If not in hash table, timer will not be active yet */
3488 + if (!is_confirmed(ct))
3489 + ct->timeout.expires = extra_jiffies;
3491 + /* Need del_timer for race avoidance (may already be dying). */
3492 + if (del_timer(&ct->timeout)) {
3493 + ct->timeout.expires = jiffies + extra_jiffies;
3494 + add_timer(&ct->timeout);
3497 + WRITE_UNLOCK(&ip_conntrack_lock);
3502 + * ip_ct_gather_frags - Gather fragments of a particular skb
3503 + * @skb: pointer to sk_buff of fragmented IP packet
3505 + * This code is just a wrapper around the defragmentation code in the core IPv4
3506 + * stack. It also takes care of nonlinear skb's.
3508 + * Returns new sk_buff, or NULL
3511 +ip_ct_gather_frags(struct sk_buff *skb)
3513 + struct sock *sk = skb->sk;
3514 +#ifdef CONFIG_NETFILTER_DEBUG
3515 + unsigned int olddebug = skb->nf_debug;
3522 + local_bh_disable();
3523 + skb = ip_defrag(skb);
3524 + local_bh_enable();
3533 + skb_set_owner_w(skb, sk);
3537 + ip_send_check(skb->nh.iph);
3538 + skb->nfcache |= NFC_ALTERED;
3539 +#ifdef CONFIG_NETFILTER_DEBUG
3540 + /* Packet path as if nothing had happened. */
3541 + skb->nf_debug = olddebug;
3546 +/* Used by ipt_REJECT. */
3547 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
3549 + struct ip_conntrack *ct;
3550 + enum ip_conntrack_info ctinfo;
3552 + ct = __ip_conntrack_get(nfct, &ctinfo);
3554 + /* This ICMP is in reverse direction to the packet which
3556 + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
3557 + ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
3559 + ctinfo = IP_CT_RELATED;
3561 + /* Attach new skbuff, and increment count */
3562 + nskb->nfct = &ct->infos[ctinfo];
3563 + atomic_inc(&ct->ct_general.use);
3567 +do_kill(const struct ip_conntrack_tuple_hash *i,
3568 + int (*kill)(const struct ip_conntrack *i, void *data),
3571 + return kill(i->ctrack, data);
3574 +/* Bring out ya dead! */
3575 +static struct ip_conntrack_tuple_hash *
3576 +get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
3577 + void *data, unsigned int *bucket)
3579 + struct ip_conntrack_tuple_hash *h = NULL;
3581 + READ_LOCK(&ip_conntrack_lock);
3582 + for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
3583 + h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
3584 + struct ip_conntrack_tuple_hash *, kill, data);
3587 + atomic_inc(&h->ctrack->ct_general.use);
3588 + READ_UNLOCK(&ip_conntrack_lock);
3594 + * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries
3595 + * @kill: callback function selecting which entries to delete
3596 + * @data: opaque data pointer, becomes 2nd argument for kill function
3598 + * This function can be used to selectively delete elements of the conntrack
3599 + * hashtable. The function iterates over the list of conntrack entries and
3600 + * calls the 'kill' function for every entry. If the return value is true,
3601 + * the connection is deleted (death_by_timeout).
3604 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
3607 + struct ip_conntrack_tuple_hash *h;
3608 + unsigned int bucket = 0;
3610 + while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
3611 + /* Time to push up daises... */
3612 + if (del_timer(&h->ctrack->timeout))
3613 + death_by_timeout((unsigned long)h->ctrack);
3614 + /* ... else the timer will get him soon. */
3616 + ip_conntrack_put(h->ctrack);
3620 +/* Fast function for those who don't want to parse /proc (and I don't
3622 +/* Reversing the socket's dst/src point of view gives us the reply
3625 +getorigdst(struct sock *sk, int optval, void *user, int *len)
3627 + struct inet_opt *inet = inet_sk(sk);
3628 + struct ip_conntrack_tuple_hash *h;
3629 + struct ip_conntrack_tuple tuple;
3631 + IP_CT_TUPLE_U_BLANK(&tuple);
3632 + tuple.src.ip = inet->rcv_saddr;
3633 + tuple.src.u.tcp.port = inet->sport;
3634 + tuple.dst.ip = inet->daddr;
3635 + tuple.dst.u.tcp.port = inet->dport;
3636 + tuple.dst.protonum = IPPROTO_TCP;
3638 + /* We only do TCP at the moment: is there a better way? */
3639 + if (strcmp(sk->sk_prot->name, "TCP")) {
3640 + DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
3641 + return -ENOPROTOOPT;
3644 + if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
3645 + DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
3646 + *len, sizeof(struct sockaddr_in));
3650 + h = ip_conntrack_find_get(&tuple, NULL);
3652 + struct sockaddr_in sin;
3654 + sin.sin_family = AF_INET;
3655 + sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3656 + .tuple.dst.u.tcp.port;
3657 + sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3660 + DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
3661 + NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
3662 + ip_conntrack_put(h->ctrack);
3663 + if (copy_to_user(user, &sin, sizeof(sin)) != 0)
3668 + DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
3669 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
3670 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
3674 +static struct nf_sockopt_ops so_getorigdst = {
3676 + .get_optmin = SO_ORIGINAL_DST,
3677 + .get_optmax = SO_ORIGINAL_DST+1,
3678 + .get = &getorigdst,
3681 +static int kill_all(const struct ip_conntrack *i, void *data)
3686 +/* Mishearing the voices in his head, our hero wonders how he's
3687 + supposed to kill the mall. */
3688 +void ip_conntrack_cleanup(void)
3690 + ip_ct_attach = NULL;
3691 + /* This makes sure all current packets have passed through
3692 + netfilter framework. Roll on, two-stage module
3694 + synchronize_net();
3696 + i_see_dead_people:
3697 + ip_ct_selective_cleanup(kill_all, NULL);
3698 + if (atomic_read(&ip_conntrack_count) != 0) {
3700 + goto i_see_dead_people;
3703 + kmem_cache_destroy(ip_conntrack_cachep);
3704 + vfree(ip_conntrack_hash);
3705 + nf_unregister_sockopt(&so_getorigdst);
3708 +static int hashsize;
3709 +MODULE_PARM(hashsize, "i");
3711 +int __init ip_conntrack_init(void)
3716 + /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
3717 + * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
3719 + ip_conntrack_htable_size = hashsize;
3721 + ip_conntrack_htable_size
3722 + = (((num_physpages << PAGE_SHIFT) / 16384)
3723 + / sizeof(struct list_head));
3724 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
3725 + ip_conntrack_htable_size = 8192;
3726 + if (ip_conntrack_htable_size < 16)
3727 + ip_conntrack_htable_size = 16;
3729 + ip_conntrack_max = 8 * ip_conntrack_htable_size;
3731 + printk("ip_conntrack version %s (%u buckets, %d max)"
3732 + " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
3733 + ip_conntrack_htable_size, ip_conntrack_max,
3734 + sizeof(struct ip_conntrack));
3736 + ret = nf_register_sockopt(&so_getorigdst);
3738 + printk(KERN_ERR "Unable to register netfilter socket option\n");
3742 + ip_conntrack_hash = vmalloc(sizeof(struct list_head)
3743 + * ip_conntrack_htable_size);
3744 + if (!ip_conntrack_hash) {
3745 + printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
3746 + goto err_unreg_sockopt;
3749 + ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
3750 + sizeof(struct ip_conntrack), 0,
3751 + SLAB_HWCACHE_ALIGN, NULL, NULL);
3752 + if (!ip_conntrack_cachep) {
3753 + printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
3754 + goto err_free_hash;
3756 + /* Don't NEED lock here, but good form anyway. */
3757 + WRITE_LOCK(&ip_conntrack_lock);
3758 + /* Sew in builtin protocols. */
3759 + list_append(&protocol_list, &ip_conntrack_protocol_tcp);
3760 + list_append(&protocol_list, &ip_conntrack_protocol_udp);
3761 + list_append(&protocol_list, &ip_conntrack_protocol_icmp);
3762 + WRITE_UNLOCK(&ip_conntrack_lock);
3764 + for (i = 0; i < ip_conntrack_htable_size; i++)
3765 + INIT_LIST_HEAD(&ip_conntrack_hash[i]);
3767 + /* For use by ipt_REJECT */
3768 + ip_ct_attach = ip_conntrack_attach;
3772 + vfree(ip_conntrack_hash);
3774 + nf_unregister_sockopt(&so_getorigdst);
3778 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c
3779 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-04 06:16:44.000000000 +0000
3780 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-05 09:55:23.000000000 +0000
3781 @@ -194,6 +194,26 @@
3782 return ip_conntrack_confirm(*pskb);
3785 +static unsigned int ip_conntrack_defrag(unsigned int hooknum,
3786 + struct sk_buff **pskb,
3787 + const struct net_device *in,
3788 + const struct net_device *out,
3789 + int (*okfn)(struct sk_buff *))
3791 + /* Previously seen (loopback)? Ignore. Do this before
3792 + fragment check. */
3793 + if ((*pskb)->nfct)
3796 + /* Gather fragments. */
3797 + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
3798 + *pskb = ip_ct_gather_frags(*pskb);
3805 static unsigned int ip_refrag(unsigned int hooknum,
3806 struct sk_buff **pskb,
3807 const struct net_device *in,
3808 @@ -236,6 +256,14 @@
3810 /* Connection tracking may drop packets, but never alters them, so
3811 make it the first hook. */
3812 +static struct nf_hook_ops ip_conntrack_defrag_ops = {
3813 + .hook = ip_conntrack_defrag,
3814 + .owner = THIS_MODULE,
3816 + .hooknum = NF_IP_PRE_ROUTING,
3817 + .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
3820 static struct nf_hook_ops ip_conntrack_in_ops = {
3821 .hook = ip_conntrack_in,
3822 .owner = THIS_MODULE,
3823 @@ -244,6 +272,14 @@
3824 .priority = NF_IP_PRI_CONNTRACK,
3827 +static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = {
3828 + .hook = ip_conntrack_defrag,
3829 + .owner = THIS_MODULE,
3831 + .hooknum = NF_IP_LOCAL_OUT,
3832 + .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
3835 static struct nf_hook_ops ip_conntrack_local_out_ops = {
3836 .hook = ip_conntrack_local,
3837 .owner = THIS_MODULE,
3838 @@ -470,10 +506,20 @@
3839 if (!proc) goto cleanup_init;
3840 proc->owner = THIS_MODULE;
3842 + ret = nf_register_hook(&ip_conntrack_defrag_ops);
3844 + printk("ip_conntrack: can't register pre-routing defrag hook.\n");
3845 + goto cleanup_proc;
3847 + ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
3849 + printk("ip_conntrack: can't register local_out defrag hook.\n");
3850 + goto cleanup_defragops;
3852 ret = nf_register_hook(&ip_conntrack_in_ops);
3854 printk("ip_conntrack: can't register pre-routing hook.\n");
3855 - goto cleanup_proc;
3856 + goto cleanup_defraglocalops;
3858 ret = nf_register_hook(&ip_conntrack_local_out_ops);
3860 @@ -511,6 +557,10 @@
3861 nf_unregister_hook(&ip_conntrack_local_out_ops);
3863 nf_unregister_hook(&ip_conntrack_in_ops);
3864 + cleanup_defraglocalops:
3865 + nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
3866 + cleanup_defragops:
3867 + nf_unregister_hook(&ip_conntrack_defrag_ops);
3869 proc_net_remove("ip_conntrack");
3871 @@ -519,13 +569,20 @@
3875 -/* FIXME: Allow NULL functions and sub in pointers to generic for
3878 + * ip_conntrack_protocol_register - Register layer 4 protocol helper
3879 + * @proto: structure describing this layer 4 protocol helper
3881 + * This function is called by layer 4 protocol helpers to register
3882 + * themselves with the conntrack core.
3884 int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
3887 struct list_head *i;
3889 + /* FIXME: Allow NULL functions and sub in pointers to generic for
3891 WRITE_LOCK(&ip_conntrack_lock);
3892 list_for_each(i, &protocol_list) {
3893 if (((struct ip_conntrack_protocol *)i)->proto
3894 @@ -542,12 +599,20 @@
3899 + * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper
3900 + * @proto: structure describing this layer 4 protocol helper
3902 + * This function is called byh layer 4 protocol helpers to unregister
3903 + * themselvers from the conntrack core. Please note that all conntrack
3904 + * entries for this protocol are deleted from the conntrack hash table.
3906 void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
3908 WRITE_LOCK(&ip_conntrack_lock);
3910 - /* ip_ct_find_proto() returns proto_generic in case there is no protocol
3911 - * helper. So this should be enough - HW */
3912 + /* ip_ct_find_proto() returns proto_generic in case there is no
3913 + * protocol helper. So this should be enough - HW */
3914 LIST_DELETE(&protocol_list, proto);
3915 WRITE_UNLOCK(&ip_conntrack_lock);
3918 EXPORT_SYMBOL(ip_conntrack_expect_list);
3919 EXPORT_SYMBOL(ip_conntrack_lock);
3920 EXPORT_SYMBOL(ip_conntrack_hash);
3921 +EXPORT_SYMBOL(ip_conntrack_untracked);
3922 EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
3923 EXPORT_SYMBOL_GPL(ip_conntrack_put);
3924 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig
3925 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 1970-01-01 00:00:00.000000000 +0000
3926 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 2004-03-05 09:55:06.000000000 +0000
3928 +/* This file contains all the functions required for the standalone
3929 + ip_conntrack module.
3931 + These are not required by the compatibility layer.
3934 +/* (C) 1999-2001 Paul `Rusty' Russell
3935 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3937 + * This program is free software; you can redistribute it and/or modify
3938 + * it under the terms of the GNU General Public License version 2 as
3939 + * published by the Free Software Foundation.
3942 +#include <linux/config.h>
3943 +#include <linux/types.h>
3944 +#include <linux/ip.h>
3945 +#include <linux/netfilter.h>
3946 +#include <linux/netfilter_ipv4.h>
3947 +#include <linux/module.h>
3948 +#include <linux/skbuff.h>
3949 +#include <linux/proc_fs.h>
3950 +#ifdef CONFIG_SYSCTL
3951 +#include <linux/sysctl.h>
3953 +#include <net/checksum.h>
3955 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
3956 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
3958 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3959 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
3960 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3961 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
3962 +#include <linux/netfilter_ipv4/listhelp.h>
3965 +#define DEBUGP printk
3967 +#define DEBUGP(format, args...)
3970 +MODULE_LICENSE("GPL");
3972 +static int kill_proto(const struct ip_conntrack *i, void *data)
3974 + return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
3975 + *((u_int8_t *) data));
3978 +static unsigned int
3979 +print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple,
3980 + struct ip_conntrack_protocol *proto)
3984 + len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
3985 + NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
3987 + len += proto->print_tuple(buffer + len, tuple);
3992 +/* FIXME: Don't print source proto part. --RR */
3993 +static unsigned int
3994 +print_expect(char *buffer, const struct ip_conntrack_expect *expect)
3998 + if (expect->expectant->helper->timeout)
3999 + len = sprintf(buffer, "EXPECTING: %lu ",
4000 + timer_pending(&expect->timeout)
4001 + ? (expect->timeout.expires - jiffies)/HZ : 0);
4003 + len = sprintf(buffer, "EXPECTING: - ");
4004 + len += sprintf(buffer + len, "use=%u proto=%u ",
4005 + atomic_read(&expect->use), expect->tuple.dst.protonum);
4006 + len += print_tuple(buffer + len, &expect->tuple,
4007 + __ip_ct_find_proto(expect->tuple.dst.protonum));
4008 + len += sprintf(buffer + len, "\n");
4012 +static unsigned int
4013 +print_conntrack(char *buffer, struct ip_conntrack *conntrack)
4016 + struct ip_conntrack_protocol *proto
4017 + = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4018 + .tuple.dst.protonum);
4020 + len = sprintf(buffer, "%-8s %u %lu ",
4022 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4023 + .tuple.dst.protonum,
4024 + timer_pending(&conntrack->timeout)
4025 + ? (conntrack->timeout.expires - jiffies)/HZ : 0);
4027 + len += proto->print_conntrack(buffer + len, conntrack);
4028 + len += print_tuple(buffer + len,
4029 + &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
4031 + if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
4032 + len += sprintf(buffer + len, "[UNREPLIED] ");
4033 + len += print_tuple(buffer + len,
4034 + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
4036 + if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
4037 + len += sprintf(buffer + len, "[ASSURED] ");
4038 + len += sprintf(buffer + len, "use=%u ",
4039 + atomic_read(&conntrack->ct_general.use));
4040 + len += sprintf(buffer + len, "\n");
4045 +/* Returns true when finished. */
4047 +conntrack_iterate(const struct ip_conntrack_tuple_hash *hash,
4048 + char *buffer, off_t offset, off_t *upto,
4049 + unsigned int *len, unsigned int maxlen)
4051 + unsigned int newlen;
4052 + IP_NF_ASSERT(hash->ctrack);
4054 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
4056 + /* Only count originals */
4057 + if (DIRECTION(hash))
4060 + if ((*upto)++ < offset)
4063 + newlen = print_conntrack(buffer + *len, hash->ctrack);
4064 + if (*len + newlen > maxlen)
4066 + else *len += newlen;
4072 +list_conntracks(char *buffer, char **start, off_t offset, int length)
4075 + unsigned int len = 0;
4077 + struct list_head *e;
4079 + READ_LOCK(&ip_conntrack_lock);
4080 + /* Traverse hash; print originals then reply. */
4081 + for (i = 0; i < ip_conntrack_htable_size; i++) {
4082 + if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
4083 + struct ip_conntrack_tuple_hash *,
4084 + buffer, offset, &upto, &len, length))
4088 + /* Now iterate through expecteds. */
4089 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
4090 + list_for_each(e, &ip_conntrack_expect_list) {
4091 + unsigned int last_len;
4092 + struct ip_conntrack_expect *expect
4093 + = (struct ip_conntrack_expect *)e;
4094 + if (upto++ < offset) continue;
4097 + len += print_expect(buffer + len, expect);
4098 + if (len > length) {
4100 + goto finished_expects;
4105 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
4107 + READ_UNLOCK(&ip_conntrack_lock);
4109 + /* `start' hack - see fs/proc/generic.c line ~165 */
4110 + *start = (char *)((unsigned int)upto - offset);
4114 +static unsigned int ip_confirm(unsigned int hooknum,
4115 + struct sk_buff **pskb,
4116 + const struct net_device *in,
4117 + const struct net_device *out,
4118 + int (*okfn)(struct sk_buff *))
4120 + /* We've seen it coming out the other side: confirm it */
4121 + return ip_conntrack_confirm(*pskb);
4124 +static unsigned int ip_refrag(unsigned int hooknum,
4125 + struct sk_buff **pskb,
4126 + const struct net_device *in,
4127 + const struct net_device *out,
4128 + int (*okfn)(struct sk_buff *))
4130 + struct rtable *rt = (struct rtable *)(*pskb)->dst;
4132 + /* We've seen it coming out the other side: confirm */
4133 + if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
4136 + /* Local packets are never produced too large for their
4137 + interface. We degfragment them at LOCAL_OUT, however,
4138 + so we have to refragment them here. */
4139 + if ((*pskb)->len > dst_pmtu(&rt->u.dst) &&
4140 + !skb_shinfo(*pskb)->tso_size) {
4141 + /* No hook can be after us, so this should be OK. */
4142 + ip_fragment(*pskb, okfn);
4148 +static unsigned int ip_conntrack_local(unsigned int hooknum,
4149 + struct sk_buff **pskb,
4150 + const struct net_device *in,
4151 + const struct net_device *out,
4152 + int (*okfn)(struct sk_buff *))
4154 + /* root is playing with raw sockets. */
4155 + if ((*pskb)->len < sizeof(struct iphdr)
4156 + || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
4157 + if (net_ratelimit())
4158 + printk("ipt_hook: happy cracking.\n");
4161 + return ip_conntrack_in(hooknum, pskb, in, out, okfn);
4164 +/* Connection tracking may drop packets, but never alters them, so
4165 + make it the first hook. */
4166 +static struct nf_hook_ops ip_conntrack_in_ops = {
4167 + .hook = ip_conntrack_in,
4168 + .owner = THIS_MODULE,
4170 + .hooknum = NF_IP_PRE_ROUTING,
4171 + .priority = NF_IP_PRI_CONNTRACK,
4174 +static struct nf_hook_ops ip_conntrack_local_out_ops = {
4175 + .hook = ip_conntrack_local,
4176 + .owner = THIS_MODULE,
4178 + .hooknum = NF_IP_LOCAL_OUT,
4179 + .priority = NF_IP_PRI_CONNTRACK,
4182 +/* Refragmenter; last chance. */
4183 +static struct nf_hook_ops ip_conntrack_out_ops = {
4184 + .hook = ip_refrag,
4185 + .owner = THIS_MODULE,
4187 + .hooknum = NF_IP_POST_ROUTING,
4188 + .priority = NF_IP_PRI_LAST,
4191 +static struct nf_hook_ops ip_conntrack_local_in_ops = {
4192 + .hook = ip_confirm,
4193 + .owner = THIS_MODULE,
4195 + .hooknum = NF_IP_LOCAL_IN,
4196 + .priority = NF_IP_PRI_LAST-1,
4199 +/* Sysctl support */
4201 +#ifdef CONFIG_SYSCTL
4203 +/* From ip_conntrack_core.c */
4204 +extern int ip_conntrack_max;
4205 +extern unsigned int ip_conntrack_htable_size;
4207 +/* From ip_conntrack_proto_tcp.c */
4208 +extern unsigned long ip_ct_tcp_timeout_syn_sent;
4209 +extern unsigned long ip_ct_tcp_timeout_syn_recv;
4210 +extern unsigned long ip_ct_tcp_timeout_established;
4211 +extern unsigned long ip_ct_tcp_timeout_fin_wait;
4212 +extern unsigned long ip_ct_tcp_timeout_close_wait;
4213 +extern unsigned long ip_ct_tcp_timeout_last_ack;
4214 +extern unsigned long ip_ct_tcp_timeout_time_wait;
4215 +extern unsigned long ip_ct_tcp_timeout_close;
4217 +/* From ip_conntrack_proto_udp.c */
4218 +extern unsigned long ip_ct_udp_timeout;
4219 +extern unsigned long ip_ct_udp_timeout_stream;
4221 +/* From ip_conntrack_proto_icmp.c */
4222 +extern unsigned long ip_ct_icmp_timeout;
4224 +/* From ip_conntrack_proto_icmp.c */
4225 +extern unsigned long ip_ct_generic_timeout;
4227 +static struct ctl_table_header *ip_ct_sysctl_header;
4229 +static ctl_table ip_ct_sysctl_table[] = {
4231 + .ctl_name = NET_IPV4_NF_CONNTRACK_MAX,
4232 + .procname = "ip_conntrack_max",
4233 + .data = &ip_conntrack_max,
4234 + .maxlen = sizeof(int),
4236 + .proc_handler = &proc_dointvec,
4239 + .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
4240 + .procname = "ip_conntrack_buckets",
4241 + .data = &ip_conntrack_htable_size,
4242 + .maxlen = sizeof(unsigned int),
4244 + .proc_handler = &proc_dointvec,
4247 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
4248 + .procname = "ip_conntrack_tcp_timeout_syn_sent",
4249 + .data = &ip_ct_tcp_timeout_syn_sent,
4250 + .maxlen = sizeof(unsigned int),
4252 + .proc_handler = &proc_dointvec_jiffies,
4255 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
4256 + .procname = "ip_conntrack_tcp_timeout_syn_recv",
4257 + .data = &ip_ct_tcp_timeout_syn_recv,
4258 + .maxlen = sizeof(unsigned int),
4260 + .proc_handler = &proc_dointvec_jiffies,
4263 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
4264 + .procname = "ip_conntrack_tcp_timeout_established",
4265 + .data = &ip_ct_tcp_timeout_established,
4266 + .maxlen = sizeof(unsigned int),
4268 + .proc_handler = &proc_dointvec_jiffies,
4271 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
4272 + .procname = "ip_conntrack_tcp_timeout_fin_wait",
4273 + .data = &ip_ct_tcp_timeout_fin_wait,
4274 + .maxlen = sizeof(unsigned int),
4276 + .proc_handler = &proc_dointvec_jiffies,
4279 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
4280 + .procname = "ip_conntrack_tcp_timeout_close_wait",
4281 + .data = &ip_ct_tcp_timeout_close_wait,
4282 + .maxlen = sizeof(unsigned int),
4284 + .proc_handler = &proc_dointvec_jiffies,
4287 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
4288 + .procname = "ip_conntrack_tcp_timeout_last_ack",
4289 + .data = &ip_ct_tcp_timeout_last_ack,
4290 + .maxlen = sizeof(unsigned int),
4292 + .proc_handler = &proc_dointvec_jiffies,
4295 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
4296 + .procname = "ip_conntrack_tcp_timeout_time_wait",
4297 + .data = &ip_ct_tcp_timeout_time_wait,
4298 + .maxlen = sizeof(unsigned int),
4300 + .proc_handler = &proc_dointvec_jiffies,
4303 + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
4304 + .procname = "ip_conntrack_tcp_timeout_close",
4305 + .data = &ip_ct_tcp_timeout_close,
4306 + .maxlen = sizeof(unsigned int),
4308 + .proc_handler = &proc_dointvec_jiffies,
4311 + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,
4312 + .procname = "ip_conntrack_udp_timeout",
4313 + .data = &ip_ct_udp_timeout,
4314 + .maxlen = sizeof(unsigned int),
4316 + .proc_handler = &proc_dointvec_jiffies,
4319 + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
4320 + .procname = "ip_conntrack_udp_timeout_stream",
4321 + .data = &ip_ct_udp_timeout_stream,
4322 + .maxlen = sizeof(unsigned int),
4324 + .proc_handler = &proc_dointvec_jiffies,
4327 + .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
4328 + .procname = "ip_conntrack_icmp_timeout",
4329 + .data = &ip_ct_icmp_timeout,
4330 + .maxlen = sizeof(unsigned int),
4332 + .proc_handler = &proc_dointvec_jiffies,
4335 + .ctl_name = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,
4336 + .procname = "ip_conntrack_generic_timeout",
4337 + .data = &ip_ct_generic_timeout,
4338 + .maxlen = sizeof(unsigned int),
4340 + .proc_handler = &proc_dointvec_jiffies,
4345 +#define NET_IP_CONNTRACK_MAX 2089
4347 +static ctl_table ip_ct_netfilter_table[] = {
4349 + .ctl_name = NET_IPV4_NETFILTER,
4350 + .procname = "netfilter",
4352 + .child = ip_ct_sysctl_table,
4355 + .ctl_name = NET_IP_CONNTRACK_MAX,
4356 + .procname = "ip_conntrack_max",
4357 + .data = &ip_conntrack_max,
4358 + .maxlen = sizeof(int),
4360 + .proc_handler = &proc_dointvec
4365 +static ctl_table ip_ct_ipv4_table[] = {
4367 + .ctl_name = NET_IPV4,
4368 + .procname = "ipv4",
4370 + .child = ip_ct_netfilter_table,
4375 +static ctl_table ip_ct_net_table[] = {
4377 + .ctl_name = CTL_NET,
4378 + .procname = "net",
4380 + .child = ip_ct_ipv4_table,
4385 +static int init_or_cleanup(int init)
4387 + struct proc_dir_entry *proc;
4390 + if (!init) goto cleanup;
4392 + ret = ip_conntrack_init();
4394 + goto cleanup_nothing;
4396 + proc = proc_net_create("ip_conntrack",0,list_conntracks);
4397 + if (!proc) goto cleanup_init;
4398 + proc->owner = THIS_MODULE;
4400 + ret = nf_register_hook(&ip_conntrack_in_ops);
4402 + printk("ip_conntrack: can't register pre-routing hook.\n");
4403 + goto cleanup_proc;
4405 + ret = nf_register_hook(&ip_conntrack_local_out_ops);
4407 + printk("ip_conntrack: can't register local out hook.\n");
4408 + goto cleanup_inops;
4410 + ret = nf_register_hook(&ip_conntrack_out_ops);
4412 + printk("ip_conntrack: can't register post-routing hook.\n");
4413 + goto cleanup_inandlocalops;
4415 + ret = nf_register_hook(&ip_conntrack_local_in_ops);
4417 + printk("ip_conntrack: can't register local in hook.\n");
4418 + goto cleanup_inoutandlocalops;
4420 +#ifdef CONFIG_SYSCTL
4421 + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
4422 + if (ip_ct_sysctl_header == NULL) {
4423 + printk("ip_conntrack: can't register to sysctl.\n");
4431 +#ifdef CONFIG_SYSCTL
4432 + unregister_sysctl_table(ip_ct_sysctl_header);
4434 + nf_unregister_hook(&ip_conntrack_local_in_ops);
4435 + cleanup_inoutandlocalops:
4436 + nf_unregister_hook(&ip_conntrack_out_ops);
4437 + cleanup_inandlocalops:
4438 + nf_unregister_hook(&ip_conntrack_local_out_ops);
4440 + nf_unregister_hook(&ip_conntrack_in_ops);
4442 + proc_net_remove("ip_conntrack");
4444 + ip_conntrack_cleanup();
4450 + * ip_conntrack_protocol_register - Register layer 4 protocol helper
4451 + * @proto: structure describing this layer 4 protocol helper
4453 + * This function is called by layer 4 protocol helpers to register
4454 + * themselves with the conntrack core.
4456 +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
4459 + struct list_head *i;
4461 + /* FIXME: Allow NULL functions and sub in pointers to generic for
4463 + WRITE_LOCK(&ip_conntrack_lock);
4464 + list_for_each(i, &protocol_list) {
4465 + if (((struct ip_conntrack_protocol *)i)->proto
4466 + == proto->proto) {
4472 + list_prepend(&protocol_list, proto);
4475 + WRITE_UNLOCK(&ip_conntrack_lock);
4480 + * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper
4481 + * @proto: structure describing this layer 4 protocol helper
4483 + * This function is called byh layer 4 protocol helpers to unregister
4484 + * themselvers from the conntrack core. Please note that all conntrack
4485 + * entries for this protocol are deleted from the conntrack hash table.
4487 +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
4489 + WRITE_LOCK(&ip_conntrack_lock);
4491 + /* ip_ct_find_proto() returns proto_generic in case there is no
4492 + * protocol helper. So this should be enough - HW */
4493 + LIST_DELETE(&protocol_list, proto);
4494 + WRITE_UNLOCK(&ip_conntrack_lock);
4496 + /* Somebody could be still looking at the proto in bh. */
4497 + synchronize_net();
4499 + /* Remove all contrack entries for this protocol */
4500 + ip_ct_selective_cleanup(kill_proto, &proto->proto);
4503 +static int __init init(void)
4505 + return init_or_cleanup(1);
4508 +static void __exit fini(void)
4510 + init_or_cleanup(0);
4516 +/* Some modules need us, but don't depend directly on any symbol.
4517 + They should call this. */
4518 +void need_ip_conntrack(void)
4522 +EXPORT_SYMBOL(ip_conntrack_protocol_register);
4523 +EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
4524 +EXPORT_SYMBOL(invert_tuplepr);
4525 +EXPORT_SYMBOL(ip_conntrack_alter_reply);
4526 +EXPORT_SYMBOL(ip_conntrack_destroyed);
4527 +EXPORT_SYMBOL(ip_conntrack_get);
4528 +EXPORT_SYMBOL(need_ip_conntrack);
4529 +EXPORT_SYMBOL(ip_conntrack_helper_register);
4530 +EXPORT_SYMBOL(ip_conntrack_helper_unregister);
4531 +EXPORT_SYMBOL(ip_ct_selective_cleanup);
4532 +EXPORT_SYMBOL(ip_ct_refresh);
4533 +EXPORT_SYMBOL(ip_ct_find_proto);
4534 +EXPORT_SYMBOL(__ip_ct_find_proto);
4535 +EXPORT_SYMBOL(ip_ct_find_helper);
4536 +EXPORT_SYMBOL(ip_conntrack_expect_related);
4537 +EXPORT_SYMBOL(ip_conntrack_change_expect);
4538 +EXPORT_SYMBOL(ip_conntrack_unexpect_related);
4539 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
4540 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
4541 +EXPORT_SYMBOL(ip_conntrack_tuple_taken);
4542 +EXPORT_SYMBOL(ip_ct_gather_frags);
4543 +EXPORT_SYMBOL(ip_conntrack_htable_size);
4544 +EXPORT_SYMBOL(ip_conntrack_expect_list);
4545 +EXPORT_SYMBOL(ip_conntrack_lock);
4546 +EXPORT_SYMBOL(ip_conntrack_hash);
4547 +EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
4548 +EXPORT_SYMBOL_GPL(ip_conntrack_put);
4549 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c
4550 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c 2004-03-04 06:16:37.000000000 +0000
4551 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c 2004-03-05 09:55:23.000000000 +0000
4553 WRITE_UNLOCK(&ip_nat_lock);
4556 -/* We do checksum mangling, so if they were wrong before they're still
4557 - * wrong. Also works for incomplete packets (eg. ICMP dest
4558 - * unreachables.) */
4560 + * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum
4561 + * @oldvalinv: bit-inverted old value of 32bit word
4562 + * @newval: new value of 32bit word
4563 + * @oldcheck: old checksum value
4565 + * This function implements incremental checksum mangling, so if a checksum
4566 + * was wrong it will still be wrong after mangling. Also works for incomplete
4567 + * packets (eg. ICMP dest unreachables). Return value is the new checksum.
4570 ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
4572 @@ -124,7 +131,14 @@
4576 -/* Is this tuple already taken? (not by us) */
4578 + * ip_nat_used_tuple - Is this tuple already in use?
4579 + * @tuple: tuple to be used for this check
4580 + * @ignored_conntrack: conntrack excluded from this check
4582 + * This function checks for the reply (inverted) tuple in the conntrack
4583 + * hash. This is necessarry with NAT, since there is no fixed mapping.
4586 ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
4587 const struct ip_conntrack *ignored_conntrack)
4588 @@ -515,6 +529,19 @@
4593 + * ip_nat_setup_info - Set up NAT mappings for NEW packet
4594 + * @conntrack: conntrack on which we operate
4595 + * @mr: address/port range which is valid for this NAT mapping
4596 + * @hooknum: hook at which this NAT mapping applies
4598 + * This function is called by NAT targets (SNAT,DNAT,...) and by
4599 + * the NAT application helper modules. It is called for the NEW packet
4600 + * of a connection in order to specify which NAT mappings shall apply to
4601 + * this connection at a given hook.
4603 + * Note: The reply mappings are created automagically by this function.
4606 ip_nat_setup_info(struct ip_conntrack *conntrack,
4607 const struct ip_nat_multi_range *mr,
4608 @@ -1016,6 +1043,10 @@
4609 /* FIXME: Man, this is a hack. <SIGH> */
4610 IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
4611 ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
4613 + /* Initialize fake conntrack so that NAT will skip it */
4614 + ip_conntrack_untracked.nat.info.initialized |=
4615 + (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST);
4619 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c.orig
4620 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c.orig 1970-01-01 00:00:00.000000000 +0000
4621 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c.orig 2004-03-05 09:55:06.000000000 +0000
4623 +/* NAT for netfilter; shared with compatibility layer. */
4625 +/* (C) 1999-2001 Paul `Rusty' Russell
4626 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
4628 + * This program is free software; you can redistribute it and/or modify
4629 + * it under the terms of the GNU General Public License version 2 as
4630 + * published by the Free Software Foundation.
4633 +#include <linux/module.h>
4634 +#include <linux/types.h>
4635 +#include <linux/timer.h>
4636 +#include <linux/skbuff.h>
4637 +#include <linux/netfilter_ipv4.h>
4638 +#include <linux/vmalloc.h>
4639 +#include <net/checksum.h>
4640 +#include <net/icmp.h>
4641 +#include <net/ip.h>
4642 +#include <net/tcp.h> /* For tcp_prot in getorigdst */
4643 +#include <linux/icmp.h>
4644 +#include <linux/udp.h>
4646 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
4647 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
4649 +#include <linux/netfilter_ipv4/ip_conntrack.h>
4650 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
4651 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
4652 +#include <linux/netfilter_ipv4/ip_nat.h>
4653 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
4654 +#include <linux/netfilter_ipv4/ip_nat_core.h>
4655 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
4656 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
4657 +#include <linux/netfilter_ipv4/listhelp.h>
4660 +#define DEBUGP printk
4662 +#define DEBUGP(format, args...)
4665 +DECLARE_RWLOCK(ip_nat_lock);
4666 +DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
4668 +/* Calculated at init based on memory size */
4669 +static unsigned int ip_nat_htable_size;
4671 +static struct list_head *bysource;
4672 +static struct list_head *byipsproto;
4674 +LIST_HEAD(helpers);
4676 +extern struct ip_nat_protocol unknown_nat_protocol;
4678 +/* We keep extra hashes for each conntrack, for fast searching. */
4679 +static inline size_t
4680 +hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto)
4682 + /* Modified src and dst, to ensure we don't create two
4683 + identical streams. */
4684 + return (src + dst + proto) % ip_nat_htable_size;
4687 +static inline size_t
4688 +hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
4690 + /* Original src, to ensure we map it consistently if poss. */
4691 + return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
4694 +/* Noone using conntrack by the time this called. */
4695 +static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
4697 + struct ip_nat_info *info = &conn->nat.info;
4698 + unsigned int hs, hp;
4700 + if (!info->initialized)
4703 + IP_NF_ASSERT(info->bysource.conntrack);
4704 + IP_NF_ASSERT(info->byipsproto.conntrack);
4706 + hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
4707 + conn->tuplehash[IP_CT_DIR_ORIGINAL]
4708 + .tuple.dst.protonum);
4710 + hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
4711 + conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
4712 + conn->tuplehash[IP_CT_DIR_REPLY]
4713 + .tuple.dst.protonum);
4715 + WRITE_LOCK(&ip_nat_lock);
4716 + LIST_DELETE(&bysource[hs], &info->bysource);
4717 + LIST_DELETE(&byipsproto[hp], &info->byipsproto);
4718 + WRITE_UNLOCK(&ip_nat_lock);
4722 + * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum
4723 + * @oldvalinv: bit-inverted old value of 32bit word
4724 + * @newval: new value of 32bit word
4725 + * @oldcheck: old checksum value
4727 + * This function implements incremental checksum mangling, so if a checksum
4728 + * was wrong it will still be wrong after mangling. Also works for incomplete
4729 + * packets (eg. ICMP dest unreachables). Return value is the new checksum.
4732 +ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
4734 + u_int32_t diffs[] = { oldvalinv, newval };
4735 + return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
4736 + oldcheck^0xFFFF));
4739 +static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
4741 + return i->protonum == proto;
4744 +struct ip_nat_protocol *
4745 +find_nat_proto(u_int16_t protonum)
4747 + struct ip_nat_protocol *i;
4749 + MUST_BE_READ_LOCKED(&ip_nat_lock);
4750 + i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
4752 + i = &unknown_nat_protocol;
4757 + * ip_nat_used_tuple - Is this tuple already in use?
4758 + * @tuple: tuple to be used for this check
4759 + * @ignored_conntrack: conntrack excluded from this check
4761 + * This function checks for the reply (inverted) tuple in the conntrack
4762 + * hash. This is necessarry with NAT, since there is no fixed mapping.
4765 +ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
4766 + const struct ip_conntrack *ignored_conntrack)
4768 + /* Conntrack tracking doesn't keep track of outgoing tuples; only
4769 + incoming ones. NAT means they don't have a fixed mapping,
4770 + so we invert the tuple and look for the incoming reply.
4772 + We could keep a separate hash if this proves too slow. */
4773 + struct ip_conntrack_tuple reply;
4775 + invert_tuplepr(&reply, tuple);
4776 + return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
4779 +/* Does tuple + the source manip come within the range mr */
4781 +in_range(const struct ip_conntrack_tuple *tuple,
4782 + const struct ip_conntrack_manip *manip,
4783 + const struct ip_nat_multi_range *mr)
4785 + struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
4787 + struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
4789 + for (i = 0; i < mr->rangesize; i++) {
4790 + /* If we are allowed to map IPs, then we must be in the
4791 + range specified, otherwise we must be unchanged. */
4792 + if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
4793 + if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
4794 + || (ntohl(newtuple.src.ip)
4795 + > ntohl(mr->range[i].max_ip)))
4798 + if (newtuple.src.ip != tuple->src.ip)
4802 + if (!(mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
4803 + || proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
4804 + &mr->range[i].min, &mr->range[i].max))
4811 +src_cmp(const struct ip_nat_hash *i,
4812 + const struct ip_conntrack_tuple *tuple,
4813 + const struct ip_nat_multi_range *mr)
4815 + return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
4816 + == tuple->dst.protonum
4817 + && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
4819 + && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
4820 + == tuple->src.u.all
4821 + && in_range(tuple,
4822 + &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4827 +/* Only called for SRC manip */
4828 +static struct ip_conntrack_manip *
4829 +find_appropriate_src(const struct ip_conntrack_tuple *tuple,
4830 + const struct ip_nat_multi_range *mr)
4832 + unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
4833 + struct ip_nat_hash *i;
4835 + MUST_BE_READ_LOCKED(&ip_nat_lock);
4836 + i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
4838 + return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
4843 +#ifdef CONFIG_IP_NF_NAT_LOCAL
4844 +/* If it's really a local destination manip, it may need to do a
4845 + source manip too. */
4847 +do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
4849 + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = var_ip } } };
4850 + struct rtable *rt;
4852 + /* FIXME: IPTOS_TOS(iph->tos) --RR */
4853 + if (ip_route_output_key(&rt, &fl) != 0) {
4854 + DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
4859 + *other_ipp = rt->rt_src;
4865 +/* Simple way to iterate through all. */
4866 +static inline int fake_cmp(const struct ip_nat_hash *i,
4867 + u_int32_t src, u_int32_t dst, u_int16_t protonum,
4868 + unsigned int *score,
4869 + const struct ip_conntrack *conntrack)
4871 + /* Compare backwards: we're dealing with OUTGOING tuples, and
4872 + inside the conntrack is the REPLY tuple. Don't count this
4874 + if (i->conntrack != conntrack
4875 + && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
4876 + && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
4877 + && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
4883 +static inline unsigned int
4884 +count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
4885 + const struct ip_conntrack *conntrack)
4887 + unsigned int score = 0;
4890 + MUST_BE_READ_LOCKED(&ip_nat_lock);
4891 + h = hash_by_ipsproto(src, dst, protonum);
4892 + LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
4893 + src, dst, protonum, &score, conntrack);
4898 +/* For [FUTURE] fragmentation handling, we want the least-used
4899 + src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
4900 + if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
4901 + 1-65535, we don't do pro-rata allocation based on ports; we choose
4902 + the ip with the lowest src-ip/dst-ip/proto usage.
4904 + If an allocation then fails (eg. all 6 ports used in the 1.2.3.4
4905 + range), we eliminate that and try again. This is not the most
4906 + efficient approach, but if you're worried about that, don't hand us
4907 + ranges you don't really have. */
4908 +static struct ip_nat_range *
4909 +find_best_ips_proto(struct ip_conntrack_tuple *tuple,
4910 + const struct ip_nat_multi_range *mr,
4911 + const struct ip_conntrack *conntrack,
4912 + unsigned int hooknum)
4916 + const struct ip_nat_range *range;
4917 + unsigned int score;
4918 + struct ip_conntrack_tuple tuple;
4919 + } best = { NULL, 0xFFFFFFFF };
4920 + u_int32_t *var_ipp, *other_ipp, saved_ip, orig_dstip;
4921 + static unsigned int randomness;
4923 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
4924 + var_ipp = &tuple->src.ip;
4925 + saved_ip = tuple->dst.ip;
4926 + other_ipp = &tuple->dst.ip;
4928 + var_ipp = &tuple->dst.ip;
4929 + saved_ip = tuple->src.ip;
4930 + other_ipp = &tuple->src.ip;
4932 + /* Don't do do_extra_mangle unless necessary (overrides
4933 + explicit socket bindings, for example) */
4934 + orig_dstip = tuple->dst.ip;
4936 + IP_NF_ASSERT(mr->rangesize >= 1);
4937 + for (i = 0; i < mr->rangesize; i++) {
4939 + u_int32_t minip, maxip, j;
4941 + /* Don't do ranges which are already eliminated. */
4942 + if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
4946 + if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
4947 + minip = ntohl(mr->range[i].min_ip);
4948 + maxip = ntohl(mr->range[i].max_ip);
4950 + minip = maxip = ntohl(*var_ipp);
4953 + for (j = 0; j < maxip - minip + 1; j++) {
4954 + unsigned int score;
4956 + *var_ipp = htonl(minip + (randomness + j)
4957 + % (maxip - minip + 1));
4959 + /* Reset the other ip in case it was mangled by
4960 + * do_extra_mangle last time. */
4961 + *other_ipp = saved_ip;
4963 +#ifdef CONFIG_IP_NF_NAT_LOCAL
4964 + if (hooknum == NF_IP_LOCAL_OUT
4965 + && *var_ipp != orig_dstip
4966 + && !do_extra_mangle(*var_ipp, other_ipp)) {
4967 + DEBUGP("Range %u %u.%u.%u.%u rt failed!\n",
4968 + i, NIPQUAD(*var_ipp));
4969 + /* Can't route? This whole range part is
4970 + * probably screwed, but keep trying
4976 + /* Count how many others map onto this. */
4977 + score = count_maps(tuple->src.ip, tuple->dst.ip,
4978 + tuple->dst.protonum, conntrack);
4979 + if (score < best.score) {
4980 + /* Optimization: doesn't get any better than
4983 + return (struct ip_nat_range *)
4986 + best.score = score;
4987 + best.tuple = *tuple;
4988 + best.range = &mr->range[i];
4992 + *tuple = best.tuple;
4994 + /* Discard const. */
4995 + return (struct ip_nat_range *)best.range;
4998 +/* Fast version doesn't iterate through hash chains, but only handles
4999 + common case of single IP address (null NAT, masquerade) */
5000 +static struct ip_nat_range *
5001 +find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,
5002 + const struct ip_nat_multi_range *mr,
5003 + const struct ip_conntrack *conntrack,
5004 + unsigned int hooknum)
5006 + if (mr->rangesize != 1
5007 + || (mr->range[0].flags & IP_NAT_RANGE_FULL)
5008 + || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
5009 + && mr->range[0].min_ip != mr->range[0].max_ip))
5010 + return find_best_ips_proto(tuple, mr, conntrack, hooknum);
5012 + if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
5013 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
5014 + tuple->src.ip = mr->range[0].min_ip;
5016 + /* Only do extra mangle when required (breaks
5017 + socket binding) */
5018 +#ifdef CONFIG_IP_NF_NAT_LOCAL
5019 + if (tuple->dst.ip != mr->range[0].min_ip
5020 + && hooknum == NF_IP_LOCAL_OUT
5021 + && !do_extra_mangle(mr->range[0].min_ip,
5025 + tuple->dst.ip = mr->range[0].min_ip;
5029 + /* Discard const. */
5030 + return (struct ip_nat_range *)&mr->range[0];
5034 +get_unique_tuple(struct ip_conntrack_tuple *tuple,
5035 + const struct ip_conntrack_tuple *orig_tuple,
5036 + const struct ip_nat_multi_range *mrr,
5037 + struct ip_conntrack *conntrack,
5038 + unsigned int hooknum)
5040 + struct ip_nat_protocol *proto
5041 + = find_nat_proto(orig_tuple->dst.protonum);
5042 + struct ip_nat_range *rptr;
5046 + /* We temporarily use flags for marking full parts, but we
5047 + always clean up afterwards */
5048 + struct ip_nat_multi_range *mr = (void *)mrr;
5050 + /* 1) If this srcip/proto/src-proto-part is currently mapped,
5051 + and that same mapping gives a unique tuple within the given
5054 + This is only required for source (ie. NAT/masq) mappings.
5055 + So far, we don't do local source mappings, so multiple
5056 + manips not an issue. */
5057 + if (hooknum == NF_IP_POST_ROUTING) {
5058 + struct ip_conntrack_manip *manip;
5060 + manip = find_appropriate_src(orig_tuple, mr);
5062 + /* Apply same source manipulation. */
5063 + *tuple = ((struct ip_conntrack_tuple)
5064 + { *manip, orig_tuple->dst });
5065 + DEBUGP("get_unique_tuple: Found current src map\n");
5066 + if (!ip_nat_used_tuple(tuple, conntrack))
5071 + /* 2) Select the least-used IP/proto combination in the given
5074 + *tuple = *orig_tuple;
5075 + while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
5077 + DEBUGP("Found best for "); DUMP_TUPLE(tuple);
5078 + /* 3) The per-protocol part of the manip is made to
5079 + map into the range to make a unique tuple. */
5081 + /* Only bother mapping if it's not already in range
5083 + if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
5084 + || proto->in_range(tuple, HOOK2MANIP(hooknum),
5085 + &rptr->min, &rptr->max))
5086 + && !ip_nat_used_tuple(tuple, conntrack)) {
5090 + if (proto->unique_tuple(tuple, rptr,
5091 + HOOK2MANIP(hooknum),
5093 + /* Must be unique. */
5094 + IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
5098 + } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
5099 + /* Try implicit source NAT; protocol
5100 + may be able to play with ports to
5101 + make it unique. */
5102 + struct ip_nat_range r
5103 + = { IP_NAT_RANGE_MAP_IPS,
5104 + tuple->src.ip, tuple->src.ip,
5106 + DEBUGP("Trying implicit mapping\n");
5107 + if (proto->unique_tuple(tuple, &r,
5110 + /* Must be unique. */
5111 + IP_NF_ASSERT(!ip_nat_used_tuple
5112 + (tuple, conntrack));
5117 + DEBUGP("Protocol can't get unique tuple %u.\n",
5121 + /* Eliminate that from range, and try again. */
5122 + rptr->flags |= IP_NAT_RANGE_FULL;
5123 + *tuple = *orig_tuple;
5129 + /* Clear full flags. */
5130 + IP_NF_ASSERT(mr->rangesize >= 1);
5131 + for (i = 0; i < mr->rangesize; i++)
5132 + mr->range[i].flags &= ~IP_NAT_RANGE_FULL;
5138 +helper_cmp(const struct ip_nat_helper *helper,
5139 + const struct ip_conntrack_tuple *tuple)
5141 + return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
5144 +/* Where to manip the reply packets (will be reverse manip). */
5145 +static unsigned int opposite_hook[NF_IP_NUMHOOKS]
5146 += { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
5147 + [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
5148 +#ifdef CONFIG_IP_NF_NAT_LOCAL
5149 + [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
5150 + [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
5155 + * ip_nat_setup_info - Set up NAT mappings for NEW packet
5156 + * @conntrack: conntrack on which we operate
5157 + * @mr: address/port range which is valid for this NAT mapping
5158 + * @hooknum: hook at which this NAT mapping applies
5160 + * This function is called by NAT targets (SNAT,DNAT,...) and by
5161 + * the NAT application helper modules. It is called for the NEW packet
5162 + * of a connection in order to specify which NAT mappings shall apply to
5163 + * this connection at a given hook.
5165 + * Note: The reply mappings are created automagically by this function.
5168 +ip_nat_setup_info(struct ip_conntrack *conntrack,
5169 + const struct ip_nat_multi_range *mr,
5170 + unsigned int hooknum)
5172 + struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
5173 + struct ip_conntrack_tuple orig_tp;
5174 + struct ip_nat_info *info = &conntrack->nat.info;
5175 + int in_hashes = info->initialized;
5177 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5178 + IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
5179 + || hooknum == NF_IP_POST_ROUTING
5180 + || hooknum == NF_IP_LOCAL_OUT);
5181 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5182 + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
5184 + /* What we've got will look like inverse of reply. Normally
5185 + this is what is in the conntrack, except for prior
5186 + manipulations (future optimization: if num_manips == 0,
5188 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
5189 + invert_tuplepr(&orig_tp,
5190 + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
5196 + DEBUGP("Hook %u (%s), ", hooknum,
5197 + HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");
5198 + DUMP_TUPLE(&orig_tp);
5199 + DEBUGP("Range %p: ", mr);
5200 + for (i = 0; i < mr->rangesize; i++) {
5201 + DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",
5203 + (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)
5204 + ? " MAP_IPS" : "",
5205 + (mr->range[i].flags
5206 + & IP_NAT_RANGE_PROTO_SPECIFIED)
5207 + ? " PROTO_SPECIFIED" : "",
5208 + (mr->range[i].flags & IP_NAT_RANGE_FULL)
5210 + NIPQUAD(mr->range[i].min_ip),
5211 + NIPQUAD(mr->range[i].max_ip),
5212 + mr->range[i].min.all,
5213 + mr->range[i].max.all);
5219 + if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
5221 + DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
5227 + DEBUGP("Hook %u (%s) %p\n", hooknum,
5228 + HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
5230 + DEBUGP("Original: ");
5231 + DUMP_TUPLE(&orig_tp);
5233 + DUMP_TUPLE(&new_tuple);
5236 + /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
5237 + the original (A/B/C/D') and the mangled one (E/F/G/H').
5239 + We're only allowed to work with the SRC per-proto
5240 + part, so we create inverses of both to start, then
5241 + derive the other fields we need. */
5243 + /* Reply connection: simply invert the new tuple
5245 + invert_tuplepr(&reply, &new_tuple);
5247 + /* Alter conntrack table so it recognizes replies.
5248 + If fail this race (reply tuple now used), repeat. */
5249 + } while (!ip_conntrack_alter_reply(conntrack, &reply));
5251 + /* FIXME: We can simply used existing conntrack reply tuple
5253 + /* Create inverse of original: C/D/A/B' */
5254 + invert_tuplepr(&inv_tuple, &orig_tp);
5256 + /* Has source changed?. */
5257 + if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {
5258 + /* In this direction, a source manip. */
5259 + info->manips[info->num_manips++] =
5260 + ((struct ip_nat_info_manip)
5261 + { IP_CT_DIR_ORIGINAL, hooknum,
5262 + IP_NAT_MANIP_SRC, new_tuple.src });
5264 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5266 + /* In the reverse direction, a destination manip. */
5267 + info->manips[info->num_manips++] =
5268 + ((struct ip_nat_info_manip)
5269 + { IP_CT_DIR_REPLY, opposite_hook[hooknum],
5270 + IP_NAT_MANIP_DST, orig_tp.src });
5271 + IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
5274 + /* Has destination changed? */
5275 + if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {
5276 + /* In this direction, a destination manip */
5277 + info->manips[info->num_manips++] =
5278 + ((struct ip_nat_info_manip)
5279 + { IP_CT_DIR_ORIGINAL, hooknum,
5280 + IP_NAT_MANIP_DST, reply.src });
5282 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5284 + /* In the reverse direction, a source manip. */
5285 + info->manips[info->num_manips++] =
5286 + ((struct ip_nat_info_manip)
5287 + { IP_CT_DIR_REPLY, opposite_hook[hooknum],
5288 + IP_NAT_MANIP_SRC, inv_tuple.src });
5289 + IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
5292 + /* If there's a helper, assign it; based on new tuple. */
5293 + if (!conntrack->master)
5294 + info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
5298 + info->initialized |= (1 << HOOK2MANIP(hooknum));
5301 + IP_NF_ASSERT(info->bysource.conntrack);
5302 + replace_in_hashes(conntrack, info);
5304 + place_in_hashes(conntrack, info);
5310 +void replace_in_hashes(struct ip_conntrack *conntrack,
5311 + struct ip_nat_info *info)
5313 + /* Source has changed, so replace in hashes. */
5314 + unsigned int srchash
5315 + = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5317 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5318 + .tuple.dst.protonum);
5319 + /* We place packet as seen OUTGOUNG in byips_proto hash
5320 + (ie. reverse dst and src of reply packet. */
5321 + unsigned int ipsprotohash
5322 + = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
5324 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5326 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5327 + .tuple.dst.protonum);
5329 + IP_NF_ASSERT(info->bysource.conntrack == conntrack);
5330 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5332 + list_del(&info->bysource.list);
5333 + list_del(&info->byipsproto.list);
5335 + list_prepend(&bysource[srchash], &info->bysource);
5336 + list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5339 +void place_in_hashes(struct ip_conntrack *conntrack,
5340 + struct ip_nat_info *info)
5342 + unsigned int srchash
5343 + = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5345 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5346 + .tuple.dst.protonum);
5347 + /* We place packet as seen OUTGOUNG in byips_proto hash
5348 + (ie. reverse dst and src of reply packet. */
5349 + unsigned int ipsprotohash
5350 + = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
5352 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5354 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5355 + .tuple.dst.protonum);
5357 + IP_NF_ASSERT(!info->bysource.conntrack);
5359 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5360 + info->byipsproto.conntrack = conntrack;
5361 + info->bysource.conntrack = conntrack;
5363 + list_prepend(&bysource[srchash], &info->bysource);
5364 + list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5367 +/* Returns true if succeeded. */
5369 +manip_pkt(u_int16_t proto,
5370 + struct sk_buff **pskb,
5371 + unsigned int iphdroff,
5372 + const struct ip_conntrack_manip *manip,
5373 + enum ip_nat_manip_type maniptype)
5375 + struct iphdr *iph;
5377 + (*pskb)->nfcache |= NFC_ALTERED;
5378 + if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph)))
5381 + iph = (void *)(*pskb)->data + iphdroff;
5383 + /* Manipulate protcol part. */
5384 + if (!find_nat_proto(proto)->manip_pkt(pskb,
5385 + iphdroff + iph->ihl*4,
5386 + manip, maniptype))
5389 + iph = (void *)(*pskb)->data + iphdroff;
5391 + if (maniptype == IP_NAT_MANIP_SRC) {
5392 + iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
5394 + iph->saddr = manip->ip;
5396 + iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
5398 + iph->daddr = manip->ip;
5403 +static inline int exp_for_packet(struct ip_conntrack_expect *exp,
5404 + struct sk_buff *skb)
5406 + struct ip_conntrack_protocol *proto;
5409 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
5410 + proto = __ip_ct_find_proto(skb->nh.iph->protocol);
5411 + if (proto->exp_matches_pkt)
5412 + ret = proto->exp_matches_pkt(exp, skb);
5417 +/* Do packet manipulations according to binding. */
5419 +do_bindings(struct ip_conntrack *ct,
5420 + enum ip_conntrack_info ctinfo,
5421 + struct ip_nat_info *info,
5422 + unsigned int hooknum,
5423 + struct sk_buff **pskb)
5426 + struct ip_nat_helper *helper;
5427 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
5428 + int proto = (*pskb)->nh.iph->protocol;
5430 + /* Need nat lock to protect against modification, but neither
5431 + conntrack (referenced) and helper (deleted with
5432 + synchronize_bh()) can vanish. */
5433 + READ_LOCK(&ip_nat_lock);
5434 + for (i = 0; i < info->num_manips; i++) {
5435 + if (info->manips[i].direction == dir
5436 + && info->manips[i].hooknum == hooknum) {
5437 + DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
5439 + info->manips[i].maniptype == IP_NAT_MANIP_SRC
5441 + NIPQUAD(info->manips[i].manip.ip),
5442 + htons(info->manips[i].manip.u.all));
5443 + if (!manip_pkt(proto, pskb, 0,
5444 + &info->manips[i].manip,
5445 + info->manips[i].maniptype)) {
5446 + READ_UNLOCK(&ip_nat_lock);
5451 + helper = info->helper;
5452 + READ_UNLOCK(&ip_nat_lock);
5455 + struct ip_conntrack_expect *exp = NULL;
5456 + struct list_head *cur_item;
5457 + int ret = NF_ACCEPT;
5458 + int helper_called = 0;
5460 + DEBUGP("do_bindings: helper existing for (%p)\n", ct);
5462 + /* Always defragged for helpers */
5463 + IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
5464 + & htons(IP_MF|IP_OFFSET)));
5466 + /* Have to grab read lock before sibling_list traversal */
5467 + READ_LOCK(&ip_conntrack_lock);
5468 + list_for_each(cur_item, &ct->sibling_list) {
5469 + exp = list_entry(cur_item, struct ip_conntrack_expect,
5472 + /* if this expectation is already established, skip */
5476 + if (exp_for_packet(exp, *pskb)) {
5477 + /* FIXME: May be true multiple times in the
5478 + * case of UDP!! */
5479 + DEBUGP("calling nat helper (exp=%p) for packet\n", exp);
5480 + ret = helper->help(ct, exp, info, ctinfo,
5482 + if (ret != NF_ACCEPT) {
5483 + READ_UNLOCK(&ip_conntrack_lock);
5486 + helper_called = 1;
5489 + /* Helper might want to manip the packet even when there is no
5490 + * matching expectation for this packet */
5491 + if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
5492 + DEBUGP("calling nat helper for packet without expectation\n");
5493 + ret = helper->help(ct, NULL, info, ctinfo,
5495 + if (ret != NF_ACCEPT) {
5496 + READ_UNLOCK(&ip_conntrack_lock);
5500 + READ_UNLOCK(&ip_conntrack_lock);
5502 + /* Adjust sequence number only once per packet
5503 + * (helper is called at all hooks) */
5504 + if (proto == IPPROTO_TCP
5505 + && (hooknum == NF_IP_POST_ROUTING
5506 + || hooknum == NF_IP_LOCAL_IN)) {
5507 + DEBUGP("ip_nat_core: adjusting sequence number\n");
5508 + /* future: put this in a l4-proto specific function,
5509 + * and call this function here. */
5510 + if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
5523 +icmp_reply_translation(struct sk_buff **pskb,
5524 + struct ip_conntrack *conntrack,
5525 + unsigned int hooknum,
5529 + struct icmphdr icmp;
5533 + struct ip_nat_info *info = &conntrack->nat.info;
5536 + if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside)))
5538 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
5540 + /* We're actually going to mangle it beyond trivial checksum
5541 + adjustment, so make sure the current checksum is correct. */
5542 + if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) {
5543 + hdrlen = (*pskb)->nh.iph->ihl * 4;
5544 + if ((u16)csum_fold(skb_checksum(*pskb, hdrlen,
5545 + (*pskb)->len - hdrlen, 0)))
5549 + /* Must be RELATED */
5550 + IP_NF_ASSERT((*pskb)->nfct
5551 + - (struct ip_conntrack *)(*pskb)->nfct->master
5554 + - (struct ip_conntrack *)(*pskb)->nfct->master
5555 + == IP_CT_RELATED+IP_CT_IS_REPLY);
5557 + /* Redirects on non-null nats must be dropped, else they'll
5558 + start talking to each other without our translation, and be
5559 + confused... --RR */
5560 + if (inside->icmp.type == ICMP_REDIRECT) {
5561 + /* Don't care about races here. */
5562 + if (info->initialized
5563 + != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
5564 + || info->num_manips != 0)
5568 + DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
5569 + *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
5570 + /* Note: May not be from a NAT'd host, but probably safest to
5571 + do translation always as if it came from the host itself
5572 + (even though a "host unreachable" coming from the host
5573 + itself is a bit weird).
5575 + More explanation: some people use NAT for anonymizing.
5576 + Also, CERT recommends dropping all packets from private IP
5577 + addresses (although ICMP errors from internal links with
5578 + such addresses are not too uncommon, as Alan Cox points
5581 + READ_LOCK(&ip_nat_lock);
5582 + for (i = 0; i < info->num_manips; i++) {
5583 + DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
5584 + i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?
5585 + "ORIG" : "REPLY", info->manips[i].hooknum);
5587 + if (info->manips[i].direction != dir)
5590 + /* Mapping the inner packet is just like a normal
5591 + packet, except it was never src/dst reversed, so
5592 + where we would normally apply a dst manip, we apply
5593 + a src, and vice versa. */
5594 + if (info->manips[i].hooknum == hooknum) {
5595 + DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
5596 + info->manips[i].maniptype == IP_NAT_MANIP_SRC
5598 + NIPQUAD(info->manips[i].manip.ip),
5599 + ntohs(info->manips[i].manip.u.udp.port));
5600 + if (!manip_pkt(inside->ip.protocol, pskb,
5601 + (*pskb)->nh.iph->ihl*4
5602 + + sizeof(inside->icmp),
5603 + &info->manips[i].manip,
5604 + !info->manips[i].maniptype))
5607 + /* Outer packet needs to have IP header NATed like
5610 + /* Use mapping to map outer packet: 0 give no
5611 + per-proto mapping */
5612 + DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
5613 + info->manips[i].maniptype == IP_NAT_MANIP_SRC
5615 + NIPQUAD(info->manips[i].manip.ip));
5616 + if (!manip_pkt(0, pskb, 0,
5617 + &info->manips[i].manip,
5618 + info->manips[i].maniptype))
5622 + READ_UNLOCK(&ip_nat_lock);
5624 + hdrlen = (*pskb)->nh.iph->ihl * 4;
5626 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
5628 + inside->icmp.checksum = 0;
5629 + inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
5630 + (*pskb)->len - hdrlen,
5635 + READ_UNLOCK(&ip_nat_lock);
5639 +int __init ip_nat_init(void)
5643 + /* Leave them the same for the moment. */
5644 + ip_nat_htable_size = ip_conntrack_htable_size;
5646 + /* One vmalloc for both hash tables */
5647 + bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
5651 + byipsproto = bysource + ip_nat_htable_size;
5653 + /* Sew in builtin protocols. */
5654 + WRITE_LOCK(&ip_nat_lock);
5655 + list_append(&protos, &ip_nat_protocol_tcp);
5656 + list_append(&protos, &ip_nat_protocol_udp);
5657 + list_append(&protos, &ip_nat_protocol_icmp);
5658 + WRITE_UNLOCK(&ip_nat_lock);
5660 + for (i = 0; i < ip_nat_htable_size; i++) {
5661 + INIT_LIST_HEAD(&bysource[i]);
5662 + INIT_LIST_HEAD(&byipsproto[i]);
5665 + /* FIXME: Man, this is a hack. <SIGH> */
5666 + IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
5667 + ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
5672 +/* Clear NAT section of all conntracks, in case we're loaded again. */
5673 +static int clean_nat(const struct ip_conntrack *i, void *data)
5675 + memset((void *)&i->nat, 0, sizeof(i->nat));
5679 +/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
5680 +void ip_nat_cleanup(void)
5682 + ip_ct_selective_cleanup(&clean_nat, NULL);
5683 + ip_conntrack_destroyed = NULL;
5686 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c
5687 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c 2004-03-04 06:16:38.000000000 +0000
5688 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c 2004-03-05 09:55:06.000000000 +0000
5689 @@ -150,9 +150,19 @@
5693 -/* Generic function for mangling variable-length address changes inside
5694 - * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
5695 - * command in FTP).
5697 + * ip_nat_mangle_tcp_packet - Mangle and potentially resize payload packet
5698 + * @skb: pointer to skb of packet on which we operate
5699 + * @ct: conntrack of the connection to which this packet belongs
5700 + * @ctinfo: conntrack_info of the connection to which this packet belongs
5701 + * @match_offset: offset in bytes where to-be-manipulated part starts
5702 + * @match_len: lenght of the to-be-manipulated part
5703 + * @rep_buffer: pointer to buffer containing replacement
5704 + * @rep_len: length of replacement
5706 + * Generic function for mangling fixed and variable-length changes inside
5707 + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command
5710 * Takes care about all the nasty sequence number changes, checksumming,
5711 * skb enlargement, ...
5712 @@ -198,16 +208,27 @@
5716 -/* Generic function for mangling variable-length address changes inside
5717 - * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
5718 - * command in the Amanda protocol)
5720 + * ip_nat_mangle_udp_packet - Mangle and potentially resize payload packet
5721 + * @skb: pointer to skb of packet on which we operate
5722 + * @ct: conntrack of the connection to which this packet belongs
5723 + * @ctinfo: conntrack_info of the connection to which this packet belongs
5724 + * @match_offset: offset in bytes where to-be-manipulated part starts
5725 + * @match_len: lenght of the to-be-manipulated part
5726 + * @rep_buffer: pointer to buffer containing replacement
5727 + * @rep_len: length of replacement
5729 + * Generic function for mangling fixed and variable-length changes inside
5730 + * NATed TCP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
5731 + * commad in the Amanda protocol)
5733 * Takes care about all the nasty sequence number changes, checksumming,
5734 * skb enlargement, ...
5736 - * XXX - This function could be merged with ip_nat_mangle_tcp_packet which
5737 - * should be fairly easy to do.
5739 + * FIXME: should be unified with ip_nat_mangle_tcp_packet!!
5744 ip_nat_mangle_udp_packet(struct sk_buff **pskb,
5745 struct ip_conntrack *ct,
5746 @@ -405,6 +426,13 @@
5747 return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
5751 + * ip_nat_helper_register - Register NAT application helper
5752 + * @me: structure describing the helper
5754 + * This function is called by NAT application helpers to register
5755 + * themselves with the NAT core.
5757 int ip_nat_helper_register(struct ip_nat_helper *me)
5760 @@ -431,6 +459,13 @@
5765 + * ip_nat_helper_unregister - Unregister NAT application helper
5766 + * @me: structure describing the helper
5768 + * This function is called by NAT application helpers to unregister
5769 + * themselves from the NAT core.
5771 void ip_nat_helper_unregister(struct ip_nat_helper *me)
5773 WRITE_LOCK(&ip_nat_lock);
5774 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c
5775 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c 2004-03-04 06:16:55.000000000 +0000
5776 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c 2004-03-05 09:55:06.000000000 +0000
5777 @@ -266,7 +266,13 @@
5781 -/* Protocol registration. */
5783 + * ip_nat_protocol_register - Register a layer 4 protocol helper
5784 + * @proto: structure describing this helper
5786 + * This function is called by NAT layer 4 protocol helpers to register
5787 + * themselvers with the NAT core.
5789 int ip_nat_protocol_register(struct ip_nat_protocol *proto)
5792 @@ -287,9 +293,16 @@
5796 -/* Noone stores the protocol anywhere; simply delete it. */
5798 + * ip_nat_protocol_unregister - Unregister a layer 4 protocol helper
5799 + * @proto: structure describing the helper
5801 + * This function is called by NAT layer 4 protocol helpers to
5802 + * unregister themselves from the NAT core.
5804 void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
5806 + /* Noone stores the protocol anywhere; simply delete it. */
5807 WRITE_LOCK(&ip_nat_lock);
5808 LIST_DELETE(&protos, proto);
5809 WRITE_UNLOCK(&ip_nat_lock);
5810 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
5811 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 00:00:00.000000000 +0000
5812 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-03-05 09:55:11.000000000 +0000
5815 + * Strip all IP options in the IP packet header.
5817 + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
5818 + * This software is distributed under GNU GPL v2, 1991
5821 +#include <linux/module.h>
5822 +#include <linux/skbuff.h>
5823 +#include <linux/ip.h>
5824 +#include <net/checksum.h>
5826 +#include <linux/netfilter_ipv4/ip_tables.h>
5828 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
5829 +MODULE_DESCRIPTION("Strip all options in IPv4 packets");
5830 +MODULE_LICENSE("GPL");
5832 +static unsigned int
5833 +target(struct sk_buff **pskb,
5834 + const struct net_device *in,
5835 + const struct net_device *out,
5836 + unsigned int hooknum,
5837 + const void *targinfo,
5840 + struct iphdr *iph;
5841 + struct sk_buff *skb;
5842 + struct ip_options *opt;
5843 + unsigned char *optiph;
5846 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
5850 + iph = (*pskb)->nh.iph;
5851 + optiph = skb->nh.raw;
5852 + l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
5854 + /* if no options in packet then nothing to clear. */
5855 + if (iph->ihl * 4 == sizeof(struct iphdr))
5856 + return IPT_CONTINUE;
5858 + /* else clear all options */
5859 + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
5860 + memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
5861 + opt = &(IPCB(skb)->opt);
5865 + skb->nfcache |= NFC_ALTERED;
5867 + return IPT_CONTINUE;
5871 +checkentry(const char *tablename,
5872 + const struct ipt_entry *e,
5874 + unsigned int targinfosize,
5875 + unsigned int hook_mask)
5877 + if (strcmp(tablename, "mangle")) {
5878 + printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
5881 + /* nothing else to check because no parameters */
5885 +static struct ipt_target ipt_ipv4optsstrip_reg = {
5886 + .name = "IPV4OPTSSTRIP",
5888 + .checkentry = checkentry,
5889 + .me = THIS_MODULE };
5891 +static int __init init(void)
5893 + return ipt_register_target(&ipt_ipv4optsstrip_reg);
5896 +static void __exit fini(void)
5898 + ipt_unregister_target(&ipt_ipv4optsstrip_reg);
5903 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_LOG.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_LOG.c
5904 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_LOG.c 2004-03-04 06:17:03.000000000 +0000
5905 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_LOG.c 2004-03-05 09:55:08.000000000 +0000
5907 #include <net/tcp.h>
5908 #include <net/route.h>
5910 +#include <linux/netfilter.h>
5911 #include <linux/netfilter_ipv4/ip_tables.h>
5912 #include <linux/netfilter_ipv4/ipt_LOG.h>
5915 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
5916 MODULE_DESCRIPTION("iptables syslog logging module");
5918 +static unsigned int nflog = 1;
5919 +MODULE_PARM(nflog, "i");
5920 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
5923 #define DEBUGP printk
5925 @@ -324,28 +329,25 @@
5926 /* maxlen = 230+ 91 + 230 + 252 = 803 */
5929 -static unsigned int
5930 -ipt_log_target(struct sk_buff **pskb,
5932 +ipt_log_packet(unsigned int hooknum,
5933 + const struct sk_buff *skb,
5934 const struct net_device *in,
5935 const struct net_device *out,
5936 - unsigned int hooknum,
5937 - const void *targinfo,
5939 + const struct ipt_log_info *loginfo,
5940 + const char *level_string,
5941 + const char *prefix)
5943 - const struct ipt_log_info *loginfo = targinfo;
5944 - char level_string[4] = "< >";
5946 - level_string[1] = '0' + (loginfo->level % 8);
5947 spin_lock_bh(&log_lock);
5948 printk(level_string);
5949 printk("%sIN=%s OUT=%s ",
5951 + prefix == NULL ? loginfo->prefix : prefix,
5953 out ? out->name : "");
5954 #ifdef CONFIG_BRIDGE_NETFILTER
5955 - if ((*pskb)->nf_bridge) {
5956 - struct net_device *physindev = (*pskb)->nf_bridge->physindev;
5957 - struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
5958 + if (skb->nf_bridge) {
5959 + struct net_device *physindev = skb->nf_bridge->physindev;
5960 + struct net_device *physoutdev = skb->nf_bridge->physoutdev;
5962 if (physindev && in != physindev)
5963 printk("PHYSIN=%s ", physindev->name);
5964 @@ -357,25 +359,56 @@
5966 /* MAC logging for input chain only. */
5968 - if ((*pskb)->dev && (*pskb)->dev->hard_header_len
5969 - && (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
5970 + if (skb->dev && skb->dev->hard_header_len
5971 + && skb->mac.raw != (void*)skb->nh.iph) {
5973 - unsigned char *p = (*pskb)->mac.raw;
5974 - for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
5975 + unsigned char *p = skb->mac.raw;
5976 + for (i = 0; i < skb->dev->hard_header_len; i++,p++)
5977 printk("%02x%c", *p,
5978 - i==(*pskb)->dev->hard_header_len - 1
5979 + i==skb->dev->hard_header_len - 1
5985 - dump_packet(loginfo, *pskb, 0);
5986 + dump_packet(loginfo, skb, 0);
5988 spin_unlock_bh(&log_lock);
5991 +static unsigned int
5992 +ipt_log_target(struct sk_buff **pskb,
5993 + const struct net_device *in,
5994 + const struct net_device *out,
5995 + unsigned int hooknum,
5996 + const void *targinfo,
5999 + const struct ipt_log_info *loginfo = targinfo;
6000 + char level_string[4] = "< >";
6002 + level_string[1] = '0' + (loginfo->level % 8);
6003 + ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
6005 return IPT_CONTINUE;
6009 +ipt_logfn(unsigned int hooknum,
6010 + const struct sk_buff *skb,
6011 + const struct net_device *in,
6012 + const struct net_device *out,
6013 + const char *prefix)
6015 + struct ipt_log_info loginfo = {
6017 + .logflags = IPT_LOG_MASK,
6021 + ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
6024 static int ipt_log_checkentry(const char *tablename,
6025 const struct ipt_entry *e,
6027 @@ -413,11 +446,18 @@
6029 static int __init init(void)
6031 - return ipt_register_target(&ipt_log_reg);
6032 + if (ipt_register_target(&ipt_log_reg))
6035 + nf_log_register(PF_INET, &ipt_logfn);
6040 static void __exit fini(void)
6043 + nf_log_unregister(PF_INET, &ipt_logfn);
6044 ipt_unregister_target(&ipt_log_reg);
6047 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_NOTRACK.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_NOTRACK.c
6048 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_NOTRACK.c 1970-01-01 00:00:00.000000000 +0000
6049 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_NOTRACK.c 2004-03-05 09:55:23.000000000 +0000
6051 +/* This is a module which is used for setting up fake conntracks
6052 + * on packets so that they are not seen by the conntrack/NAT code.
6054 +#include <linux/module.h>
6055 +#include <linux/skbuff.h>
6057 +#include <linux/netfilter_ipv4/ip_tables.h>
6058 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6060 +static unsigned int
6061 +target(struct sk_buff **pskb,
6062 + const struct net_device *in,
6063 + const struct net_device *out,
6064 + unsigned int hooknum,
6065 + const void *targinfo,
6068 + /* Previously seen (loopback)? Ignore. */
6069 + if ((*pskb)->nfct != NULL)
6070 + return IPT_CONTINUE;
6072 + /* Attach fake conntrack entry.
6073 + If there is a real ct entry correspondig to this packet,
6074 + it'll hang aroun till timing out. We don't deal with it
6075 + for performance reasons. JK */
6076 + (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
6077 + nf_conntrack_get((*pskb)->nfct);
6079 + return IPT_CONTINUE;
6083 +checkentry(const char *tablename,
6084 + const struct ipt_entry *e,
6086 + unsigned int targinfosize,
6087 + unsigned int hook_mask)
6089 + if (targinfosize != 0) {
6090 + printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
6095 + if (strcmp(tablename, "raw") != 0) {
6096 + printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
6103 +static struct ipt_target ipt_notrack_reg = {
6104 + .name = "NOTRACK",
6106 + .checkentry = checkentry,
6110 +static int __init init(void)
6112 + if (ipt_register_target(&ipt_notrack_reg))
6118 +static void __exit fini(void)
6120 + ipt_unregister_target(&ipt_notrack_reg);
6125 +MODULE_LICENSE("GPL");
6126 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c
6127 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 00:00:00.000000000 +0000
6128 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c 2004-03-05 09:55:14.000000000 +0000
6130 +/* TTL modification target for IP tables
6131 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
6133 + * Version: $Revision$
6135 + * This software is distributed under the terms of GNU GPL
6138 +#include <linux/module.h>
6139 +#include <linux/skbuff.h>
6140 +#include <linux/ip.h>
6141 +#include <net/checksum.h>
6143 +#include <linux/netfilter_ipv4/ip_tables.h>
6144 +#include <linux/netfilter_ipv4/ipt_TTL.h>
6146 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
6147 +MODULE_DESCRIPTION("IP tables TTL modification module");
6148 +MODULE_LICENSE("GPL");
6150 +static unsigned int
6151 +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
6152 + const struct net_device *out, unsigned int hooknum,
6153 + const void *targinfo, void *userinfo)
6155 + struct iphdr *iph;
6156 + const struct ipt_TTL_info *info = targinfo;
6157 + u_int16_t diffs[2];
6160 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
6163 + iph = (*pskb)->nh.iph;
6165 + switch (info->mode) {
6167 + new_ttl = info->ttl;
6170 + new_ttl = iph->ttl + info->ttl;
6171 + if (new_ttl > 255)
6175 + new_ttl = iph->ttl + info->ttl;
6180 + new_ttl = iph->ttl;
6184 + if (new_ttl != iph->ttl) {
6185 + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
6186 + iph->ttl = new_ttl;
6187 + diffs[1] = htons(((unsigned)iph->ttl) << 8);
6188 + iph->check = csum_fold(csum_partial((char *)diffs,
6190 + iph->check^0xFFFF));
6191 + (*pskb)->nfcache |= NFC_ALTERED;
6194 + return IPT_CONTINUE;
6197 +static int ipt_ttl_checkentry(const char *tablename,
6198 + const struct ipt_entry *e,
6200 + unsigned int targinfosize,
6201 + unsigned int hook_mask)
6203 + struct ipt_TTL_info *info = targinfo;
6205 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
6206 + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
6208 + IPT_ALIGN(sizeof(struct ipt_TTL_info)));
6212 + if (strcmp(tablename, "mangle")) {
6213 + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
6217 + if (info->mode > IPT_TTL_MAXMODE) {
6218 + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n",
6223 + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
6224 + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
6231 +static struct ipt_target ipt_TTL = {
6233 + .target = ipt_ttl_target,
6234 + .checkentry = ipt_ttl_checkentry,
6238 +static int __init init(void)
6240 + return ipt_register_target(&ipt_TTL);
6243 +static void __exit fini(void)
6245 + ipt_unregister_target(&ipt_TTL);
6250 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ULOG.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ULOG.c
6251 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ULOG.c 2004-03-04 06:16:42.000000000 +0000
6252 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ULOG.c 2004-03-05 09:55:08.000000000 +0000
6254 #include <linux/netlink.h>
6255 #include <linux/netdevice.h>
6256 #include <linux/mm.h>
6257 +#include <linux/netfilter.h>
6258 #include <linux/netfilter_ipv4/ip_tables.h>
6259 #include <linux/netfilter_ipv4/ipt_ULOG.h>
6260 #include <linux/netfilter_ipv4/lockhelp.h>
6262 MODULE_PARM(flushtimeout, "i");
6263 MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
6265 +static unsigned int nflog = 1;
6266 +MODULE_PARM(nflog, "i");
6267 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
6269 /* global data structures */
6272 @@ -157,17 +162,17 @@
6276 -static unsigned int ipt_ulog_target(struct sk_buff **pskb,
6277 - const struct net_device *in,
6278 - const struct net_device *out,
6279 - unsigned int hooknum,
6280 - const void *targinfo, void *userinfo)
6281 +static void ipt_ulog_packet(unsigned int hooknum,
6282 + const struct sk_buff *skb,
6283 + const struct net_device *in,
6284 + const struct net_device *out,
6285 + const struct ipt_ulog_info *loginfo,
6286 + const char *prefix)
6289 ulog_packet_msg_t *pm;
6290 size_t size, copy_len;
6291 struct nlmsghdr *nlh;
6292 - struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
6294 /* ffs == find first bit set, necessary because userspace
6295 * is already shifting groupnumber, but we need unshifted.
6298 /* calculate the size of the skb needed */
6299 if ((loginfo->copy_range == 0) ||
6300 - (loginfo->copy_range > (*pskb)->len)) {
6301 - copy_len = (*pskb)->len;
6302 + (loginfo->copy_range > skb->len)) {
6303 + copy_len = skb->len;
6305 copy_len = loginfo->copy_range;
6307 @@ -214,19 +219,21 @@
6309 /* copy hook, prefix, timestamp, payload, etc. */
6310 pm->data_len = copy_len;
6311 - pm->timestamp_sec = (*pskb)->stamp.tv_sec;
6312 - pm->timestamp_usec = (*pskb)->stamp.tv_usec;
6313 - pm->mark = (*pskb)->nfmark;
6314 + pm->timestamp_sec = skb->stamp.tv_sec;
6315 + pm->timestamp_usec = skb->stamp.tv_usec;
6316 + pm->mark = skb->nfmark;
6318 - if (loginfo->prefix[0] != '\0')
6319 + if (prefix != NULL)
6320 + strncpy(pm->prefix, prefix, sizeof(pm->prefix));
6321 + else if (loginfo->prefix[0] != '\0')
6322 strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
6324 *(pm->prefix) = '\0';
6326 if (in && in->hard_header_len > 0
6327 - && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
6328 + && skb->mac.raw != (void *) skb->nh.iph
6329 && in->hard_header_len <= ULOG_MAC_LEN) {
6330 - memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
6331 + memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
6332 pm->mac_len = in->hard_header_len;
6337 pm->outdev_name[0] = '\0';
6339 - /* copy_len <= (*pskb)->len, so can't fail. */
6340 - if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
6341 + /* copy_len <= skb->len, so can't fail. */
6342 + if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
6345 /* check if we are building multi-part messages */
6348 UNLOCK_BH(&ulog_lock);
6350 - return IPT_CONTINUE;
6355 PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
6356 @@ -276,8 +282,35 @@
6357 PRINTR("ipt_ULOG: Error building netlink message\n");
6359 UNLOCK_BH(&ulog_lock);
6362 +static unsigned int ipt_ulog_target(struct sk_buff **pskb,
6363 + const struct net_device *in,
6364 + const struct net_device *out,
6365 + unsigned int hooknum,
6366 + const void *targinfo, void *userinfo)
6368 + struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
6370 - return IPT_CONTINUE;
6371 + ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
6373 + return IPT_CONTINUE;
6376 +static void ipt_logfn(unsigned int hooknum,
6377 + const struct sk_buff *skb,
6378 + const struct net_device *in,
6379 + const struct net_device *out,
6380 + const char *prefix)
6382 + struct ipt_ulog_info loginfo = {
6383 + .nl_group = ULOG_DEFAULT_NLGROUP,
6385 + .qthreshold = ULOG_DEFAULT_QTHRESHOLD,
6389 + ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
6392 static int ipt_ulog_checkentry(const char *tablename,
6394 sock_release(nflognl->sk_socket);
6399 + nf_log_register(PF_INET, &ipt_logfn);
6406 DEBUGP("ipt_ULOG: cleanup_module\n");
6409 + nf_log_unregister(PF_INET, &ipt_logfn);
6410 ipt_unregister_target(&ipt_ulog_reg);
6411 sock_release(nflognl->sk_socket);
6413 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c
6414 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 00:00:00.000000000 +0000
6415 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c 2004-03-05 09:55:15.000000000 +0000
6418 + * netfilter module to limit the number of parallel tcp
6419 + * connections per IP address.
6420 + * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
6421 + * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
6422 + * only ignore TIME_WAIT or gone connections
6426 + * Kernel module to match connection tracking information.
6427 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
6429 +#include <linux/module.h>
6430 +#include <linux/skbuff.h>
6431 +#include <linux/list.h>
6432 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6433 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
6434 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
6435 +#include <linux/netfilter_ipv4/ip_tables.h>
6436 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
6440 +MODULE_LICENSE("GPL");
6442 +/* we'll save the tuples of all connections we care about */
6443 +struct ipt_connlimit_conn
6445 + struct list_head list;
6446 + struct ip_conntrack_tuple tuple;
6449 +struct ipt_connlimit_data {
6451 + struct list_head iphash[256];
6454 +static int ipt_iphash(u_int32_t addr)
6458 + hash = addr & 0xff;
6459 + hash ^= (addr >> 8) & 0xff;
6460 + hash ^= (addr >> 16) & 0xff;
6461 + hash ^= (addr >> 24) & 0xff;
6465 +static int count_them(struct ipt_connlimit_data *data,
6466 + u_int32_t addr, u_int32_t mask,
6467 + struct ip_conntrack *ct)
6470 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
6471 + "fin_wait", "time_wait", "close", "close_wait",
6472 + "last_ack", "listen" };
6474 + int addit = 1, matches = 0;
6475 + struct ip_conntrack_tuple tuple;
6476 + struct ip_conntrack_tuple_hash *found;
6477 + struct ipt_connlimit_conn *conn;
6478 + struct list_head *hash,*lh;
6480 + spin_lock(&data->lock);
6481 + tuple = ct->tuplehash[0].tuple;
6482 + hash = &data->iphash[ipt_iphash(addr & mask)];
6484 + /* check the saved connections */
6485 + for (lh = hash->next; lh != hash; lh = lh->next) {
6486 + conn = list_entry(lh,struct ipt_connlimit_conn,list);
6487 + found = ip_conntrack_find_get(&conn->tuple,ct);
6488 + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
6490 + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
6491 + /* Just to be sure we have it only once in the list.
6492 + We should'nt see tuples twice unless someone hooks this
6493 + into a table without "-p tcp --syn" */
6497 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
6498 + ipt_iphash(addr & mask),
6499 + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
6500 + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
6501 + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
6503 + if (NULL == found) {
6504 + /* this one is gone */
6506 + list_del(lh->next);
6510 + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
6511 + /* we don't care about connections which are
6512 + closed already -> ditch it */
6514 + list_del(lh->next);
6516 + nf_conntrack_put(&found->ctrack->infos[0]);
6519 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
6520 + /* same source IP address -> be counted! */
6523 + nf_conntrack_put(&found->ctrack->infos[0]);
6526 + /* save the new connection in our list */
6528 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
6529 + ipt_iphash(addr & mask),
6530 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
6531 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
6533 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
6536 + memset(conn,0,sizeof(*conn));
6537 + INIT_LIST_HEAD(&conn->list);
6538 + conn->tuple = tuple;
6539 + list_add(&conn->list,hash);
6542 + spin_unlock(&data->lock);
6547 +match(const struct sk_buff *skb,
6548 + const struct net_device *in,
6549 + const struct net_device *out,
6550 + const void *matchinfo,
6554 + const struct ipt_connlimit_info *info = matchinfo;
6555 + int connections, match;
6556 + struct ip_conntrack *ct;
6557 + enum ip_conntrack_info ctinfo;
6559 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
6561 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
6565 + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
6566 + if (-1 == connections) {
6567 + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
6568 + *hotdrop = 1; /* let's free some memory :-) */
6571 + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
6573 + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
6574 + "connections=%d limit=%d match=%s\n",
6575 + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
6576 + connections, info->limit, match ? "yes" : "no");
6582 +static int check(const char *tablename,
6583 + const struct ipt_ip *ip,
6585 + unsigned int matchsize,
6586 + unsigned int hook_mask)
6588 + struct ipt_connlimit_info *info = matchinfo;
6592 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
6595 + /* refuse anything but tcp */
6596 + if (ip->proto != IPPROTO_TCP)
6599 + /* init private data */
6600 + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
6601 + spin_lock_init(&(info->data->lock));
6602 + for (i = 0; i < 256; i++)
6603 + INIT_LIST_HEAD(&(info->data->iphash[i]));
6608 +static void destroy(void *matchinfo, unsigned int matchinfosize)
6610 + struct ipt_connlimit_info *info = matchinfo;
6611 + struct ipt_connlimit_conn *conn;
6612 + struct list_head *hash;
6616 + for (i = 0; i < 256; i++) {
6617 + hash = &(info->data->iphash[i]);
6618 + while (hash != hash->next) {
6619 + conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
6620 + list_del(hash->next);
6624 + kfree(info->data);
6627 +static struct ipt_match connlimit_match = {
6628 + .name = "connlimit",
6630 + .checkentry = &check,
6631 + .destroy = &destroy,
6635 +static int __init init(void)
6637 + return ipt_register_match(&connlimit_match);
6640 +static void __exit fini(void)
6642 + ipt_unregister_match(&connlimit_match);
6647 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c
6648 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c 2004-03-04 06:17:04.000000000 +0000
6649 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c 2004-03-05 09:55:23.000000000 +0000
6652 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
6655 - statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6657 - statebit = IPT_CONNTRACK_STATE_INVALID;
6659 + if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
6660 + statebit = IPT_CONNTRACK_STATE_UNTRACKED;
6662 + statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6664 + statebit = IPT_CONNTRACK_STATE_INVALID;
6666 if(sinfo->flags & IPT_CONNTRACK_STATE) {
6668 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
6669 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c.orig
6670 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c.orig 1970-01-01 00:00:00.000000000 +0000
6671 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c.orig 2004-03-04 06:17:04.000000000 +0000
6673 +/* Kernel module to match connection tracking information.
6674 + * Superset of Rusty's minimalistic state match.
6676 + * (C) 2001 Marc Boucher (marc@mbsi.ca).
6678 + * This program is free software; you can redistribute it and/or modify
6679 + * it under the terms of the GNU General Public License version 2 as
6680 + * published by the Free Software Foundation.
6683 +#include <linux/module.h>
6684 +#include <linux/skbuff.h>
6685 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6686 +#include <linux/netfilter_ipv4/ip_tables.h>
6687 +#include <linux/netfilter_ipv4/ipt_conntrack.h>
6689 +MODULE_LICENSE("GPL");
6690 +MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
6691 +MODULE_DESCRIPTION("iptables connection tracking match module");
6694 +match(const struct sk_buff *skb,
6695 + const struct net_device *in,
6696 + const struct net_device *out,
6697 + const void *matchinfo,
6701 + const struct ipt_conntrack_info *sinfo = matchinfo;
6702 + struct ip_conntrack *ct;
6703 + enum ip_conntrack_info ctinfo;
6704 + unsigned int statebit;
6706 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
6708 +#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
6711 + statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6713 + statebit = IPT_CONNTRACK_STATE_INVALID;
6715 + if(sinfo->flags & IPT_CONNTRACK_STATE) {
6717 + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
6718 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
6719 + statebit |= IPT_CONNTRACK_STATE_SNAT;
6721 + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
6722 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
6723 + statebit |= IPT_CONNTRACK_STATE_DNAT;
6726 + if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
6730 + if(sinfo->flags & IPT_CONNTRACK_PROTO) {
6731 + if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
6735 + if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
6736 + 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))
6740 + if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
6741 + 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))
6745 + if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
6746 + 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))
6750 + if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
6751 + 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))
6755 + if(sinfo->flags & IPT_CONNTRACK_STATUS) {
6756 + if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
6760 + if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
6761 + unsigned long expires;
6766 + expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
6768 + if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
6775 +static int check(const char *tablename,
6776 + const struct ipt_ip *ip,
6778 + unsigned int matchsize,
6779 + unsigned int hook_mask)
6781 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
6787 +static struct ipt_match conntrack_match = {
6788 + .name = "conntrack",
6790 + .checkentry = &check,
6791 + .me = THIS_MODULE,
6794 +static int __init init(void)
6796 + need_ip_conntrack();
6797 + return ipt_register_match(&conntrack_match);
6800 +static void __exit fini(void)
6802 + ipt_unregister_match(&conntrack_match);
6807 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c
6808 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 00:00:00.000000000 +0000
6809 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c 2004-03-05 09:55:17.000000000 +0000
6811 +/* iptables match extension to limit the number of packets per second
6812 + * seperately for each destination.
6814 + * (C) 2003 by Harald Welte <laforge@netfilter.org>
6818 + * Development of this code was funded by Astaro AG, http://www.astaro.com/
6820 + * based on ipt_limit.c by:
6821 + * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
6822 + * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
6823 + * Rusty Russell <rusty@rustcorp.com.au>
6825 + * The general idea is to create a hash table for every dstip and have a
6826 + * seperate limit counter per tuple. This way you can do something like 'limit
6827 + * the number of syn packets for each of my internal addresses.
6829 + * Ideally this would just be implemented as a general 'hash' match, which would
6830 + * allow us to attach any iptables target to it's hash buckets. But this is
6831 + * not possible in the current iptables architecture. As always, pkttables for
6832 + * 2.7.x will help ;)
6834 +#include <linux/module.h>
6835 +#include <linux/skbuff.h>
6836 +#include <linux/spinlock.h>
6837 +#include <linux/random.h>
6838 +#include <linux/jhash.h>
6839 +#include <linux/slab.h>
6840 +#include <linux/vmalloc.h>
6841 +#include <linux/tcp.h>
6842 +#include <linux/udp.h>
6843 +#include <linux/proc_fs.h>
6844 +#include <linux/seq_file.h>
6846 +#define ASSERT_READ_LOCK(x)
6847 +#define ASSERT_WRITE_LOCK(x)
6848 +#include <linux/netfilter_ipv4/lockhelp.h>
6849 +#include <linux/netfilter_ipv4/listhelp.h>
6851 +#include <linux/netfilter_ipv4/ip_tables.h>
6852 +#include <linux/netfilter_ipv4/ipt_dstlimit.h>
6854 +/* FIXME: this is just for IP_NF_ASSERRT */
6855 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6857 +#define MS2JIFFIES(x) ((x*HZ)/1000)
6859 +MODULE_LICENSE("GPL");
6860 +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
6861 +MODULE_DESCRIPTION("iptables match for limiting per destination");
6863 +/* need to declare this at the top */
6864 +static struct proc_dir_entry *dstlimit_procdir;
6865 +static struct file_operations dl_file_ops;
6867 +/* hash table crap */
6869 +struct dsthash_dst {
6875 +struct dsthash_ent {
6876 + /* static / read-only parts in the beginning */
6877 + struct list_head list;
6878 + struct dsthash_dst dst;
6880 + /* modified structure members in the end */
6881 + unsigned long expires; /* precalculated expiry time */
6883 + unsigned long prev; /* last modification */
6885 + u_int32_t credit_cap, cost;
6889 +struct ipt_dstlimit_htable {
6890 + struct list_head list; /* global list of all htables */
6893 + struct dstlimit_cfg cfg; /* config */
6895 + /* used internally */
6896 + spinlock_t lock; /* lock for list_head */
6897 + u_int32_t rnd; /* random seed for hash */
6898 + struct timer_list timer; /* timer for gc */
6899 + atomic_t count; /* number entries in table */
6901 + /* seq_file stuff */
6902 + struct proc_dir_entry *pde;
6904 + struct list_head hash[0]; /* hashtable itself */
6907 +DECLARE_RWLOCK(dstlimit_lock); /* protects htables list */
6908 +static LIST_HEAD(dstlimit_htables);
6909 +static kmem_cache_t *dstlimit_cachep;
6911 +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
6913 + return (ent->dst.dst_ip == b->dst_ip
6914 + && ent->dst.port == b->port
6915 + && ent->dst.src_ip == b->src_ip);
6918 +static inline u_int32_t
6919 +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
6921 + return (jhash_3words(dst->dst_ip, dst->port,
6922 + dst->src_ip, ht->rnd) % ht->cfg.size);
6925 +static inline struct dsthash_ent *
6926 +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
6928 + struct dsthash_ent *ent;
6929 + u_int32_t hash = hash_dst(ht, dst);
6930 + MUST_BE_LOCKED(&ht->lock);
6931 + ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
6935 +/* allocate dsthash_ent, initialize dst, put in htable and lock it */
6936 +static struct dsthash_ent *
6937 +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
6939 + struct dsthash_ent *ent;
6941 + /* initialize hash with random val at the time we allocate
6942 + * the first hashtable entry */
6944 + get_random_bytes(&ht->rnd, 4);
6946 + if (ht->cfg.max &&
6947 + atomic_read(&ht->count) >= ht->cfg.max) {
6948 + /* FIXME: do something. question is what.. */
6949 + if (net_ratelimit())
6950 + printk(KERN_WARNING
6951 + "ipt_dstlimit: max count of %u reached\n",
6956 + ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
6958 + if (net_ratelimit())
6960 + "ipt_dstlimit: can't allocate dsthash_ent\n");
6964 + atomic_inc(&ht->count);
6966 + ent->dst.dst_ip = dst->dst_ip;
6967 + ent->dst.port = dst->port;
6968 + ent->dst.src_ip = dst->src_ip;
6970 + list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
6976 +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
6978 + MUST_BE_LOCKED(&ht->lock);
6980 + list_del(&ent->list);
6981 + kmem_cache_free(dstlimit_cachep, ent);
6982 + atomic_dec(&ht->count);
6984 +static void htable_gc(unsigned long htlong);
6986 +static int htable_create(struct ipt_dstlimit_info *minfo)
6989 + unsigned int size;
6990 + struct ipt_dstlimit_htable *hinfo;
6992 + if (minfo->cfg.size)
6993 + size = minfo->cfg.size;
6995 + size = (((num_physpages << PAGE_SHIFT) / 16384)
6996 + / sizeof(struct list_head));
6997 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
7002 + /* FIXME: don't use vmalloc() here or anywhere else -HW */
7003 + hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
7004 + + (sizeof(struct list_head) * size));
7006 + printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
7009 + minfo->hinfo = hinfo;
7011 + /* copy match config into hashtable config */
7012 + memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
7013 + hinfo->cfg.size = size;
7014 + if (!hinfo->cfg.max)
7015 + hinfo->cfg.max = 8 * hinfo->cfg.size;
7016 + else if (hinfo->cfg.max < hinfo->cfg.size)
7017 + hinfo->cfg.max = hinfo->cfg.size;
7019 + for (i = 0; i < hinfo->cfg.size; i++)
7020 + INIT_LIST_HEAD(&hinfo->hash[i]);
7022 + atomic_set(&hinfo->count, 0);
7023 + atomic_set(&hinfo->use, 1);
7025 + hinfo->lock = SPIN_LOCK_UNLOCKED;
7026 + hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
7027 + if (!hinfo->pde) {
7031 + hinfo->pde->proc_fops = &dl_file_ops;
7032 + hinfo->pde->data = hinfo;
7034 + init_timer(&hinfo->timer);
7035 + hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
7036 + hinfo->timer.data = (unsigned long )hinfo;
7037 + hinfo->timer.function = htable_gc;
7038 + add_timer(&hinfo->timer);
7040 + WRITE_LOCK(&dstlimit_lock);
7041 + list_add(&hinfo->list, &dstlimit_htables);
7042 + WRITE_UNLOCK(&dstlimit_lock);
7047 +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
7052 +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
7054 + return (jiffies >= he->expires);
7057 +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
7058 + int (*select)(struct ipt_dstlimit_htable *ht,
7059 + struct dsthash_ent *he))
7063 + IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
7065 + /* lock hash table and iterate over it */
7066 + LOCK_BH(&ht->lock);
7067 + for (i = 0; i < ht->cfg.size; i++) {
7068 + struct dsthash_ent *dh, *n;
7069 + list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
7070 + if ((*select)(ht, dh))
7071 + __dsthash_free(ht, dh);
7074 + UNLOCK_BH(&ht->lock);
7077 +/* hash table garbage collector, run by timer */
7078 +static void htable_gc(unsigned long htlong)
7080 + struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
7082 + htable_selective_cleanup(ht, select_gc);
7084 + /* re-add the timer accordingly */
7085 + ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
7086 + add_timer(&ht->timer);
7089 +static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
7091 + /* remove timer, if it is pending */
7092 + if (timer_pending(&hinfo->timer))
7093 + del_timer(&hinfo->timer);
7095 + /* remove proc entry */
7096 + remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
7098 + htable_selective_cleanup(hinfo, select_all);
7102 +static struct ipt_dstlimit_htable *htable_find_get(char *name)
7104 + struct ipt_dstlimit_htable *hinfo;
7106 + READ_LOCK(&dstlimit_lock);
7107 + list_for_each_entry(hinfo, &dstlimit_htables, list) {
7108 + if (!strcmp(name, hinfo->pde->name)) {
7109 + atomic_inc(&hinfo->use);
7110 + READ_UNLOCK(&dstlimit_lock);
7114 + READ_UNLOCK(&dstlimit_lock);
7119 +static void htable_put(struct ipt_dstlimit_htable *hinfo)
7121 + if (atomic_dec_and_test(&hinfo->use)) {
7122 + WRITE_LOCK(&dstlimit_lock);
7123 + list_del(&hinfo->list);
7124 + WRITE_UNLOCK(&dstlimit_lock);
7125 + htable_destroy(hinfo);
7130 +/* The algorithm used is the Simple Token Bucket Filter (TBF)
7131 + * see net/sched/sch_tbf.c in the linux source tree
7134 +/* Rusty: This is my (non-mathematically-inclined) understanding of
7135 + this algorithm. The `average rate' in jiffies becomes your initial
7136 + amount of credit `credit' and the most credit you can ever have
7137 + `credit_cap'. The `peak rate' becomes the cost of passing the
7140 + `prev' tracks the last packet hit: you gain one credit per jiffy.
7141 + If you get credit balance more than this, the extra credit is
7142 + discarded. Every time the match passes, you lose `cost' credits;
7143 + if you don't have that many, the test fails.
7145 + See Alexey's formal explanation in net/sched/sch_tbf.c.
7147 + To get the maximum range, we multiply by this factor (ie. you get N
7148 + credits per jiffy). We want to allow a rate as low as 1 per day
7149 + (slowest userspace tool allows), which means
7150 + CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
7152 +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
7154 +/* Repeated shift and or gives us all 1s, final shift and add 1 gives
7155 + * us the power of 2 below the theoretical max, so GCC simply does a
7157 +#define _POW2_BELOW2(x) ((x)|((x)>>1))
7158 +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
7159 +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
7160 +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
7161 +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
7162 +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
7164 +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
7166 +/* Precision saver. */
7167 +static inline u_int32_t
7168 +user2credits(u_int32_t user)
7170 + /* If multiplying would overflow... */
7171 + if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
7172 + /* Divide first. */
7173 + return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
7175 + return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
7178 +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
7180 + dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now))
7181 + * CREDITS_PER_JIFFY;
7182 + if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
7183 + dh->rateinfo.credit = dh->rateinfo.credit_cap;
7187 +dstlimit_match(const struct sk_buff *skb,
7188 + const struct net_device *in,
7189 + const struct net_device *out,
7190 + const void *matchinfo,
7194 + struct ipt_dstlimit_info *r =
7195 + ((struct ipt_dstlimit_info *)matchinfo)->u.master;
7196 + struct ipt_dstlimit_htable *hinfo = r->hinfo;
7197 + unsigned long now = jiffies;
7198 + struct dsthash_ent *dh;
7199 + struct dsthash_dst dst;
7201 + memset(&dst, 0, sizeof(dst));
7203 + /* dest ip is always in hash */
7204 + dst.dst_ip = skb->nh.iph->daddr;
7206 + /* source ip only if respective hashmode, otherwise set to
7208 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
7209 + dst.src_ip = skb->nh.iph->saddr;
7211 + /* dest port only if respective mode */
7212 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
7215 + /* Must not be a fragment. */
7219 + /* Must be big enough to read ports (both UDP and TCP have
7220 + them at the start). */
7221 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
7222 + /* We've been asked to examine this packet, and we
7223 + can't. Hence, no choice but to drop. */
7228 + switch (skb->nh.iph->protocol) {
7229 + struct tcphdr *th;
7230 + struct udphdr *uh;
7232 + th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
7233 + dst.port = th->dest;
7236 + uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
7237 + dst.port = uh->dest;
7244 + LOCK_BH(&hinfo->lock);
7245 + dh = __dsthash_find(hinfo, &dst);
7247 + dh = __dsthash_alloc_init(hinfo, &dst);
7250 + /* enomem... don't match == DROP */
7251 + if (net_ratelimit())
7252 + printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
7253 + UNLOCK_BH(&hinfo->lock);
7257 + dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
7259 + dh->rateinfo.prev = jiffies;
7260 + dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
7261 + hinfo->cfg.burst);
7262 + dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
7263 + hinfo->cfg.burst);
7264 + dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
7266 + UNLOCK_BH(&hinfo->lock);
7270 + /* update expiration timeout */
7271 + dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
7273 + rateinfo_recalc(dh, now);
7274 + if (dh->rateinfo.credit >= dh->rateinfo.cost) {
7275 + /* We're underlimit. */
7276 + dh->rateinfo.credit -= dh->rateinfo.cost;
7277 + UNLOCK_BH(&hinfo->lock);
7281 + UNLOCK_BH(&hinfo->lock);
7283 + /* default case: we're overlimit, thus don't match */
7288 +dstlimit_checkentry(const char *tablename,
7289 + const struct ipt_ip *ip,
7291 + unsigned int matchsize,
7292 + unsigned int hook_mask)
7294 + struct ipt_dstlimit_info *r = matchinfo;
7296 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
7299 + /* Check for overflow. */
7300 + if (r->cfg.burst == 0
7301 + || user2credits(r->cfg.avg * r->cfg.burst) <
7302 + user2credits(r->cfg.avg)) {
7303 + printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
7304 + r->cfg.avg, r->cfg.burst);
7308 + if (r->cfg.mode == 0
7309 + || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
7310 + |IPT_DSTLIMIT_HASH_DIP
7311 + |IPT_DSTLIMIT_HASH_SIP))
7314 + if (!r->cfg.gc_interval)
7317 + if (!r->cfg.expire)
7320 + r->hinfo = htable_find_get(r->name);
7321 + if (!r->hinfo && (htable_create(r) != 0)) {
7325 + /* Ugly hack: For SMP, we only want to use one set */
7332 +dstlimit_destroy(void *matchinfo, unsigned int matchsize)
7334 + struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
7336 + htable_put(r->hinfo);
7339 +static struct ipt_match ipt_dstlimit = {
7340 + .list = { .prev = NULL, .next = NULL },
7341 + .name = "dstlimit",
7342 + .match = dstlimit_match,
7343 + .checkentry = dstlimit_checkentry,
7344 + .destroy = dstlimit_destroy,
7350 +static void *dl_seq_start(struct seq_file *s, loff_t *pos)
7352 + struct proc_dir_entry *pde = s->private;
7353 + struct ipt_dstlimit_htable *htable = pde->data;
7354 + unsigned int *bucket;
7356 + LOCK_BH(&htable->lock);
7357 + if (*pos >= htable->cfg.size)
7360 + bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
7362 + return ERR_PTR(-ENOMEM);
7368 +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
7370 + struct proc_dir_entry *pde = s->private;
7371 + struct ipt_dstlimit_htable *htable = pde->data;
7372 + unsigned int *bucket = (unsigned int *)v;
7374 + *pos = ++(*bucket);
7375 + if (*pos >= htable->cfg.size) {
7382 +static void dl_seq_stop(struct seq_file *s, void *v)
7384 + struct proc_dir_entry *pde = s->private;
7385 + struct ipt_dstlimit_htable *htable = pde->data;
7386 + unsigned int *bucket = (unsigned int *)v;
7390 + UNLOCK_BH(&htable->lock);
7393 +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
7395 + /* recalculate to show accurate numbers */
7396 + rateinfo_recalc(ent, jiffies);
7398 + return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
7399 + (ent->expires - jiffies)/HZ,
7400 + NIPQUAD(ent->dst.src_ip),
7401 + NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
7402 + ent->rateinfo.credit, ent->rateinfo.credit_cap,
7403 + ent->rateinfo.cost);
7406 +static int dl_seq_show(struct seq_file *s, void *v)
7408 + struct proc_dir_entry *pde = s->private;
7409 + struct ipt_dstlimit_htable *htable = pde->data;
7410 + unsigned int *bucket = (unsigned int *)v;
7412 + if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
7413 + struct dsthash_ent *, s)) {
7414 + /* buffer was filled and unable to print that tuple */
7420 +static struct seq_operations dl_seq_ops = {
7421 + .start = dl_seq_start,
7422 + .next = dl_seq_next,
7423 + .stop = dl_seq_stop,
7424 + .show = dl_seq_show
7427 +static int dl_proc_open(struct inode *inode, struct file *file)
7429 + int ret = seq_open(file, &dl_seq_ops);
7432 + struct seq_file *sf = file->private_data;
7433 + sf->private = PDE(inode);
7438 +static struct file_operations dl_file_ops = {
7439 + .owner = THIS_MODULE,
7440 + .open = dl_proc_open,
7442 + .llseek = seq_lseek,
7443 + .release = seq_release
7446 +static int init_or_fini(int fini)
7453 + if (ipt_register_match(&ipt_dstlimit)) {
7455 + goto cleanup_nothing;
7458 + /* FIXME: do we really want HWCACHE_ALIGN since our objects are
7459 + * quite small ? */
7460 + dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
7461 + sizeof(struct dsthash_ent), 0,
7462 + SLAB_HWCACHE_ALIGN, NULL, NULL);
7463 + if (!dstlimit_cachep) {
7464 + printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
7466 + goto cleanup_unreg_match;
7469 + dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
7470 + if (!dstlimit_procdir) {
7471 + printk(KERN_ERR "Unable to create proc dir entry\n");
7473 + goto cleanup_free_slab;
7479 + remove_proc_entry("ipt_dstlimit", proc_net);
7481 + kmem_cache_destroy(dstlimit_cachep);
7482 +cleanup_unreg_match:
7483 + ipt_unregister_match(&ipt_dstlimit);
7489 +static int __init init(void)
7491 + return init_or_fini(0);
7494 +static void __exit fini(void)
7501 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c
7502 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
7503 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c 2004-03-05 09:55:18.000000000 +0000
7506 + * This module implements a simple TSK FLC
7507 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
7508 + * to limit , in an adaptive and flexible way , the packet rate crossing
7509 + * a given stream . It serves as an initial and very simple (but effective)
7510 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
7511 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
7512 + * into our code in a precise , adaptive and efficient manner.
7513 + * The goal is very similar to that of "limit" match , but using techniques of
7514 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
7515 + * avoiding over and undershoots - and stuff like that .
7518 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
7519 + * 2002-08-17 : Changed to eliminate floating point operations .
7520 + * 2002-08-23 : Coding style changes .
7523 +#include <linux/module.h>
7524 +#include <linux/skbuff.h>
7525 +#include <linux/ip.h>
7526 +#include <linux/random.h>
7527 +#include <net/tcp.h>
7528 +#include <linux/spinlock.h>
7529 +#include <linux/netfilter_ipv4/ip_tables.h>
7530 +#include <linux/netfilter_ipv4/ipt_fuzzy.h>
7533 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
7534 + Expressed in percentage
7537 +#define PAR_LOW 1/100
7540 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
7542 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
7543 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
7544 +MODULE_LICENSE("GPL");
7546 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7554 + return ( (100*(tx-mini)) / (maxi-mini) );
7557 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7565 + return ( (100*( maxi - tx )) / ( maxi - mini ) );
7569 +ipt_fuzzy_match(const struct sk_buff *pskb,
7570 + const struct net_device *in,
7571 + const struct net_device *out,
7572 + const void *matchinfo,
7576 + /* From userspace */
7578 + struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
7580 + u_int8_t random_number;
7581 + unsigned long amount;
7582 + u_int8_t howhigh, howlow;
7585 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
7587 + info->bytes_total += pskb->len;
7588 + info->packets_total++;
7590 + info->present_time = jiffies;
7592 + if (info->present_time >= info->previous_time)
7593 + amount = info->present_time - info->previous_time;
7595 + /* There was a transition : I choose to re-sample
7596 + and keep the old acceptance rate...
7600 + info->previous_time = info->present_time;
7601 + info->bytes_total = info->packets_total = 0;
7604 + if (amount > HZ/10) /* More than 100 ms elapsed ... */
7607 + info->mean_rate = (u_int32_t) ((HZ*info->packets_total) \
7610 + info->previous_time = info->present_time;
7611 + info->bytes_total = info->packets_total = 0;
7613 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
7614 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
7616 + info->acceptance_rate = (u_int8_t) \
7617 + (howhigh*PAR_LOW + PAR_HIGH*howlow);
7619 + /* In fact , the above defuzzification would require a denominator
7620 + proportional to (howhigh+howlow) but , in this particular case ,
7621 + that expression is constant .
7622 + An imediate consequence is that it isn't necessary to call
7623 + both mf_high and mf_low - but to keep things understandable ,
7628 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
7631 + if ( info->acceptance_rate < 100 )
7633 + get_random_bytes((void *)(&random_number), 1);
7635 + /* If within the acceptance , it can pass => don't match */
7636 + if (random_number <= (255 * info->acceptance_rate) / 100)
7639 + return 1; /* It can't pass ( It matches ) */
7642 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
7647 +ipt_fuzzy_checkentry(const char *tablename,
7648 + const struct ipt_ip *e,
7650 + unsigned int matchsize,
7651 + unsigned int hook_mask)
7654 + const struct ipt_fuzzy_info *info = matchinfo;
7656 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
7657 + printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
7658 + IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
7662 + if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
7663 + || (info->minimum_rate >= info->maximum_rate )) {
7664 + printk("ipt_fuzzy: BAD limits , please verify !!!\n");
7671 +static struct ipt_match ipt_fuzzy_reg = {
7673 + .match = ipt_fuzzy_match,
7674 + .checkentry = ipt_fuzzy_checkentry,
7678 +static int __init init(void)
7680 + return ipt_register_match(&ipt_fuzzy_reg);
7683 +static void __exit fini(void)
7685 + ipt_unregister_match(&ipt_fuzzy_reg);
7690 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c
7691 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c 1970-01-01 00:00:00.000000000 +0000
7692 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c 2004-03-05 09:55:19.000000000 +0000
7695 + This is a module which is used to match ipv4 options.
7696 + This file is distributed under the terms of the GNU General Public
7697 + License (GPL). Copies of the GPL can be obtained from:
7698 + ftp://prep.ai.mit.edu/pub/gnu/GPL
7700 + 11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
7701 + 12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
7702 + 12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
7703 + 18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
7704 + 19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
7707 +#include <linux/module.h>
7708 +#include <linux/skbuff.h>
7709 +#include <net/ip.h>
7711 +#include <linux/netfilter_ipv4/ip_tables.h>
7712 +#include <linux/netfilter_ipv4/ipt_ipv4options.h>
7714 +MODULE_LICENSE("GPL");
7715 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
7718 +match(const struct sk_buff *skb,
7719 + const struct net_device *in,
7720 + const struct net_device *out,
7721 + const void *matchinfo,
7725 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
7726 + const struct iphdr *iph = skb->nh.iph;
7727 + const struct ip_options *opt;
7729 + if (iph->ihl * 4 == sizeof(struct iphdr)) {
7730 + /* No options, so we match only the "DONTs" and the "IGNOREs" */
7732 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
7733 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
7734 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
7735 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
7736 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
7737 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
7742 + if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
7743 + /* there are options, and we don't need to care which one */
7746 + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
7747 + /* there are options but we don't want any ! */
7752 + opt = &(IPCB(skb)->opt);
7754 + /* source routing */
7755 + if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
7756 + if (!((opt->srr) & (opt->is_strictroute)))
7759 + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
7760 + if (!((opt->srr) & (!opt->is_strictroute)))
7763 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
7767 + /* record route */
7768 + if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
7772 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
7777 + if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
7781 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
7785 + /* router-alert option */
7786 + if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
7787 + if (!opt->router_alert)
7790 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
7791 + if (opt->router_alert)
7800 +checkentry(const char *tablename,
7801 + const struct ipt_ip *ip,
7803 + unsigned int matchsize,
7804 + unsigned int hook_mask)
7806 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
7807 + /* Check the size */
7808 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
7810 + /* Now check the coherence of the data ... */
7811 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
7812 + (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
7813 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
7814 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
7815 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
7816 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
7817 + return 0; /* opposites */
7818 + if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
7819 + (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
7820 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
7821 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
7822 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
7823 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
7824 + ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
7825 + return 0; /* opposites */
7826 + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
7827 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
7828 + return 0; /* cannot match in the same time loose and strict source routing */
7829 + if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
7830 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
7831 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
7832 + return 0; /* opposites */
7833 + if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
7834 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
7835 + return 0; /* opposites */
7836 + if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
7837 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
7838 + return 0; /* opposites */
7839 + if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
7840 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
7841 + return 0; /* opposites */
7843 + /* everything looks ok. */
7847 +static struct ipt_match ipv4options_match = {
7848 + .name = "ipv4options",
7850 + .checkentry = checkentry,
7854 +static int __init init(void)
7856 + return ipt_register_match(&ipv4options_match);
7859 +static void __exit fini(void)
7861 + ipt_unregister_match(&ipv4options_match);
7866 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c
7867 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 00:00:00.000000000 +0000
7868 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c 2004-03-05 09:55:20.000000000 +0000
7870 +/* Kernel module to match one of a list of TCP/UDP ports: ports are in
7871 + the same place so we can treat them as equal. */
7872 +#include <linux/module.h>
7873 +#include <linux/types.h>
7874 +#include <linux/udp.h>
7875 +#include <linux/skbuff.h>
7877 +#include <linux/netfilter_ipv4/ipt_mport.h>
7878 +#include <linux/netfilter_ipv4/ip_tables.h>
7880 +MODULE_LICENSE("GPL");
7883 +#define duprintf(format, args...) printk(format , ## args)
7885 +#define duprintf(format, args...)
7888 +/* Returns 1 if the port is matched by the test, 0 otherwise. */
7890 +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
7894 + u_int16_t pflags = minfo->pflags;
7895 + for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
7899 + && minfo->ports[i] == 65535)
7902 + s = minfo->ports[i];
7905 + e = minfo->ports[++i];
7910 + if (minfo->flags & IPT_MPORT_SOURCE
7911 + && src >= s && src <= e)
7914 + if (minfo->flags & IPT_MPORT_DESTINATION
7915 + && dst >= s && dst <= e)
7923 +match(const struct sk_buff *skb,
7924 + const struct net_device *in,
7925 + const struct net_device *out,
7926 + const void *matchinfo,
7931 + const struct ipt_mport *minfo = matchinfo;
7936 + /* Must be big enough to read ports (both UDP and TCP have
7937 + them at the start). */
7938 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
7939 + /* We've been asked to examine this packet, and we
7940 + can't. Hence, no choice but to drop. */
7941 + duprintf("ipt_multiport:"
7942 + " Dropping evil offset=0 tinygram.\n");
7947 + return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
7950 +/* Called when user tries to insert an entry of this type. */
7952 +checkentry(const char *tablename,
7953 + const struct ipt_ip *ip,
7955 + unsigned int matchsize,
7956 + unsigned int hook_mask)
7958 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
7961 + /* Must specify proto == TCP/UDP, no unknown flags or bad count */
7962 + return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
7963 + && !(ip->invflags & IPT_INV_PROTO)
7964 + && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
7967 +static struct ipt_match mport_match = {
7970 + .checkentry = &checkentry,
7974 +static int __init init(void)
7976 + return ipt_register_match(&mport_match);
7979 +static void __exit fini(void)
7981 + ipt_unregister_match(&mport_match);
7986 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c
7987 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 00:00:00.000000000 +0000
7988 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c 2004-03-05 09:55:21.000000000 +0000
7991 + This is a module which is used for match support for every Nth packet
7992 + This file is distributed under the terms of the GNU General Public
7993 + License (GPL). Copies of the GPL can be obtained from:
7994 + ftp://prep.ai.mit.edu/pub/gnu/GPL
7996 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
7997 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
7998 + * added support for multiple counters
7999 + * added support for matching on individual packets
8000 + in the counter cycle
8001 + 2004-02-19 Harald Welte <laforge@netfilter.org>
8006 +#include <linux/module.h>
8007 +#include <linux/skbuff.h>
8008 +#include <linux/ip.h>
8009 +#include <net/tcp.h>
8010 +#include <linux/spinlock.h>
8011 +#include <linux/netfilter_ipv4/ip_tables.h>
8012 +#include <linux/netfilter_ipv4/ipt_nth.h>
8014 +MODULE_LICENSE("GPL");
8015 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
8018 + * State information.
8025 +static struct state states[IPT_NTH_NUM_COUNTERS];
8028 +ipt_nth_match(const struct sk_buff *pskb,
8029 + const struct net_device *in,
8030 + const struct net_device *out,
8031 + const void *matchinfo,
8035 + /* Parameters from userspace */
8036 + const struct ipt_nth_info *info = matchinfo;
8037 + unsigned counter = info->counter;
8038 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
8040 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
8044 + spin_lock(&states[counter].lock);
8046 + /* Are we matching every nth packet?*/
8047 + if (info->packet == 0xFF)
8049 + /* We're matching every nth packet and only every nth packet*/
8050 + /* Do we match or invert match? */
8051 + if (info->not == 0)
8053 + if (states[counter].number == 0)
8055 + ++states[counter].number;
8058 + if (states[counter].number >= info->every)
8059 + states[counter].number = 0; /* reset the counter */
8061 + ++states[counter].number;
8066 + if (states[counter].number == 0)
8068 + ++states[counter].number;
8071 + if (states[counter].number >= info->every)
8072 + states[counter].number = 0;
8074 + ++states[counter].number;
8080 + /* We're using the --packet, so there must be a rule for every value */
8081 + if (states[counter].number == info->packet)
8083 + /* only increment the counter when a match happens */
8084 + if (states[counter].number >= info->every)
8085 + states[counter].number = 0; /* reset the counter */
8087 + ++states[counter].number;
8096 + spin_unlock(&states[counter].lock);
8100 + spin_unlock(&states[counter].lock);
8105 +ipt_nth_checkentry(const char *tablename,
8106 + const struct ipt_ip *e,
8108 + unsigned int matchsize,
8109 + unsigned int hook_mask)
8111 + /* Parameters from userspace */
8112 + const struct ipt_nth_info *info = matchinfo;
8113 + unsigned counter = info->counter;
8114 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
8116 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
8120 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
8121 + printk("nth: matchsize %u != %u\n", matchsize,
8122 + IPT_ALIGN(sizeof(struct ipt_nth_info)));
8126 + states[counter].number = info->startat;
8131 +static struct ipt_match ipt_nth_reg = {
8133 + .match = ipt_nth_match,
8134 + .checkentry = ipt_nth_checkentry,
8138 +static int __init init(void)
8142 + memset(&states, 0, sizeof(states));
8143 + for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++)
8144 + spin_lock_init(&(states[counter].lock));
8146 + return ipt_register_match(&ipt_nth_reg);
8149 +static void __exit fini(void)
8151 + ipt_unregister_match(&ipt_nth_reg);
8156 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c
8157 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 00:00:00.000000000 +0000
8158 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c 2004-03-05 09:55:22.000000000 +0000
8161 + * netfilter module to enforce network quotas
8163 + * Sam Johnston <samj@samj.net>
8165 +#include <linux/module.h>
8166 +#include <linux/skbuff.h>
8167 +#include <linux/spinlock.h>
8168 +#include <linux/interrupt.h>
8170 +#include <linux/netfilter_ipv4/ip_tables.h>
8171 +#include <linux/netfilter_ipv4/ipt_quota.h>
8173 +MODULE_LICENSE("GPL");
8174 +MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
8176 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
8179 +match(const struct sk_buff *skb,
8180 + const struct net_device *in,
8181 + const struct net_device *out,
8182 + const void *matchinfo,
8183 + int offset, int *hotdrop)
8185 + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
8186 + unsigned int datalen;
8188 + if (skb->len < sizeof(struct iphdr))
8191 + datalen = skb->len - skb->nh.iph->ihl*4;
8193 + spin_lock_bh("a_lock);
8195 + if (q->quota >= datalen) {
8196 + /* we can afford this one */
8197 + q->quota -= datalen;
8198 + spin_unlock_bh("a_lock);
8200 +#ifdef DEBUG_IPT_QUOTA
8201 + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
8206 + /* so we do not allow even small packets from now on */
8209 +#ifdef DEBUG_IPT_QUOTA
8210 + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
8213 + spin_unlock_bh("a_lock);
8218 +checkentry(const char *tablename,
8219 + const struct ipt_ip *ip,
8220 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
8222 + /* TODO: spinlocks? sanity checks? */
8223 + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
8229 +static struct ipt_match quota_match = {
8232 + .checkentry = checkentry,
8239 + return ipt_register_match("a_match);
8245 + ipt_unregister_match("a_match);
8251 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c
8252 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 00:00:00.000000000 +0000
8253 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c 2004-03-05 09:55:23.000000000 +0000
8255 +/* Kernel module to match realm from routing. */
8256 +#include <linux/module.h>
8257 +#include <linux/skbuff.h>
8258 +#include <linux/netdevice.h>
8259 +#include <net/route.h>
8261 +#include <linux/netfilter_ipv4/ipt_realm.h>
8262 +#include <linux/netfilter_ipv4/ip_tables.h>
8264 +MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
8265 +MODULE_LICENSE("GPL");
8268 +match(const struct sk_buff *skb,
8269 + const struct net_device *in,
8270 + const struct net_device *out,
8271 + const void *matchinfo,
8275 + const struct ipt_realm_info *info = matchinfo;
8276 + struct dst_entry *dst = skb->dst;
8281 + id = dst->tclassid;
8283 + return (info->id == (id & info->mask)) ^ info->invert;
8286 +static int check(const char *tablename,
8287 + const struct ipt_ip *ip,
8289 + unsigned int matchsize,
8290 + unsigned int hook_mask)
8293 + & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
8294 + (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
8295 + printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
8296 + "LOCAL_IN or FORWARD.\n");
8300 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
8306 +static struct ipt_match realm_match = {
8309 + .checkentry = check,
8313 +static int __init init(void)
8315 + return ipt_register_match(&realm_match);
8318 +static void __exit fini(void)
8320 + ipt_unregister_match(&realm_match);
8325 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c
8326 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 00:00:00.000000000 +0000
8327 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c 2004-03-05 09:55:25.000000000 +0000
8329 +#include <linux/module.h>
8330 +#include <linux/skbuff.h>
8331 +#include <net/ip.h>
8332 +#include <linux/sctp.h>
8334 +#include <linux/netfilter_ipv4/ip_tables.h>
8335 +#include <linux/netfilter_ipv4/ipt_sctp.h>
8338 +#define duprintf(format, args...) printk(format , ## args)
8340 +#define duprintf(format, args...)
8343 +#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
8344 + || (!!((invflag) & (option)) ^ (cond)))
8347 +match_flags(const struct ipt_sctp_flag_info *flag_info,
8348 + const int flag_count,
8349 + u_int8_t chunktype,
8350 + u_int8_t chunkflags)
8354 + for (i = 0; i < flag_count; i++) {
8355 + if (flag_info[i].chunktype == chunktype) {
8356 + return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
8364 +match_packet(const struct sk_buff *skb,
8365 + const u_int32_t *chunkmap,
8366 + int chunk_match_type,
8367 + const struct ipt_sctp_flag_info *flag_info,
8368 + const int flag_count,
8372 + u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
8373 + sctp_chunkhdr_t sch;
8375 + if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
8376 + SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
8379 + offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
8381 + if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
8382 + duprintf("Dropping invalid SCTP packet.\n");
8387 +// duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
8388 +// ++i, offset, sch.type, htons(sch.length), sch.flags);
8390 + offset += (htons(sch.length) + 3) & ~3;
8392 + duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
8394 + if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
8395 + switch (chunk_match_type) {
8396 + case SCTP_CHUNK_MATCH_ANY:
8397 + if (match_flags(flag_info, flag_count,
8398 + sch.type, sch.flags)) {
8403 + case SCTP_CHUNK_MATCH_ALL:
8404 + if (match_flags(flag_info, flag_count,
8405 + sch.type, sch.flags)) {
8406 + SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
8410 + case SCTP_CHUNK_MATCH_ONLY:
8411 + if (!match_flags(flag_info, flag_count,
8412 + sch.type, sch.flags)) {
8418 + switch (chunk_match_type) {
8419 + case SCTP_CHUNK_MATCH_ONLY:
8423 + } while (offset < skb->len);
8425 + switch (chunk_match_type) {
8426 + case SCTP_CHUNK_MATCH_ALL:
8427 + return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
8428 + case SCTP_CHUNK_MATCH_ANY:
8430 + case SCTP_CHUNK_MATCH_ONLY:
8434 + /* This will never be reached, but required to stop compiler whine */
8439 +match(const struct sk_buff *skb,
8440 + const struct net_device *in,
8441 + const struct net_device *out,
8442 + const void *matchinfo,
8446 + const struct ipt_sctp_info *info;
8447 + sctp_sctphdr_t sh;
8449 + info = (const struct ipt_sctp_info *)matchinfo;
8452 + duprintf("Dropping non-first fragment.. FIXME\n");
8456 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
8457 + duprintf("Dropping evil TCP offset=0 tinygram.\n");
8461 + duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
8463 + return SCCHECK(((ntohs(sh.source) >= info->spts[0])
8464 + && (ntohs(sh.source) <= info->spts[1])),
8465 + IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
8466 + && SCCHECK(((ntohs(sh.dest) >= info->dpts[0])
8467 + && (ntohs(sh.dest) <= info->dpts[1])),
8468 + IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
8469 + && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
8470 + info->flag_info, info->flag_count,
8472 + IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
8476 +checkentry(const char *tablename,
8477 + const struct ipt_ip *ip,
8479 + unsigned int matchsize,
8480 + unsigned int hook_mask)
8482 + const struct ipt_sctp_info *info;
8484 + info = (const struct ipt_sctp_info *)matchinfo;
8486 + return ip->proto == IPPROTO_SCTP
8487 + && !(ip->invflags & IPT_INV_PROTO)
8488 + && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
8489 + && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
8490 + && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
8491 + && !(info->invflags & ~info->flags)
8492 + && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) ||
8493 + (info->chunk_match_type &
8494 + (SCTP_CHUNK_MATCH_ALL
8495 + | SCTP_CHUNK_MATCH_ANY
8496 + | SCTP_CHUNK_MATCH_ONLY)));
8499 +static struct ipt_match sctp_match =
8501 + .list = { NULL, NULL},
8504 + .checkentry = &checkentry,
8509 +static int __init init(void)
8511 + return ipt_register_match(&sctp_match);
8514 +static void __exit fini(void)
8516 + ipt_unregister_match(&sctp_match);
8522 +MODULE_LICENSE("GPL");
8523 +MODULE_AUTHOR("Kiran Kumar Immidi");
8524 +MODULE_DESCRIPTION("Match for SCTP protocol packets");
8526 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c
8527 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c 2004-03-04 06:17:10.000000000 +0000
8528 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c 2004-03-05 09:55:23.000000000 +0000
8530 enum ip_conntrack_info ctinfo;
8531 unsigned int statebit;
8533 - if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
8534 + if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
8535 + statebit = IPT_STATE_UNTRACKED;
8536 + else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
8537 statebit = IPT_STATE_INVALID;
8539 statebit = IPT_STATE_BIT(ctinfo);
8540 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c.orig
8541 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c.orig 1970-01-01 00:00:00.000000000 +0000
8542 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c.orig 2004-03-04 06:17:10.000000000 +0000
8544 +/* Kernel module to match connection tracking information. */
8546 +/* (C) 1999-2001 Paul `Rusty' Russell
8547 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
8549 + * This program is free software; you can redistribute it and/or modify
8550 + * it under the terms of the GNU General Public License version 2 as
8551 + * published by the Free Software Foundation.
8554 +#include <linux/module.h>
8555 +#include <linux/skbuff.h>
8556 +#include <linux/netfilter_ipv4/ip_conntrack.h>
8557 +#include <linux/netfilter_ipv4/ip_tables.h>
8558 +#include <linux/netfilter_ipv4/ipt_state.h>
8560 +MODULE_LICENSE("GPL");
8561 +MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
8562 +MODULE_DESCRIPTION("iptables connection tracking state match module");
8565 +match(const struct sk_buff *skb,
8566 + const struct net_device *in,
8567 + const struct net_device *out,
8568 + const void *matchinfo,
8572 + const struct ipt_state_info *sinfo = matchinfo;
8573 + enum ip_conntrack_info ctinfo;
8574 + unsigned int statebit;
8576 + if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
8577 + statebit = IPT_STATE_INVALID;
8579 + statebit = IPT_STATE_BIT(ctinfo);
8581 + return (sinfo->statemask & statebit);
8584 +static int check(const char *tablename,
8585 + const struct ipt_ip *ip,
8587 + unsigned int matchsize,
8588 + unsigned int hook_mask)
8590 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_state_info)))
8596 +static struct ipt_match state_match = {
8599 + .checkentry = &check,
8600 + .me = THIS_MODULE,
8603 +static int __init init(void)
8605 + need_ip_conntrack();
8606 + return ipt_register_match(&state_match);
8609 +static void __exit fini(void)
8611 + ipt_unregister_match(&state_match);
8616 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_u32.c
8617 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 00:00:00.000000000 +0000
8618 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_u32.c 2004-03-05 09:56:07.000000000 +0000
8620 +/* Kernel module to match u32 packet content. */
8623 +U32 tests whether quantities of up to 4 bytes extracted from a packet
8624 +have specified values. The specification of what to extract is general
8625 +enough to find data at given offsets from tcp headers or payloads.
8628 + The argument amounts to a program in a small language described below.
8629 + tests := location = value | tests && location = value
8630 + value := range | value , range
8631 + range := number | number : number
8632 + a single number, n, is interpreted the same as n:n
8633 + n:m is interpreted as the range of numbers >=n and <=m
8634 + location := number | location operator number
8635 + operator := & | << | >> | @
8637 + The operators &, <<, >>, && mean the same as in c. The = is really a set
8638 + membership operator and the value syntax describes a set. The @ operator
8639 + is what allows moving to the next header and is described further below.
8641 + *** Until I can find out how to avoid it, there are some artificial limits
8642 + on the size of the tests:
8643 + - no more than 10 ='s (and 9 &&'s) in the u32 argument
8644 + - no more than 10 ranges (and 9 commas) per value
8645 + - no more than 10 numbers (and 9 operators) per location
8647 + To describe the meaning of location, imagine the following machine that
8648 + interprets it. There are three registers:
8649 + A is of type char*, initially the address of the IP header
8650 + B and C are unsigned 32 bit integers, initially zero
8652 + The instructions are:
8653 + number B = number;
8654 + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
8655 + &number C = C&number
8656 + <<number C = C<<number
8657 + >>number C = C>>number
8658 + @number A = A+C; then do the instruction number
8659 + Any access of memory outside [skb->head,skb->end] causes the match to fail.
8660 + Otherwise the result of the computation is the final value of C.
8662 + Whitespace is allowed but not required in the tests.
8663 + However the characters that do occur there are likely to require
8664 + shell quoting, so it's a good idea to enclose the arguments in quotes.
8667 + match IP packets with total length >= 256
8668 + The IP header contains a total length field in bytes 2-3.
8669 + --u32 "0&0xFFFF=0x100:0xFFFF"
8671 + AND that with FFFF (giving bytes 2-3),
8672 + and test whether that's in the range [0x100:0xFFFF]
8674 +Example: (more realistic, hence more complicated)
8675 + match icmp packets with icmp type 0
8676 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1
8677 + --u32 "6&0xFF=1 && ...
8678 + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
8679 + Next test that it's not a fragment.
8680 + (If so it might be part of such a packet but we can't always tell.)
8681 + n.b. This test is generally needed if you want to match anything
8682 + beyond the IP header.
8683 + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
8684 + packet (not a fragment). Alternatively, you can allow first fragments
8685 + by only testing the last 5 bits of byte 6.
8686 + ... 4&0x3FFF=0 && ...
8687 + Last test: the first byte past the IP header (the type) is 0
8688 + This is where we have to use the @syntax. The length of the IP header
8689 + (IHL) in 32 bit words is stored in the right half of byte 0 of the
8691 + ... 0>>22&0x3C@0>>24=0"
8692 + The first 0 means read bytes 0-3,
8693 + >>22 means shift that 22 bits to the right. Shifting 24 bits would give
8694 + the first byte, so only 22 bits is four times that plus a few more bits.
8695 + &3C then eliminates the two extra bits on the right and the first four
8696 + bits of the first byte.
8697 + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
8698 + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz,
8699 + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
8700 + @ means to use this number as a new offset into the packet, and read
8701 + four bytes starting from there. This is the first 4 bytes of the icmp
8702 + payload, of which byte 0 is the icmp type. Therefore we simply shift
8703 + the value 24 to the right to throw out all but the first byte and compare
8704 + the result with 0.
8707 + tcp payload bytes 8-12 is any of 1, 2, 5 or 8
8708 + First we test that the packet is a tcp packet (similar to icmp).
8709 + --u32 "6&0xFF=6 && ...
8710 + Next, test that it's not a fragment (same as above).
8711 + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
8712 + 0>>22&3C as above computes the number of bytes in the IP header.
8713 + @ makes this the new offset into the packet, which is the start of the
8714 + tcp header. The length of the tcp header (again in 32 bit words) is
8715 + the left half of byte 12 of the tcp header. The 12>>26&3C
8716 + computes this length in bytes (similar to the IP header before).
8717 + @ makes this the new offset, which is the start of the tcp payload.
8718 + Finally 8 reads bytes 8-12 of the payload and = checks whether the
8719 + result is any of 1, 2, 5 or 8
8722 +#include <linux/module.h>
8723 +#include <linux/skbuff.h>
8725 +#include <linux/netfilter_ipv4/ipt_u32.h>
8726 +#include <linux/netfilter_ipv4/ip_tables.h>
8728 +/* #include <asm-i386/timex.h> for timing */
8730 +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
8731 +MODULE_DESCRIPTION("IP tables u32 matching module");
8732 +MODULE_LICENSE("GPL");
8735 +match(const struct sk_buff *skb,
8736 + const struct net_device *in,
8737 + const struct net_device *out,
8738 + const void *matchinfo,
8741 + u_int16_t datalen,
8744 + const struct ipt_u32 *data = matchinfo;
8746 + unsigned char* origbase = (char*)skb->nh.iph;
8747 + unsigned char* base = origbase;
8748 + unsigned char* head = skb->head;
8749 + unsigned char* end = skb->end;
8751 + u_int32_t pos, val;
8752 + /* unsigned long long cycles1, cycles2, cycles3, cycles4;
8753 + cycles1 = get_cycles(); */
8755 + for (testind=0; testind < data->ntests; testind++) {
8756 + base = origbase; /* reset for each test */
8757 + pos = data->tests[testind].location[0].number;
8758 + if (base+pos+3 > end || base+pos < head)
8760 + val = (base[pos]<<24) + (base[pos+1]<<16) +
8761 + (base[pos+2]<<8) + base[pos+3];
8762 + nnums = data->tests[testind].nnums;
8763 + for (i=1; i < nnums; i++) {
8764 + u_int32_t number = data->tests[testind].location[i].number;
8765 + switch (data->tests[testind].location[i].nextop) {
8767 + val = val & number;
8769 + case IPT_U32_LEFTSH:
8770 + val = val << number;
8772 + case IPT_U32_RIGHTSH:
8773 + val = val >> number;
8776 + base = base + val;
8778 + if (base+pos+3 > end || base+pos < head)
8780 + val = (base[pos]<<24) + (base[pos+1]<<16) +
8781 + (base[pos+2]<<8) + base[pos+3];
8785 + nvals = data->tests[testind].nvalues;
8786 + for (i=0; i < nvals; i++) {
8787 + if ((data->tests[testind].value[i].min <= val) &&
8788 + (val <= data->tests[testind].value[i].max)) {
8792 + if (i >= data->tests[testind].nvalues) {
8793 + /* cycles2 = get_cycles();
8794 + printk("failed %d in %d cycles\n", testind,
8795 + cycles2-cycles1); */
8799 + /* cycles2 = get_cycles();
8800 + printk("succeeded in %d cycles\n", cycles2-cycles1); */
8805 +checkentry(const char *tablename,
8806 + const struct ipt_ip *ip,
8808 + unsigned int matchsize,
8809 + unsigned int hook_mask)
8811 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
8816 +static struct ipt_match u32_match
8817 += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE };
8819 +static int __init init(void)
8821 + return ipt_register_match(&u32_match);
8824 +static void __exit fini(void)
8826 + ipt_unregister_match(&u32_match);
8831 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/iptable_raw.c linux-2.6.4-rc2/net/ipv4/netfilter/iptable_raw.c
8832 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/iptable_raw.c 1970-01-01 00:00:00.000000000 +0000
8833 +++ linux-2.6.4-rc2/net/ipv4/netfilter/iptable_raw.c 2004-03-05 09:55:23.000000000 +0000
8836 + * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
8838 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
8840 +#include <linux/module.h>
8841 +#include <linux/netfilter_ipv4/ip_tables.h>
8843 +#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
8845 +/* Standard entry. */
8846 +struct ipt_standard
8848 + struct ipt_entry entry;
8849 + struct ipt_standard_target target;
8852 +struct ipt_error_target
8854 + struct ipt_entry_target target;
8855 + char errorname[IPT_FUNCTION_MAXNAMELEN];
8860 + struct ipt_entry entry;
8861 + struct ipt_error_target target;
8866 + struct ipt_replace repl;
8867 + struct ipt_standard entries[2];
8868 + struct ipt_error term;
8869 +} initial_table __initdata
8870 += { { "raw", RAW_VALID_HOOKS, 3,
8871 + sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
8872 + { [NF_IP_PRE_ROUTING] 0,
8873 + [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
8874 + { [NF_IP_PRE_ROUTING] 0,
8875 + [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
8879 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8881 + sizeof(struct ipt_entry),
8882 + sizeof(struct ipt_standard),
8883 + 0, { 0, 0 }, { } },
8884 + { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
8885 + -NF_ACCEPT - 1 } },
8887 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8889 + sizeof(struct ipt_entry),
8890 + sizeof(struct ipt_standard),
8891 + 0, { 0, 0 }, { } },
8892 + { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
8893 + -NF_ACCEPT - 1 } }
8896 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8898 + sizeof(struct ipt_entry),
8899 + sizeof(struct ipt_error),
8900 + 0, { 0, 0 }, { } },
8901 + { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
8908 +static struct ipt_table packet_raw = {
8910 + .table = &initial_table.repl,
8911 + .valid_hooks = RAW_VALID_HOOKS,
8912 + .lock = RW_LOCK_UNLOCKED,
8916 +/* The work comes in here from netfilter.c. */
8917 +static unsigned int
8918 +ipt_hook(unsigned int hook,
8919 + struct sk_buff **pskb,
8920 + const struct net_device *in,
8921 + const struct net_device *out,
8922 + int (*okfn)(struct sk_buff *))
8924 + return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
8927 +/* 'raw' is the very first table. */
8928 +static struct nf_hook_ops ipt_ops[] = {
8932 + .hooknum = NF_IP_PRE_ROUTING,
8933 + .priority = NF_IP_PRI_RAW
8938 + .hooknum = NF_IP_LOCAL_OUT,
8939 + .priority = NF_IP_PRI_RAW
8943 +static int __init init(void)
8947 + /* Register table */
8948 + ret = ipt_register_table(&packet_raw);
8952 + /* Register hooks */
8953 + ret = nf_register_hook(&ipt_ops[0]);
8955 + goto cleanup_table;
8957 + ret = nf_register_hook(&ipt_ops[1]);
8959 + goto cleanup_hook0;
8964 + nf_unregister_hook(&ipt_ops[0]);
8966 + ipt_unregister_table(&packet_raw);
8971 +static void __exit fini(void)
8975 + for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
8976 + nf_unregister_hook(&ipt_ops[i]);
8978 + ipt_unregister_table(&packet_raw);
8983 +MODULE_LICENSE("GPL");
8984 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig
8985 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig 2004-03-04 06:17:03.000000000 +0000
8986 +++ linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig 2004-03-05 09:55:23.000000000 +0000
8987 @@ -218,5 +218,37 @@
8988 To compile it as a module, choose M here. If unsure, say N.
8990 #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
8991 +config IP6_NF_TARGET_HL
8992 + tristate 'HL target support'
8993 + depends on IP6_NF_MANGLE
8996 +config IP6_NF_TARGET_REJECT
8997 + tristate 'REJECT target support'
8998 + depends on IP6_NF_FILTER
9001 +config IP6_NF_MATCH_FUZZY
9002 + tristate 'Fuzzy match support'
9003 + depends on IP6_NF_FILTER
9006 +config IP6_NF_MATCH_NTH
9007 + tristate 'Nth match support'
9008 + depends on IP6_NF_IPTABLES
9012 + tristate 'raw table support (required for TRACE)'
9013 + depends on IP6_NF_IPTABLES
9015 + This option adds a `raw' table to ip6tables. This table is the very
9016 + first in the netfilter framework and hooks in at the PREROUTING
9017 + and OUTPUT chains.
9019 + If you want to compile it as a module, say M here and read
9020 + <file:Documentation/modules.txt>. If unsure, say `N'.
9025 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile linux-2.6.4-rc2/net/ipv6/netfilter/Makefile
9026 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile 2004-03-04 06:16:48.000000000 +0000
9027 +++ linux-2.6.4-rc2/net/ipv6/netfilter/Makefile 2004-03-05 09:55:23.000000000 +0000
9029 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
9030 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
9031 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
9032 +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
9033 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
9034 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
9035 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
9037 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
9038 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
9039 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
9040 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
9041 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
9042 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
9043 +obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
9045 +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
9046 +obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
9047 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
9048 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c
9049 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c 1970-01-01 00:00:00.000000000 +0000
9050 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c 2004-03-05 09:55:10.000000000 +0000
9053 + * Hop Limit modification target for ip6tables
9054 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
9055 + * Based on HW's TTL module
9057 + * This software is distributed under the terms of GNU GPL
9060 +#include <linux/module.h>
9061 +#include <linux/skbuff.h>
9062 +#include <linux/ip.h>
9064 +#include <linux/netfilter_ipv6/ip6_tables.h>
9065 +#include <linux/netfilter_ipv6/ip6t_HL.h>
9067 +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
9068 +MODULE_DESCRIPTION("IP tables Hop Limit modification module");
9069 +MODULE_LICENSE("GPL");
9071 +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
9072 + const struct net_device *in, const struct net_device *out,
9073 + const void *targinfo, void *userinfo)
9075 + struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
9076 + const struct ip6t_HL_info *info = targinfo;
9077 + u_int16_t diffs[2];
9080 + switch (info->mode) {
9082 + new_hl = info->hop_limit;
9085 + new_hl = ip6h->hop_limit + info->hop_limit;
9090 + new_hl = ip6h->hop_limit + info->hop_limit;
9095 + new_hl = ip6h->hop_limit;
9099 + if (new_hl != ip6h->hop_limit) {
9100 + diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
9101 + ip6h->hop_limit = new_hl;
9102 + diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
9105 + return IP6T_CONTINUE;
9108 +static int ip6t_hl_checkentry(const char *tablename,
9109 + const struct ip6t_entry *e,
9111 + unsigned int targinfosize,
9112 + unsigned int hook_mask)
9114 + struct ip6t_HL_info *info = targinfo;
9116 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
9117 + printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
9119 + IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
9123 + if (strcmp(tablename, "mangle")) {
9124 + printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
9128 + if (info->mode > IP6T_HL_MAXMODE) {
9129 + printk(KERN_WARNING "HL: invalid or unknown Mode %u\n",
9134 + if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
9135 + printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
9142 +static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL",
9143 + ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
9145 +static int __init init(void)
9147 + return ip6t_register_target(&ip6t_HL);
9150 +static void __exit fini(void)
9152 + ip6t_unregister_target(&ip6t_HL);
9157 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_LOG.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_LOG.c
9158 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_LOG.c 2004-03-04 06:16:41.000000000 +0000
9159 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_LOG.c 2004-03-05 09:55:08.000000000 +0000
9161 #include <net/udp.h>
9162 #include <net/tcp.h>
9163 #include <net/ipv6.h>
9164 +#include <linux/netfilter.h>
9165 #include <linux/netfilter_ipv6/ip6_tables.h>
9167 MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
9168 MODULE_DESCRIPTION("IP6 tables LOG target module");
9169 MODULE_LICENSE("GPL");
9171 +static unsigned int nflog = 1;
9172 +MODULE_PARM(nflog, "i");
9173 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
9176 #include <net/route.h>
9177 #include <linux/netfilter_ipv6/ip6t_LOG.h>
9178 @@ -265,40 +270,38 @@
9182 -static unsigned int
9183 -ip6t_log_target(struct sk_buff **pskb,
9184 - unsigned int hooknum,
9186 +ip6t_log_packet(unsigned int hooknum,
9187 + const struct sk_buff *skb,
9188 const struct net_device *in,
9189 const struct net_device *out,
9190 - const void *targinfo,
9192 + const struct ip6t_log_info *loginfo,
9193 + const char *level_string,
9194 + const char *prefix)
9196 - struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
9197 - const struct ip6t_log_info *loginfo = targinfo;
9198 - char level_string[4] = "< >";
9199 + struct ipv6hdr *ipv6h = skb->nh.ipv6h;
9201 - level_string[1] = '0' + (loginfo->level % 8);
9202 spin_lock_bh(&log_lock);
9203 printk(level_string);
9204 printk("%sIN=%s OUT=%s ",
9206 + prefix == NULL ? loginfo->prefix : prefix,
9208 out ? out->name : "");
9210 /* MAC logging for input chain only. */
9212 - if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
9213 - if ((*pskb)->dev->type != ARPHRD_SIT){
9214 + if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) {
9215 + if (skb->dev->type != ARPHRD_SIT){
9217 - unsigned char *p = (*pskb)->mac.raw;
9218 - for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
9219 + unsigned char *p = skb->mac.raw;
9220 + for (i = 0; i < skb->dev->hard_header_len; i++,p++)
9221 printk("%02x%c", *p,
9222 - i==(*pskb)->dev->hard_header_len - 1
9223 + i==skb->dev->hard_header_len - 1
9227 - unsigned char *p = (*pskb)->mac.raw;
9228 - if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
9229 + unsigned char *p = skb->mac.raw;
9230 + if ( p - (ETH_ALEN*2+2) > skb->head ){
9232 for (i = 0; i < (ETH_ALEN); i++,p++)
9233 printk("%02x%s", *p,
9234 @@ -309,10 +312,10 @@
9235 i == ETH_ALEN-1 ? ' ' : ':');
9238 - if (((*pskb)->dev->addr_len == 4) &&
9239 - (*pskb)->dev->hard_header_len > 20){
9240 + if ((skb->dev->addr_len == 4) &&
9241 + skb->dev->hard_header_len > 20){
9243 - p = (*pskb)->mac.raw + 12;
9244 + p = skb->mac.raw + 12;
9245 for (i = 0; i < 4; i++,p++)
9247 i == 3 ? "->" : ".");
9248 @@ -328,10 +331,41 @@
9249 dump_packet(loginfo, ipv6h, 1);
9251 spin_unlock_bh(&log_lock);
9254 +static unsigned int
9255 +ip6t_log_target(struct sk_buff **pskb,
9256 + unsigned int hooknum,
9257 + const struct net_device *in,
9258 + const struct net_device *out,
9259 + const void *targinfo,
9262 + const struct ip6t_log_info *loginfo = targinfo;
9263 + char level_string[4] = "< >";
9265 + level_string[1] = '0' + (loginfo->level % 8);
9266 + ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
9268 return IP6T_CONTINUE;
9272 +ip6t_logfn(unsigned int hooknum,
9273 + const struct sk_buff *skb,
9274 + const struct net_device *in,
9275 + const struct net_device *out,
9276 + const char *prefix)
9278 + struct ip6t_log_info loginfo = {
9280 + .logflags = IP6T_LOG_MASK,
9284 + ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
9287 static int ip6t_log_checkentry(const char *tablename,
9288 const struct ip6t_entry *e,
9290 @@ -360,20 +394,27 @@
9294 -static struct ip6t_target ip6t_log_reg
9295 -= { { NULL, NULL }, "LOG", ip6t_log_target, ip6t_log_checkentry, NULL,
9297 +static struct ip6t_target ip6t_log_reg = {
9299 + .target = ip6t_log_target,
9300 + .checkentry = ip6t_log_checkentry,
9301 + .me = THIS_MODULE,
9304 static int __init init(void)
9306 if (ip6t_register_target(&ip6t_log_reg))
9309 + nf_log_register(PF_INET6, &ip6t_logfn);
9314 static void __exit fini(void)
9317 + nf_log_unregister(PF_INET6, &ip6t_logfn);
9318 ip6t_unregister_target(&ip6t_log_reg);
9321 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c
9322 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 00:00:00.000000000 +0000
9323 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c 2004-03-05 09:55:13.000000000 +0000
9326 + * This is a module which is used for rejecting packets.
9327 + * Added support for customized reject packets (Jozsef Kadlecsik).
9329 + * Port to IPv6 / ip6tables (Harald Welte <laforge@gnumonks.org>)
9331 +#include <linux/config.h>
9332 +#include <linux/module.h>
9333 +#include <linux/skbuff.h>
9334 +#include <linux/icmpv6.h>
9335 +#include <net/tcp.h>
9336 +#include <linux/netfilter_ipv6/ip6_tables.h>
9337 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
9340 +#define DEBUGP printk
9342 +#define DEBUGP(format, args...)
9346 +/* Send RST reply */
9347 +static void send_reset(struct sk_buff *oldskb)
9349 + struct sk_buff *nskb;
9350 + struct tcphdr *otcph, *tcph;
9351 + struct rtable *rt;
9352 + unsigned int otcplen;
9355 + /* IP header checks: fragment, too short. */
9356 + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
9357 + || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
9360 + otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
9361 + otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
9363 + /* No RST for RST. */
9367 + /* Check checksum. */
9368 + if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
9369 + oldskb->nh.iph->daddr,
9370 + csum_partial((char *)otcph, otcplen, 0)) != 0)
9373 + /* Copy skb (even if skb is about to be dropped, we can't just
9374 + clone it because there may be other things, such as tcpdump,
9375 + interested in it) */
9376 + nskb = skb_copy(oldskb, GFP_ATOMIC);
9380 + /* This packet will not be the same as the other: clear nf fields */
9381 + nf_conntrack_put(nskb->nfct);
9382 + nskb->nfct = NULL;
9383 + nskb->nfcache = 0;
9384 +#ifdef CONFIG_NETFILTER_DEBUG
9385 + nskb->nf_debug = 0;
9388 + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
9390 + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
9391 + tcph->source = xchg(&tcph->dest, tcph->source);
9393 + /* Truncate to length (no data) */
9394 + tcph->doff = sizeof(struct tcphdr)/4;
9395 + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
9396 + nskb->nh.iph->tot_len = htons(nskb->len);
9400 + tcph->seq = otcph->ack_seq;
9401 + tcph->ack_seq = 0;
9404 + tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
9405 + + otcplen - (otcph->doff<<2));
9410 + ((u_int8_t *)tcph)[13] = 0;
9412 + tcph->ack = needs_ack;
9415 + tcph->urg_ptr = 0;
9417 + /* Adjust TCP checksum */
9419 + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
9420 + nskb->nh.iph->saddr,
9421 + nskb->nh.iph->daddr,
9422 + csum_partial((char *)tcph,
9423 + sizeof(struct tcphdr), 0));
9425 + /* Adjust IP TTL, DF */
9426 + nskb->nh.iph->ttl = MAXTTL;
9427 + /* Set DF, id = 0 */
9428 + nskb->nh.iph->frag_off = htons(IP_DF);
9429 + nskb->nh.iph->id = 0;
9431 + /* Adjust IP checksum */
9432 + nskb->nh.iph->check = 0;
9433 + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
9434 + nskb->nh.iph->ihl);
9437 + if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
9438 + RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
9442 + dst_release(nskb->dst);
9443 + nskb->dst = &rt->u.dst;
9445 + /* "Never happens" */
9446 + if (nskb->len > nskb->dst->pmtu)
9449 + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
9450 + ip_finish_output);
9458 +static unsigned int reject6_target(struct sk_buff **pskb,
9459 + unsigned int hooknum,
9460 + const struct net_device *in,
9461 + const struct net_device *out,
9462 + const void *targinfo,
9465 + const struct ip6t_reject_info *reject = targinfo;
9467 + /* WARNING: This code causes reentry within ip6tables.
9468 + This means that the ip6tables jump stack is now crap. We
9469 + must return an absolute verdict. --RR */
9470 + DEBUGP("REJECTv6: calling icmpv6_send\n");
9471 + switch (reject->with) {
9472 + case IP6T_ICMP6_NO_ROUTE:
9473 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out);
9475 + case IP6T_ICMP6_ADM_PROHIBITED:
9476 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out);
9478 + case IP6T_ICMP6_NOT_NEIGHBOUR:
9479 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out);
9481 + case IP6T_ICMP6_ADDR_UNREACH:
9482 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out);
9484 + case IP6T_ICMP6_PORT_UNREACH:
9485 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out);
9488 + case IPT_ICMP_ECHOREPLY: {
9489 + struct icmp6hdr *icmph = (struct icmphdr *)
9490 + ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
9491 + unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
9493 + /* Not non-head frags, or truncated */
9494 + if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0)
9495 + && datalen >= 4) {
9496 + /* Usually I don't like cut & pasting code,
9497 + but dammit, my party is starting in 45
9499 + struct icmp_bxm icmp_param;
9501 + icmp_param.icmph=*icmph;
9502 + icmp_param.icmph.type=ICMP_ECHOREPLY;
9503 + icmp_param.data_ptr=(icmph+1);
9504 + icmp_param.data_len=datalen;
9505 + icmp_reply(&icmp_param, *pskb);
9509 + case IPT_TCP_RESET:
9510 + send_reset(*pskb);
9514 + printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with);
9521 +static inline int find_ping_match(const struct ip6t_entry_match *m)
9523 + const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data;
9525 + if (strcmp(m->u.kernel.match->name, "icmp6") == 0
9526 + && icmpinfo->type == ICMPV6_ECHO_REQUEST
9527 + && !(icmpinfo->invflags & IP6T_ICMP_INV))
9533 +static int check(const char *tablename,
9534 + const struct ip6t_entry *e,
9536 + unsigned int targinfosize,
9537 + unsigned int hook_mask)
9539 + const struct ip6t_reject_info *rejinfo = targinfo;
9541 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
9542 + DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize);
9546 + /* Only allow these for packet filtering. */
9547 + if (strcmp(tablename, "filter") != 0) {
9548 + DEBUGP("REJECTv6: bad table `%s'.\n", tablename);
9551 + if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
9552 + | (1 << NF_IP6_FORWARD)
9553 + | (1 << NF_IP6_LOCAL_OUT))) != 0) {
9554 + DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask);
9558 + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
9559 + /* Must specify that it's an ICMP ping packet. */
9560 + if (e->ipv6.proto != IPPROTO_ICMPV6
9561 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
9562 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n");
9565 + /* Must contain ICMP match. */
9566 + if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) {
9567 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n");
9570 + } else if (rejinfo->with == IP6T_TCP_RESET) {
9571 + /* Must specify that it's a TCP packet */
9572 + if (e->ipv6.proto != IPPROTO_TCP
9573 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
9574 + DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n");
9582 +static struct ip6t_target ip6t_reject_reg
9583 += { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE };
9585 +static int __init init(void)
9587 + if (ip6t_register_target(&ip6t_reject_reg))
9592 +static void __exit fini(void)
9594 + ip6t_unregister_target(&ip6t_reject_reg);
9599 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c
9600 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
9601 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c 2004-03-05 09:55:18.000000000 +0000
9604 + * This module implements a simple TSK FLC
9605 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
9606 + * to limit , in an adaptive and flexible way , the packet rate crossing
9607 + * a given stream . It serves as an initial and very simple (but effective)
9608 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
9609 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
9610 + * into our code in a precise , adaptive and efficient manner.
9611 + * The goal is very similar to that of "limit" match , but using techniques of
9612 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
9613 + * avoiding over and undershoots - and stuff like that .
9616 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
9617 + * 2002-08-17 : Changed to eliminate floating point operations .
9618 + * 2002-08-23 : Coding style changes .
9619 + * 2003-04-08 Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
9622 +#include <linux/module.h>
9623 +#include <linux/skbuff.h>
9624 +#include <linux/ipv6.h>
9625 +#include <linux/random.h>
9626 +#include <net/tcp.h>
9627 +#include <linux/spinlock.h>
9628 +#include <linux/netfilter_ipv6/ip6_tables.h>
9629 +#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
9632 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
9633 + Expressed in percentage
9636 +#define PAR_LOW 1/100
9639 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
9641 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
9642 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
9643 +MODULE_LICENSE("GPL");
9645 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
9647 + if (tx >= maxi) return 100;
9649 + if (tx <= mini) return 0;
9651 + return ((100 * (tx-mini)) / (maxi-mini));
9654 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
9656 + if (tx <= mini) return 100;
9658 + if (tx >= maxi) return 0;
9660 + return ((100 * (maxi - tx)) / (maxi - mini));
9665 +ip6t_fuzzy_match(const struct sk_buff *pskb,
9666 + const struct net_device *in,
9667 + const struct net_device *out,
9668 + const void *matchinfo,
9671 + u_int16_t datalen,
9674 + /* From userspace */
9676 + struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
9678 + u_int8_t random_number;
9679 + unsigned long amount;
9680 + u_int8_t howhigh, howlow;
9683 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
9685 + info->bytes_total += pskb->len;
9686 + info->packets_total++;
9688 + info->present_time = jiffies;
9690 + if (info->present_time >= info->previous_time)
9691 + amount = info->present_time - info->previous_time;
9693 + /* There was a transition : I choose to re-sample
9694 + and keep the old acceptance rate...
9698 + info->previous_time = info->present_time;
9699 + info->bytes_total = info->packets_total = 0;
9702 + if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
9704 + info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
9707 + info->previous_time = info->present_time;
9708 + info->bytes_total = info->packets_total = 0;
9710 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
9711 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
9713 + info->acceptance_rate = (u_int8_t) \
9714 + (howhigh * PAR_LOW + PAR_HIGH * howlow);
9716 + /* In fact, the above defuzzification would require a denominator
9717 + * proportional to (howhigh+howlow) but, in this particular case,
9718 + * that expression is constant.
9719 + * An imediate consequence is that it is not necessary to call
9720 + * both mf_high and mf_low - but to keep things understandable,
9726 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
9729 + if (info->acceptance_rate < 100)
9731 + get_random_bytes((void *)(&random_number), 1);
9733 + /* If within the acceptance , it can pass => don't match */
9734 + if (random_number <= (255 * info->acceptance_rate) / 100)
9737 + return 1; /* It can't pass (It matches) */
9740 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
9745 +ip6t_fuzzy_checkentry(const char *tablename,
9746 + const struct ip6t_ip6 *ip,
9748 + unsigned int matchsize,
9749 + unsigned int hook_mask)
9752 + const struct ip6t_fuzzy_info *info = matchinfo;
9754 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
9755 + printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
9756 + IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
9760 + if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
9761 + || (info->minimum_rate >= info->maximum_rate)) {
9762 + printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
9769 +static struct ip6t_match ip6t_fuzzy_reg = {
9773 + ip6t_fuzzy_checkentry,
9777 +static int __init init(void)
9779 + if (ip6t_register_match(&ip6t_fuzzy_reg))
9785 +static void __exit fini(void)
9787 + ip6t_unregister_match(&ip6t_fuzzy_reg);
9792 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c
9793 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 00:00:00.000000000 +0000
9794 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c 2004-03-05 09:55:21.000000000 +0000
9797 + This is a module which is used for match support for every Nth packet
9798 + This file is distributed under the terms of the GNU General Public
9799 + License (GPL). Copies of the GPL can be obtained from:
9800 + ftp://prep.ai.mit.edu/pub/gnu/GPL
9802 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
9803 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
9804 + * added support for multiple counters
9805 + * added support for matching on individual packets
9806 + in the counter cycle
9807 + 2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
9811 +#include <linux/module.h>
9812 +#include <linux/skbuff.h>
9813 +#include <linux/ip.h>
9814 +#include <net/tcp.h>
9815 +#include <linux/spinlock.h>
9816 +#include <linux/netfilter_ipv6/ip6_tables.h>
9817 +#include <linux/netfilter_ipv6/ip6t_nth.h>
9819 +MODULE_LICENSE("GPL");
9822 + * State information.
9829 +static struct state states[IP6T_NTH_NUM_COUNTERS];
9832 +ip6t_nth_match(const struct sk_buff *pskb,
9833 + const struct net_device *in,
9834 + const struct net_device *out,
9835 + const void *matchinfo,
9838 + u_int16_t datalen,
9841 + /* Parameters from userspace */
9842 + const struct ip6t_nth_info *info = matchinfo;
9843 + unsigned counter = info->counter;
9844 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
9846 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
9850 + spin_lock(&states[counter].lock);
9852 + /* Are we matching every nth packet?*/
9853 + if (info->packet == 0xFF)
9855 + /* We're matching every nth packet and only every nth packet*/
9856 + /* Do we match or invert match? */
9857 + if (info->not == 0)
9859 + if (states[counter].number == 0)
9861 + ++states[counter].number;
9864 + if (states[counter].number >= info->every)
9865 + states[counter].number = 0; /* reset the counter */
9867 + ++states[counter].number;
9872 + if (states[counter].number == 0)
9874 + ++states[counter].number;
9877 + if (states[counter].number >= info->every)
9878 + states[counter].number = 0;
9880 + ++states[counter].number;
9886 + /* We're using the --packet, so there must be a rule for every value */
9887 + if (states[counter].number == info->packet)
9889 + /* only increment the counter when a match happens */
9890 + if (states[counter].number >= info->every)
9891 + states[counter].number = 0; /* reset the counter */
9893 + ++states[counter].number;
9902 + spin_unlock(&states[counter].lock);
9906 + spin_unlock(&states[counter].lock);
9911 +ip6t_nth_checkentry(const char *tablename,
9912 + const struct ip6t_ip6 *e,
9914 + unsigned int matchsize,
9915 + unsigned int hook_mask)
9917 + /* Parameters from userspace */
9918 + const struct ip6t_nth_info *info = matchinfo;
9919 + unsigned counter = info->counter;
9920 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
9922 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
9926 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
9927 + printk("nth: matchsize %u != %u\n", matchsize,
9928 + IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
9932 + states[counter].number = info->startat;
9937 +static struct ip6t_match ip6t_nth_reg = {
9941 + ip6t_nth_checkentry,
9945 +static int __init init(void)
9948 + memset(&states, 0, sizeof(states));
9949 + if (ip6t_register_match(&ip6t_nth_reg))
9952 + for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++)
9954 + spin_lock_init(&(states[counter].lock));
9957 + printk("ip6t_nth match loaded\n");
9961 +static void __exit fini(void)
9963 + ip6t_unregister_match(&ip6t_nth_reg);
9964 + printk("ip6t_nth match unloaded\n");
9969 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6table_raw.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6table_raw.c
9970 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6table_raw.c 1970-01-01 00:00:00.000000000 +0000
9971 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6table_raw.c 2004-03-05 09:55:23.000000000 +0000
9974 + * IPv6 raw table, a port of the IPv4 raw table to IPv6
9976 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
9978 +#include <linux/module.h>
9979 +#include <linux/netfilter_ipv6/ip6_tables.h>
9981 +#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
9984 +#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
9986 +#define DEBUGP(x, args...)
9989 +/* Standard entry. */
9990 +struct ip6t_standard
9992 + struct ip6t_entry entry;
9993 + struct ip6t_standard_target target;
9996 +struct ip6t_error_target
9998 + struct ip6t_entry_target target;
9999 + char errorname[IP6T_FUNCTION_MAXNAMELEN];
10004 + struct ip6t_entry entry;
10005 + struct ip6t_error_target target;
10010 + struct ip6t_replace repl;
10011 + struct ip6t_standard entries[2];
10012 + struct ip6t_error term;
10013 +} initial_table __initdata
10014 += { { "raw", RAW_VALID_HOOKS, 3,
10015 + sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
10016 + { [NF_IP6_PRE_ROUTING] 0,
10017 + [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
10018 + { [NF_IP6_PRE_ROUTING] 0,
10019 + [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
10022 + /* PRE_ROUTING */
10023 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
10025 + sizeof(struct ip6t_entry),
10026 + sizeof(struct ip6t_standard),
10027 + 0, { 0, 0 }, { } },
10028 + { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
10029 + -NF_ACCEPT - 1 } },
10031 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
10033 + sizeof(struct ip6t_entry),
10034 + sizeof(struct ip6t_standard),
10035 + 0, { 0, 0 }, { } },
10036 + { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
10037 + -NF_ACCEPT - 1 } },
10040 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
10042 + sizeof(struct ip6t_entry),
10043 + sizeof(struct ip6t_error),
10044 + 0, { 0, 0 }, { } },
10045 + { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
10052 +static struct ip6t_table packet_raw = {
10054 + .table = &initial_table.repl,
10055 + .valid_hooks = RAW_VALID_HOOKS,
10056 + .lock = RW_LOCK_UNLOCKED,
10057 + .me = THIS_MODULE
10060 +/* The work comes in here from netfilter.c. */
10061 +static unsigned int
10062 +ip6t_hook(unsigned int hook,
10063 + struct sk_buff **pskb,
10064 + const struct net_device *in,
10065 + const struct net_device *out,
10066 + int (*okfn)(struct sk_buff *))
10068 + return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
10071 +static struct nf_hook_ops ip6t_ops[] = {
10073 + .hook = ip6t_hook,
10075 + .hooknum = NF_IP6_PRE_ROUTING,
10076 + .priority = NF_IP6_PRI_FIRST
10079 + .hook = ip6t_hook,
10081 + .hooknum = NF_IP6_LOCAL_OUT,
10082 + .priority = NF_IP6_PRI_FIRST
10086 +static int __init init(void)
10090 + /* Register table */
10091 + ret = ip6t_register_table(&packet_raw);
10095 + /* Register hooks */
10096 + ret = nf_register_hook(&ip6t_ops[0]);
10098 + goto cleanup_table;
10100 + ret = nf_register_hook(&ip6t_ops[1]);
10102 + goto cleanup_hook0;
10107 + nf_unregister_hook(&ip6t_ops[0]);
10109 + ip6t_unregister_table(&packet_raw);
10114 +static void __exit fini(void)
10118 + for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
10119 + nf_unregister_hook(&ip6t_ops[i]);
10121 + ip6t_unregister_table(&packet_raw);
10124 +module_init(init);
10125 +module_exit(fini);
10126 +MODULE_LICENSE("GPL");