]> git.pld-linux.org Git - packages/kernel.git/blame - 2.6.0-t9-netfilter-20031113.patch
- ported from linux-2.4.25-atmdd.patch
[packages/kernel.git] / 2.6.0-t9-netfilter-20031113.patch
CommitLineData
5de6da4e 1diff -Nur linux-2.6.0-test9.org/include/linux/netfilter.h linux-2.6.0-test9/include/linux/netfilter.h
2--- linux-2.6.0-test9.org/include/linux/netfilter.h 2003-10-25 20:43:40.000000000 +0200
3+++ linux-2.6.0-test9/include/linux/netfilter.h 2003-11-13 11:01:38.000000000 +0100
4@@ -23,6 +23,7 @@
5 <= 0x2000 is used for protocol-flags. */
6 #define NFC_UNKNOWN 0x4000
7 #define NFC_ALTERED 0x8000
8+#define NFC_TRACE 0x10000
9
10 #ifdef __KERNEL__
11 #include <linux/config.h>
12@@ -99,6 +100,24 @@
13
14 extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
15
16+typedef void nf_logfn(unsigned int hooknum,
17+ const struct sk_buff *skb,
18+ const struct net_device *in,
19+ const struct net_device *out,
20+ const char *prefix);
21+
22+/* Function to register/unregister log function. */
23+int nf_log_register(int pf, nf_logfn *logfn);
24+void nf_log_unregister(int pf, nf_logfn *logfn);
25+
26+/* Calls the registered backend logging function */
27+void nf_log_packet(int pf,
28+ unsigned int hooknum,
29+ const struct sk_buff *skb,
30+ const struct net_device *in,
31+ const struct net_device *out,
32+ const char *fmt, ...);
33+
34 /* Activate hook; either okfn or kfree_skb called, unless a hook
35 returns NF_STOLEN (in which case, it's up to the hook to deal with
36 the consequences).
37diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.0-test9/include/linux/netfilter_ipv4/ip_conntrack.h
38--- linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ip_conntrack.h 2003-10-25 20:44:44.000000000 +0200
39+++ linux-2.6.0-test9/include/linux/netfilter_ipv4/ip_conntrack.h 2003-11-13 11:01:38.000000000 +0100
40@@ -268,6 +268,9 @@
41
42 extern unsigned int ip_conntrack_htable_size;
43
44+/* A fake conntrack entry which never vanishes. */
45+extern struct ip_conntrack ip_conntrack_untracked;
46+
47 /* eg. PROVIDES_CONNTRACK(ftp); */
48 #define PROVIDES_CONNTRACK(name) \
49 int needs_ip_conntrack_##name; \
50diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.0-test9/include/linux/netfilter_ipv4/ip_tables.h
51--- linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ip_tables.h 2003-10-25 20:43:46.000000000 +0200
52+++ linux-2.6.0-test9/include/linux/netfilter_ipv4/ip_tables.h 2003-11-13 11:01:38.000000000 +0100
53@@ -134,6 +134,12 @@
54 /* Back pointer */
55 unsigned int comefrom;
56
57+ /* Name of the chain */
58+ char *chainname;
59+
60+ /* Rule number in the chain. */
61+ u_int32_t rulenum;
62+
63 /* Packet and byte counters. */
64 struct ipt_counters counters;
65
66diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_ULOG.h linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_ULOG.h
67--- linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_ULOG.h 2003-10-25 20:43:28.000000000 +0200
68+++ linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_ULOG.h 2003-11-13 11:01:18.000000000 +0100
69@@ -11,6 +11,9 @@
70 #define NETLINK_NFLOG 5
71 #endif
72
73+#define NFLOG_DEFAULT_NLGROUP 1
74+#define NFLOG_DEFAULT_QTHRESHOLD 1
75+
76 #define ULOG_MAC_LEN 80
77 #define ULOG_PREFIX_LEN 32
78
79diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_conntrack.h
80--- linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_conntrack.h 2003-10-25 20:44:16.000000000 +0200
81+++ linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_conntrack.h 2003-11-13 11:01:38.000000000 +0100
82@@ -10,6 +10,7 @@
83
84 #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
85 #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
86+#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
87
88 /* flags, invflags: */
89 #define IPT_CONNTRACK_STATE 0x01
90diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_sctp.h
91--- linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 01:00:00.000000000 +0100
92+++ linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_sctp.h 2003-11-13 11:01:48.000000000 +0100
93@@ -0,0 +1,25 @@
94+/* iptables module for matching the SCTP header
95+ *
96+ * (C) 2003 Harald Welte <laforge@gnumonks.org>
97+ *
98+ * This software is distributed under GNU GPL v2, 1991
99+ *
100+ * $Id$
101+ */
102+#ifndef _IPT_SCTP_H
103+#define _IPT_SCTP_H
104+
105+struct ipt_sctp_info {
106+ u_int16_t spts[2]; /* Souce port range */
107+ u_int16_t dpts[2]; /* Destination port range */
108+ u_int32_t chunks; /* chunks to be matched */
109+ u_int32_t chunk_mask; /* chunk mask to be matched */
110+ u_int8_t invflags; /* Inverse flags */
111+};
112+
113+#define IPT_SCTP_INV_SRCPT 0x01 /* Invert the sense of source ports */
114+#define IPT_SCTP_INV_DSTPT 0x02 /* Invert the sense of dest ports */
115+#define IPT_SCTP_INV_CHUNKS 0x03 /* Invert the sense of chunks */
116+#define IPT_SCTP_INV_MASK 0x03 /* All possible flags */
117+
118+#endif /* _IPT_SCTP_H */
119diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_state.h linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_state.h
120--- linux-2.6.0-test9.org/include/linux/netfilter_ipv4/ipt_state.h 2003-10-25 20:44:36.000000000 +0200
121+++ linux-2.6.0-test9/include/linux/netfilter_ipv4/ipt_state.h 2003-11-13 11:01:38.000000000 +0100
122@@ -4,6 +4,8 @@
123 #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
124 #define IPT_STATE_INVALID (1 << 0)
125
126+#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
127+
128 struct ipt_state_info
129 {
130 unsigned int statemask;
131diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv4.h linux-2.6.0-test9/include/linux/netfilter_ipv4.h
132--- linux-2.6.0-test9.org/include/linux/netfilter_ipv4.h 2003-10-25 20:44:34.000000000 +0200
133+++ linux-2.6.0-test9/include/linux/netfilter_ipv4.h 2003-11-13 11:01:38.000000000 +0100
134@@ -51,6 +51,8 @@
135
136 enum nf_ip_hook_priorities {
137 NF_IP_PRI_FIRST = INT_MIN,
138+ NF_IP_PRI_CONNTRACK_DEFRAG = -400,
139+ NF_IP_PRI_RAW = -300,
140 NF_IP_PRI_CONNTRACK = -200,
141 NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
142 NF_IP_PRI_MANGLE = -150,
143diff -Nur linux-2.6.0-test9.org/include/linux/netfilter_ipv6/ip6_tables.h linux-2.6.0-test9/include/linux/netfilter_ipv6/ip6_tables.h
144--- linux-2.6.0-test9.org/include/linux/netfilter_ipv6/ip6_tables.h 2003-10-25 20:44:48.000000000 +0200
145+++ linux-2.6.0-test9/include/linux/netfilter_ipv6/ip6_tables.h 2003-11-13 11:01:38.000000000 +0100
146@@ -140,6 +140,12 @@
147 /* Back pointer */
148 unsigned int comefrom;
149
150+ /* Name of the chain */
151+ char *chainname;
152+
153+ /* Rule number in the chain. */
154+ u_int32_t rulenum;
155+
156 /* Packet and byte counters. */
157 struct ip6t_counters counters;
158
159diff -Nur linux-2.6.0-test9.org/net/bridge/br_netfilter.c linux-2.6.0-test9/net/bridge/br_netfilter.c
160--- linux-2.6.0-test9.org/net/bridge/br_netfilter.c 2003-10-25 20:44:49.000000000 +0200
161+++ linux-2.6.0-test9/net/bridge/br_netfilter.c 2003-11-13 10:57:06.000000000 +0100
162@@ -297,6 +297,8 @@
163 if (skb->pkt_type == PACKET_OTHERHOST) {
164 skb->pkt_type = PACKET_HOST;
165 nf_bridge->mask |= BRNF_PKT_TYPE;
166+ /* The physdev module checks on this */
167+ nf_bridge->mask |= BRNF_BRIDGED;
168 }
169
170 nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
171diff -Nur linux-2.6.0-test9.org/net/bridge/br_netfilter.c.orig linux-2.6.0-test9/net/bridge/br_netfilter.c.orig
172--- linux-2.6.0-test9.org/net/bridge/br_netfilter.c.orig 1970-01-01 01:00:00.000000000 +0100
173+++ linux-2.6.0-test9/net/bridge/br_netfilter.c.orig 2003-10-25 20:44:49.000000000 +0200
174@@ -0,0 +1,754 @@
175+/*
176+ * Handle firewalling
177+ * Linux ethernet bridge
178+ *
179+ * Authors:
180+ * Lennert Buytenhek <buytenh@gnu.org>
181+ * Bart De Schuymer (maintainer) <bdschuym@pandora.be>
182+ *
183+ * Changes:
184+ * Apr 29 2003: physdev module support (bdschuym)
185+ * Jun 19 2003: let arptables see bridged ARP traffic (bdschuym)
186+ * Oct 06 2003: filter encapsulated IP/ARP VLAN traffic on untagged bridge
187+ * (bdschuym)
188+ *
189+ * This program is free software; you can redistribute it and/or
190+ * modify it under the terms of the GNU General Public License
191+ * as published by the Free Software Foundation; either version
192+ * 2 of the License, or (at your option) any later version.
193+ *
194+ * Lennert dedicates this file to Kerstin Wurdinger.
195+ */
196+
197+#include <linux/module.h>
198+#include <linux/kernel.h>
199+#include <linux/ip.h>
200+#include <linux/netdevice.h>
201+#include <linux/skbuff.h>
202+#include <linux/if_ether.h>
203+#include <linux/if_vlan.h>
204+#include <linux/netfilter_bridge.h>
205+#include <linux/netfilter_ipv4.h>
206+#include <linux/netfilter_arp.h>
207+#include <linux/in_route.h>
208+#include <net/ip.h>
209+#include <asm/uaccess.h>
210+#include <asm/checksum.h>
211+#include "br_private.h"
212+
213+
214+#define skb_origaddr(skb) (((struct bridge_skb_cb *) \
215+ (skb->cb))->daddr.ipv4)
216+#define store_orig_dstaddr(skb) (skb_origaddr(skb) = (skb)->nh.iph->daddr)
217+#define dnat_took_place(skb) (skb_origaddr(skb) != (skb)->nh.iph->daddr)
218+#define clear_cb(skb) (memset(&skb_origaddr(skb), 0, \
219+ sizeof(struct bridge_skb_cb)))
220+
221+#define has_bridge_parent(device) ((device)->br_port != NULL)
222+#define bridge_parent(device) ((device)->br_port->br->dev)
223+
224+#define IS_VLAN_IP (skb->protocol == __constant_htons(ETH_P_8021Q) && \
225+ hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP))
226+#define IS_VLAN_ARP (skb->protocol == __constant_htons(ETH_P_8021Q) && \
227+ hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_ARP))
228+
229+/* We need these fake structures to make netfilter happy --
230+ * lots of places assume that skb->dst != NULL, which isn't
231+ * all that unreasonable.
232+ *
233+ * Currently, we fill in the PMTU entry because netfilter
234+ * refragmentation needs it, and the rt_flags entry because
235+ * ipt_REJECT needs it. Future netfilter modules might
236+ * require us to fill additional fields.
237+ */
238+static struct net_device __fake_net_device = {
239+ .hard_header_len = ETH_HLEN
240+};
241+
242+static struct rtable __fake_rtable = {
243+ .u = {
244+ .dst = {
245+ .__refcnt = ATOMIC_INIT(1),
246+ .dev = &__fake_net_device,
247+ .path = &__fake_rtable.u.dst,
248+ .metrics = {[RTAX_MTU - 1] = 1500},
249+ }
250+ },
251+
252+ .rt_flags = 0
253+};
254+
255+
256+/* PF_BRIDGE/PRE_ROUTING *********************************************/
257+static void __br_dnat_complain(void)
258+{
259+ static unsigned long last_complaint;
260+
261+ if (jiffies - last_complaint >= 5 * HZ) {
262+ printk(KERN_WARNING "Performing cross-bridge DNAT requires IP "
263+ "forwarding to be enabled\n");
264+ last_complaint = jiffies;
265+ }
266+}
267+
268+
269+/* This requires some explaining. If DNAT has taken place,
270+ * we will need to fix up the destination Ethernet address,
271+ * and this is a tricky process.
272+ *
273+ * There are two cases to consider:
274+ * 1. The packet was DNAT'ed to a device in the same bridge
275+ * port group as it was received on. We can still bridge
276+ * the packet.
277+ * 2. The packet was DNAT'ed to a different device, either
278+ * a non-bridged device or another bridge port group.
279+ * The packet will need to be routed.
280+ *
281+ * The correct way of distinguishing between these two cases is to
282+ * call ip_route_input() and to look at skb->dst->dev, which is
283+ * changed to the destination device if ip_route_input() succeeds.
284+ *
285+ * Let us first consider the case that ip_route_input() succeeds:
286+ *
287+ * If skb->dst->dev equals the logical bridge device the packet
288+ * came in on, we can consider this bridging. We then call
289+ * skb->dst->output() which will make the packet enter br_nf_local_out()
290+ * not much later. In that function it is assured that the iptables
291+ * FORWARD chain is traversed for the packet.
292+ *
293+ * Otherwise, the packet is considered to be routed and we just
294+ * change the destination MAC address so that the packet will
295+ * later be passed up to the IP stack to be routed.
296+ *
297+ * Let us now consider the case that ip_route_input() fails:
298+ *
299+ * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input()
300+ * will fail, while __ip_route_output_key() will return success. The source
301+ * address for __ip_route_output_key() is set to zero, so __ip_route_output_key
302+ * thinks we're handling a locally generated packet and won't care
303+ * if IP forwarding is allowed. We send a warning message to the users's
304+ * log telling her to put IP forwarding on.
305+ *
306+ * ip_route_input() will also fail if there is no route available.
307+ * In that case we just drop the packet.
308+ *
309+ * --Lennert, 20020411
310+ * --Bart, 20020416 (updated)
311+ * --Bart, 20021007 (updated)
312+ */
313+
314+static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
315+{
316+#ifdef CONFIG_NETFILTER_DEBUG
317+ skb->nf_debug |= (1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_FORWARD);
318+#endif
319+
320+ if (skb->pkt_type == PACKET_OTHERHOST) {
321+ skb->pkt_type = PACKET_HOST;
322+ skb->nf_bridge->mask |= BRNF_PKT_TYPE;
323+ }
324+ skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
325+
326+ skb->dev = bridge_parent(skb->dev);
327+ if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
328+ skb_pull(skb, VLAN_HLEN);
329+ skb->nh.raw += VLAN_HLEN;
330+ }
331+ skb->dst->output(skb);
332+ return 0;
333+}
334+
335+static int br_nf_pre_routing_finish(struct sk_buff *skb)
336+{
337+ struct net_device *dev = skb->dev;
338+ struct iphdr *iph = skb->nh.iph;
339+ struct nf_bridge_info *nf_bridge = skb->nf_bridge;
340+
341+#ifdef CONFIG_NETFILTER_DEBUG
342+ skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING);
343+#endif
344+
345+ if (nf_bridge->mask & BRNF_PKT_TYPE) {
346+ skb->pkt_type = PACKET_OTHERHOST;
347+ nf_bridge->mask ^= BRNF_PKT_TYPE;
348+ }
349+ nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
350+
351+ if (dnat_took_place(skb)) {
352+ if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
353+ dev)) {
354+ struct rtable *rt;
355+ struct flowi fl = { .nl_u =
356+ { .ip4_u = { .daddr = iph->daddr, .saddr = 0 ,
357+ .tos = iph->tos} }, .proto = 0};
358+
359+ if (!ip_route_output_key(&rt, &fl)) {
360+ /* Bridged-and-DNAT'ed traffic doesn't
361+ * require ip_forwarding.
362+ */
363+ if (((struct dst_entry *)rt)->dev == dev) {
364+ skb->dst = (struct dst_entry *)rt;
365+ goto bridged_dnat;
366+ }
367+ __br_dnat_complain();
368+ dst_release((struct dst_entry *)rt);
369+ }
370+ kfree_skb(skb);
371+ return 0;
372+ } else {
373+ if (skb->dst->dev == dev) {
374+bridged_dnat:
375+ /* Tell br_nf_local_out this is a
376+ * bridged frame
377+ */
378+ nf_bridge->mask |= BRNF_BRIDGED_DNAT;
379+ skb->dev = nf_bridge->physindev;
380+ clear_cb(skb);
381+ if (skb->protocol ==
382+ __constant_htons(ETH_P_8021Q)) {
383+ skb_push(skb, VLAN_HLEN);
384+ skb->nh.raw -= VLAN_HLEN;
385+ }
386+ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
387+ skb, skb->dev, NULL,
388+ br_nf_pre_routing_finish_bridge,
389+ 1);
390+ return 0;
391+ }
392+ memcpy(skb->mac.ethernet->h_dest, dev->dev_addr,
393+ ETH_ALEN);
394+ skb->pkt_type = PACKET_HOST;
395+ }
396+ } else {
397+ skb->dst = (struct dst_entry *)&__fake_rtable;
398+ dst_hold(skb->dst);
399+ }
400+
401+ clear_cb(skb);
402+ skb->dev = nf_bridge->physindev;
403+ if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
404+ skb_push(skb, VLAN_HLEN);
405+ skb->nh.raw -= VLAN_HLEN;
406+ }
407+ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
408+ br_handle_frame_finish, 1);
409+
410+ return 0;
411+}
412+
413+/* Replicate the checks that IPv4 does on packet reception.
414+ * Set skb->dev to the bridge device (i.e. parent of the
415+ * receiving device) to make netfilter happy, the REDIRECT
416+ * target in particular. Save the original destination IP
417+ * address to be able to detect DNAT afterwards.
418+ */
419+static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
420+ const struct net_device *in, const struct net_device *out,
421+ int (*okfn)(struct sk_buff *))
422+{
423+ struct iphdr *iph;
424+ __u32 len;
425+ struct sk_buff *skb = *pskb;
426+ struct nf_bridge_info *nf_bridge;
427+
428+ if (skb->protocol != __constant_htons(ETH_P_IP)) {
429+ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)
430+ ((*pskb)->mac.ethernet);
431+
432+ if (!IS_VLAN_IP)
433+ return NF_ACCEPT;
434+ if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
435+ goto out;
436+ skb_pull(*pskb, VLAN_HLEN);
437+ (*pskb)->nh.raw += VLAN_HLEN;
438+ } else if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
439+ goto out;
440+
441+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
442+ goto inhdr_error;
443+
444+ iph = skb->nh.iph;
445+ if (iph->ihl < 5 || iph->version != 4)
446+ goto inhdr_error;
447+
448+ if (!pskb_may_pull(skb, 4*iph->ihl))
449+ goto inhdr_error;
450+
451+ iph = skb->nh.iph;
452+ if (ip_fast_csum((__u8 *)iph, iph->ihl) != 0)
453+ goto inhdr_error;
454+
455+ len = ntohs(iph->tot_len);
456+ if (skb->len < len || len < 4*iph->ihl)
457+ goto inhdr_error;
458+
459+ if (skb->len > len) {
460+ __pskb_trim(skb, len);
461+ if (skb->ip_summed == CHECKSUM_HW)
462+ skb->ip_summed = CHECKSUM_NONE;
463+ }
464+
465+#ifdef CONFIG_NETFILTER_DEBUG
466+ skb->nf_debug ^= (1 << NF_IP_PRE_ROUTING);
467+#endif
468+ if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
469+ return NF_DROP;
470+
471+ if (skb->pkt_type == PACKET_OTHERHOST) {
472+ skb->pkt_type = PACKET_HOST;
473+ nf_bridge->mask |= BRNF_PKT_TYPE;
474+ }
475+
476+ nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
477+ nf_bridge->physindev = skb->dev;
478+ skb->dev = bridge_parent(skb->dev);
479+ store_orig_dstaddr(skb);
480+
481+ NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
482+ br_nf_pre_routing_finish);
483+
484+ return NF_STOLEN;
485+
486+inhdr_error:
487+// IP_INC_STATS_BH(IpInHdrErrors);
488+out:
489+ return NF_DROP;
490+}
491+
492+
493+/* PF_BRIDGE/LOCAL_IN ************************************************/
494+/* The packet is locally destined, which requires a real
495+ * dst_entry, so detach the fake one. On the way up, the
496+ * packet would pass through PRE_ROUTING again (which already
497+ * took place when the packet entered the bridge), but we
498+ * register an IPv4 PRE_ROUTING 'sabotage' hook that will
499+ * prevent this from happening.
500+ */
501+static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
502+ const struct net_device *in, const struct net_device *out,
503+ int (*okfn)(struct sk_buff *))
504+{
505+ struct sk_buff *skb = *pskb;
506+
507+ if (skb->dst == (struct dst_entry *)&__fake_rtable) {
508+ dst_release(skb->dst);
509+ skb->dst = NULL;
510+ }
511+
512+ return NF_ACCEPT;
513+}
514+
515+/* PF_BRIDGE/FORWARD *************************************************/
516+static int br_nf_forward_finish(struct sk_buff *skb)
517+{
518+ struct nf_bridge_info *nf_bridge = skb->nf_bridge;
519+ struct net_device *in;
520+ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
521+
522+#ifdef CONFIG_NETFILTER_DEBUG
523+ skb->nf_debug ^= (1 << NF_BR_FORWARD);
524+#endif
525+
526+ if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) {
527+ in = nf_bridge->physindev;
528+ if (nf_bridge->mask & BRNF_PKT_TYPE) {
529+ skb->pkt_type = PACKET_OTHERHOST;
530+ nf_bridge->mask ^= BRNF_PKT_TYPE;
531+ }
532+ } else {
533+ in = *((struct net_device **)(skb->cb));
534+ }
535+ if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
536+ skb_push(skb, VLAN_HLEN);
537+ skb->nh.raw -= VLAN_HLEN;
538+ }
539+ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
540+ skb->dev, br_forward_finish, 1);
541+ return 0;
542+}
543+
544+/* This is the 'purely bridged' case. For IP, we pass the packet to
545+ * netfilter with indev and outdev set to the bridge device,
546+ * but we are still able to filter on the 'real' indev/outdev
547+ * because of the ipt_physdev.c module. For ARP, indev and outdev are the
548+ * bridge ports.
549+ */
550+static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb,
551+ const struct net_device *in, const struct net_device *out,
552+ int (*okfn)(struct sk_buff *))
553+{
554+ struct sk_buff *skb = *pskb;
555+ struct nf_bridge_info *nf_bridge;
556+ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
557+
558+ if (skb->protocol != __constant_htons(ETH_P_IP) &&
559+ skb->protocol != __constant_htons(ETH_P_ARP)) {
560+ if (!IS_VLAN_IP && !IS_VLAN_ARP)
561+ return NF_ACCEPT;
562+ skb_pull(*pskb, VLAN_HLEN);
563+ (*pskb)->nh.raw += VLAN_HLEN;
564+ }
565+
566+#ifdef CONFIG_NETFILTER_DEBUG
567+ skb->nf_debug ^= (1 << NF_BR_FORWARD);
568+#endif
569+ if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) {
570+ nf_bridge = skb->nf_bridge;
571+ if (skb->pkt_type == PACKET_OTHERHOST) {
572+ skb->pkt_type = PACKET_HOST;
573+ nf_bridge->mask |= BRNF_PKT_TYPE;
574+ }
575+
576+ /* The physdev module checks on this */
577+ nf_bridge->mask |= BRNF_BRIDGED;
578+ nf_bridge->physoutdev = skb->dev;
579+
580+ NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(in),
581+ bridge_parent(out), br_nf_forward_finish);
582+ } else {
583+ struct net_device **d = (struct net_device **)(skb->cb);
584+ struct arphdr *arp = skb->nh.arph;
585+
586+ if (arp->ar_pln != 4) {
587+ if (IS_VLAN_ARP) {
588+ skb_push(*pskb, VLAN_HLEN);
589+ (*pskb)->nh.raw -= VLAN_HLEN;
590+ }
591+ return NF_ACCEPT;
592+ }
593+ *d = (struct net_device *)in;
594+ NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in,
595+ (struct net_device *)out, br_nf_forward_finish);
596+ }
597+
598+ return NF_STOLEN;
599+}
600+
601+
602+/* PF_BRIDGE/LOCAL_OUT ***********************************************/
603+static int br_nf_local_out_finish(struct sk_buff *skb)
604+{
605+#ifdef CONFIG_NETFILTER_DEBUG
606+ skb->nf_debug &= ~(1 << NF_BR_LOCAL_OUT);
607+#endif
608+ if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
609+ skb_push(skb, VLAN_HLEN);
610+ skb->nh.raw -= VLAN_HLEN;
611+ }
612+
613+ NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
614+ br_forward_finish, NF_BR_PRI_FIRST + 1);
615+
616+ return 0;
617+}
618+
619+
620+/* This function sees both locally originated IP packets and forwarded
621+ * IP packets (in both cases the destination device is a bridge
622+ * device). It also sees bridged-and-DNAT'ed packets.
623+ * To be able to filter on the physical bridge devices (with the ipt_physdev.c
624+ * module), we steal packets destined to a bridge device away from the
625+ * PF_INET/FORWARD and PF_INET/OUTPUT hook functions, and give them back later,
626+ * when we have determined the real output device. This is done in here.
627+ *
628+ * If (nf_bridge->mask & BRNF_BRIDGED_DNAT) then the packet is bridged
629+ * and we fake the PF_BRIDGE/FORWARD hook. The function br_nf_forward()
630+ * will then fake the PF_INET/FORWARD hook. br_nf_local_out() has priority
631+ * NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor
632+ * will be executed.
633+ * Otherwise, if nf_bridge->physindev is NULL, the bridge-nf code never touched
634+ * this packet before, and so the packet was locally originated. We fake
635+ * the PF_INET/LOCAL_OUT hook.
636+ * Finally, if nf_bridge->physindev isn't NULL, then the packet was IP routed,
637+ * so we fake the PF_INET/FORWARD hook. ipv4_sabotage_out() makes sure
638+ * even routed packets that didn't arrive on a bridge interface have their
639+ * nf_bridge->physindev set.
640+ */
641+
642+static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
643+ const struct net_device *in, const struct net_device *out,
644+ int (*_okfn)(struct sk_buff *))
645+{
646+ int (*okfn)(struct sk_buff *skb);
647+ struct net_device *realindev;
648+ struct sk_buff *skb = *pskb;
649+ struct nf_bridge_info *nf_bridge;
650+ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
651+
652+ if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
653+ return NF_ACCEPT;
654+
655+ /* Sometimes we get packets with NULL ->dst here (for example,
656+ * running a dhcp client daemon triggers this).
657+ */
658+ if (skb->dst == NULL)
659+ return NF_ACCEPT;
660+
661+ nf_bridge = skb->nf_bridge;
662+ nf_bridge->physoutdev = skb->dev;
663+
664+ realindev = nf_bridge->physindev;
665+
666+ /* Bridged, take PF_BRIDGE/FORWARD.
667+ * (see big note in front of br_nf_pre_routing_finish)
668+ */
669+ if (nf_bridge->mask & BRNF_BRIDGED_DNAT) {
670+ okfn = br_forward_finish;
671+
672+ if (nf_bridge->mask & BRNF_PKT_TYPE) {
673+ skb->pkt_type = PACKET_OTHERHOST;
674+ nf_bridge->mask ^= BRNF_PKT_TYPE;
675+ }
676+ if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
677+ skb_push(skb, VLAN_HLEN);
678+ skb->nh.raw -= VLAN_HLEN;
679+ }
680+
681+ NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev,
682+ skb->dev, okfn);
683+ } else {
684+ struct net_device *realoutdev = bridge_parent(skb->dev);
685+
686+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
687+ /* iptables should match -o br0.x */
688+ if (nf_bridge->netoutdev)
689+ realoutdev = nf_bridge->netoutdev;
690+#endif
691+ okfn = br_nf_local_out_finish;
692+ if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
693+ skb_pull(skb, VLAN_HLEN);
694+ (*pskb)->nh.raw += VLAN_HLEN;
695+ }
696+ /* IP forwarded traffic has a physindev, locally
697+ * generated traffic hasn't.
698+ */
699+ if (realindev != NULL) {
700+ if (((nf_bridge->mask & BRNF_DONT_TAKE_PARENT) == 0) &&
701+ has_bridge_parent(realindev))
702+ realindev = bridge_parent(realindev);
703+ NF_HOOK_THRESH(PF_INET, NF_IP_FORWARD, skb, realindev,
704+ realoutdev, okfn,
705+ NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD + 1);
706+ } else {
707+#ifdef CONFIG_NETFILTER_DEBUG
708+ skb->nf_debug ^= (1 << NF_IP_LOCAL_OUT);
709+#endif
710+
711+ NF_HOOK_THRESH(PF_INET, NF_IP_LOCAL_OUT, skb, realindev,
712+ realoutdev, okfn,
713+ NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT + 1);
714+ }
715+ }
716+
717+ return NF_STOLEN;
718+}
719+
720+
721+/* PF_BRIDGE/POST_ROUTING ********************************************/
722+static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
723+ const struct net_device *in, const struct net_device *out,
724+ int (*okfn)(struct sk_buff *))
725+{
726+ struct sk_buff *skb = *pskb;
727+ struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
728+ struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
729+ struct net_device *realoutdev = bridge_parent(skb->dev);
730+
731+ /* Be very paranoid. Must be a device driver bug. */
732+ if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
733+ printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
734+ "bad mac.raw pointer.");
735+ if (skb->dev != NULL) {
736+ printk("[%s]", skb->dev->name);
737+ if (has_bridge_parent(skb->dev))
738+ printk("[%s]", bridge_parent(skb->dev)->name);
739+ }
740+ printk(" head:%p, raw:%p\n", skb->head, skb->mac.raw);
741+ return NF_ACCEPT;
742+ }
743+
744+ if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
745+ return NF_ACCEPT;
746+
747+ /* Sometimes we get packets with NULL ->dst here (for example,
748+ * running a dhcp client daemon triggers this).
749+ */
750+ if (skb->dst == NULL)
751+ return NF_ACCEPT;
752+
753+#ifdef CONFIG_NETFILTER_DEBUG
754+ skb->nf_debug ^= (1 << NF_IP_POST_ROUTING);
755+#endif
756+
757+ /* We assume any code from br_dev_queue_push_xmit onwards doesn't care
758+ * about the value of skb->pkt_type.
759+ */
760+ if (skb->pkt_type == PACKET_OTHERHOST) {
761+ skb->pkt_type = PACKET_HOST;
762+ nf_bridge->mask |= BRNF_PKT_TYPE;
763+ }
764+
765+ if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
766+ skb_pull(skb, VLAN_HLEN);
767+ skb->nh.raw += VLAN_HLEN;
768+ }
769+
770+ nf_bridge_save_header(skb);
771+
772+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
773+ if (nf_bridge->netoutdev)
774+ realoutdev = nf_bridge->netoutdev;
775+#endif
776+ NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
777+ realoutdev, br_dev_queue_push_xmit);
778+
779+ return NF_STOLEN;
780+}
781+
782+
783+/* IPv4/SABOTAGE *****************************************************/
784+
785+/* Don't hand locally destined packets to PF_INET/PRE_ROUTING
786+ * for the second time.
787+ */
788+static unsigned int ipv4_sabotage_in(unsigned int hook, struct sk_buff **pskb,
789+ const struct net_device *in, const struct net_device *out,
790+ int (*okfn)(struct sk_buff *))
791+{
792+ if ((*pskb)->nf_bridge &&
793+ !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
794+ okfn(*pskb);
795+ return NF_STOLEN;
796+ }
797+
798+ return NF_ACCEPT;
799+}
800+
801+/* Postpone execution of PF_INET/FORWARD, PF_INET/LOCAL_OUT
802+ * and PF_INET/POST_ROUTING until we have done the forwarding
803+ * decision in the bridge code and have determined skb->physoutdev.
804+ */
805+static unsigned int ipv4_sabotage_out(unsigned int hook, struct sk_buff **pskb,
806+ const struct net_device *in, const struct net_device *out,
807+ int (*okfn)(struct sk_buff *))
808+{
809+ if ((out->hard_start_xmit == br_dev_xmit &&
810+ okfn != br_nf_forward_finish &&
811+ okfn != br_nf_local_out_finish &&
812+ okfn != br_dev_queue_push_xmit)
813+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
814+ || ((out->priv_flags & IFF_802_1Q_VLAN) &&
815+ VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)
816+#endif
817+ ) {
818+ struct sk_buff *skb = *pskb;
819+ struct nf_bridge_info *nf_bridge;
820+
821+ if (!skb->nf_bridge && !nf_bridge_alloc(skb))
822+ return NF_DROP;
823+
824+ nf_bridge = skb->nf_bridge;
825+
826+ /* This frame will arrive on PF_BRIDGE/LOCAL_OUT and we
827+ * will need the indev then. For a brouter, the real indev
828+ * can be a bridge port, so we make sure br_nf_local_out()
829+ * doesn't use the bridge parent of the indev by using
830+ * the BRNF_DONT_TAKE_PARENT mask.
831+ */
832+ if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) {
833+ nf_bridge->mask &= BRNF_DONT_TAKE_PARENT;
834+ nf_bridge->physindev = (struct net_device *)in;
835+ }
836+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
837+ /* the iptables outdev is br0.x, not br0 */
838+ if (out->priv_flags & IFF_802_1Q_VLAN)
839+ nf_bridge->netoutdev = (struct net_device *)out;
840+#endif
841+ okfn(skb);
842+ return NF_STOLEN;
843+ }
844+
845+ return NF_ACCEPT;
846+}
847+
848+/* For br_nf_local_out we need (prio = NF_BR_PRI_FIRST), to insure that innocent
849+ * PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
850+ * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
851+ * ip_refrag() can return NF_STOLEN.
852+ */
853+static struct nf_hook_ops br_nf_ops[] = {
854+ { .hook = br_nf_pre_routing,
855+ .owner = THIS_MODULE,
856+ .pf = PF_BRIDGE,
857+ .hooknum = NF_BR_PRE_ROUTING,
858+ .priority = NF_BR_PRI_BRNF, },
859+ { .hook = br_nf_local_in,
860+ .owner = THIS_MODULE,
861+ .pf = PF_BRIDGE,
862+ .hooknum = NF_BR_LOCAL_IN,
863+ .priority = NF_BR_PRI_BRNF, },
864+ { .hook = br_nf_forward,
865+ .owner = THIS_MODULE,
866+ .pf = PF_BRIDGE,
867+ .hooknum = NF_BR_FORWARD,
868+ .priority = NF_BR_PRI_BRNF, },
869+ { .hook = br_nf_local_out,
870+ .owner = THIS_MODULE,
871+ .pf = PF_BRIDGE,
872+ .hooknum = NF_BR_LOCAL_OUT,
873+ .priority = NF_BR_PRI_FIRST, },
874+ { .hook = br_nf_post_routing,
875+ .owner = THIS_MODULE,
876+ .pf = PF_BRIDGE,
877+ .hooknum = NF_BR_POST_ROUTING,
878+ .priority = NF_BR_PRI_LAST, },
879+ { .hook = ipv4_sabotage_in,
880+ .owner = THIS_MODULE,
881+ .pf = PF_INET,
882+ .hooknum = NF_IP_PRE_ROUTING,
883+ .priority = NF_IP_PRI_FIRST, },
884+ { .hook = ipv4_sabotage_out,
885+ .owner = THIS_MODULE,
886+ .pf = PF_INET,
887+ .hooknum = NF_IP_FORWARD,
888+ .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD, },
889+ { .hook = ipv4_sabotage_out,
890+ .owner = THIS_MODULE,
891+ .pf = PF_INET,
892+ .hooknum = NF_IP_LOCAL_OUT,
893+ .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
894+ { .hook = ipv4_sabotage_out,
895+ .owner = THIS_MODULE,
896+ .pf = PF_INET,
897+ .hooknum = NF_IP_POST_ROUTING,
898+ .priority = NF_IP_PRI_FIRST, },
899+};
900+
901+int br_netfilter_init(void)
902+{
903+ int i;
904+
905+ for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) {
906+ int ret;
907+
908+ if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0)
909+ continue;
910+
911+ while (i--)
912+ nf_unregister_hook(&br_nf_ops[i]);
913+
914+ return ret;
915+ }
916+
917+ printk(KERN_NOTICE "Bridge firewalling registered\n");
918+
919+ return 0;
920+}
921+
922+void br_netfilter_fini(void)
923+{
924+ int i;
925+
926+ for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--)
927+ nf_unregister_hook(&br_nf_ops[i]);
928+}
929diff -Nur linux-2.6.0-test9.org/net/core/netfilter.c linux-2.6.0-test9/net/core/netfilter.c
930--- linux-2.6.0-test9.org/net/core/netfilter.c 2003-10-25 20:43:34.000000000 +0200
931+++ linux-2.6.0-test9/net/core/netfilter.c 2003-11-13 11:01:18.000000000 +0100
932@@ -8,8 +8,10 @@
933 *
934 * February 2000: Modified by James Morris to have 1 queue per protocol.
935 * 15-Mar-2000: Added NF_REPEAT --RR.
936+ * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
937 */
938 #include <linux/config.h>
939+#include <linux/kernel.h>
940 #include <linux/netfilter.h>
941 #include <net/protocol.h>
942 #include <linux/init.h>
943@@ -743,7 +745,70 @@
944 EXPORT_SYMBOL(skb_ip_make_writable);
945 #endif /*CONFIG_INET*/
946
947+/* Internal logging interface, which relies on the real
948+ LOG target modules */
949
950+#define NF_LOG_PREFIXLEN 128
951+
952+static nf_logfn *nf_logging[NPROTO]; /* = NULL */
953+static int reported = 0;
954+static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
955+
956+int nf_log_register(int pf, nf_logfn *logfn)
957+{
958+ int ret = -EBUSY;
959+
960+ /* Any setup of logging members must be done before
961+ * substituting pointer. */
962+ smp_wmb();
963+ spin_lock(&nf_log_lock);
964+ if (!nf_logging[pf]) {
965+ nf_logging[pf] = logfn;
966+ ret = 0;
967+ }
968+ spin_unlock(&nf_log_lock);
969+ return ret;
970+}
971+
972+void nf_log_unregister(int pf, nf_logfn *logfn)
973+{
974+ spin_lock(&nf_log_lock);
975+ if (nf_logging[pf] == logfn)
976+ nf_logging[pf] = NULL;
977+ spin_unlock(&nf_log_lock);
978+
979+ /* Give time to concurrent readers. */
980+ synchronize_net();
981+}
982+
983+void nf_log_packet(int pf,
984+ unsigned int hooknum,
985+ const struct sk_buff *skb,
986+ const struct net_device *in,
987+ const struct net_device *out,
988+ const char *fmt, ...)
989+{
990+ va_list args;
991+ char prefix[NF_LOG_PREFIXLEN];
992+ nf_logfn *logfn;
993+
994+ rcu_read_lock();
995+ logfn = nf_logging[pf];
996+ if (logfn) {
997+ va_start(args, fmt);
998+ vsnprintf(prefix, sizeof(prefix), fmt, args);
999+ va_end(args);
1000+ /* We must read logging before nf_logfn[pf] */
1001+ smp_read_barrier_depends();
1002+ logfn(hooknum, skb, in, out, prefix);
1003+ } else if (!reported) {
1004+ printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
1005+ "no backend logging module loaded in!\n");
1006+ reported++;
1007+ }
1008+ rcu_read_unlock();
1009+}
1010+
1011 /* This does not belong here, but ipt_REJECT needs it if connection
1012 tracking in use: without this, connection may not be in hash table,
1013 and hence manufactured ICMP or RST packets will not be associated
1014@@ -763,6 +828,9 @@
1015 EXPORT_SYMBOL(ip_ct_attach);
1016 EXPORT_SYMBOL(ip_route_me_harder);
1017 EXPORT_SYMBOL(nf_getsockopt);
1018+EXPORT_SYMBOL(nf_log_register);
1019+EXPORT_SYMBOL(nf_log_unregister);
1020+EXPORT_SYMBOL(nf_log_packet);
1021 EXPORT_SYMBOL(nf_hook_slow);
1022 EXPORT_SYMBOL(nf_hooks);
1023 EXPORT_SYMBOL(nf_register_hook);
1024diff -Nur linux-2.6.0-test9.org/net/core/netfilter.c.orig linux-2.6.0-test9/net/core/netfilter.c.orig
1025--- linux-2.6.0-test9.org/net/core/netfilter.c.orig 1970-01-01 01:00:00.000000000 +0100
1026+++ linux-2.6.0-test9/net/core/netfilter.c.orig 2003-11-13 11:01:18.000000000 +0100
1027@@ -0,0 +1,840 @@
1028+/* netfilter.c: look after the filters for various protocols.
1029+ * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
1030+ *
1031+ * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
1032+ * way.
1033+ *
1034+ * Rusty Russell (C)2000 -- This code is GPL.
1035+ *
1036+ * February 2000: Modified by James Morris to have 1 queue per protocol.
1037+ * 15-Mar-2000: Added NF_REPEAT --RR.
1038+ * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
1039+ */
1040+#include <linux/config.h>
1041+#include <linux/kernel.h>
1042+#include <linux/netfilter.h>
1043+#include <net/protocol.h>
1044+#include <linux/init.h>
1045+#include <linux/skbuff.h>
1046+#include <linux/wait.h>
1047+#include <linux/module.h>
1048+#include <linux/interrupt.h>
1049+#include <linux/if.h>
1050+#include <linux/netdevice.h>
1051+#include <linux/inetdevice.h>
1052+#include <linux/tcp.h>
1053+#include <linux/udp.h>
1054+#include <linux/icmp.h>
1055+#include <net/sock.h>
1056+#include <net/route.h>
1057+#include <linux/ip.h>
1058+
1059+#define __KERNEL_SYSCALLS__
1060+#include <linux/unistd.h>
1061+
1062+/* In this code, we can be waiting indefinitely for userspace to
1063+ * service a packet if a hook returns NF_QUEUE. We could keep a count
1064+ * of skbuffs queued for userspace, and not deregister a hook unless
1065+ * this is zero, but that sucks. Now, we simply check when the
1066+ * packets come back: if the hook is gone, the packet is discarded. */
1067+#ifdef CONFIG_NETFILTER_DEBUG
1068+#define NFDEBUG(format, args...) printk(format , ## args)
1069+#else
1070+#define NFDEBUG(format, args...)
1071+#endif
1072+
1073+/* Sockopts only registered and called from user context, so
1074+ net locking would be overkill. Also, [gs]etsockopt calls may
1075+ sleep. */
1076+static DECLARE_MUTEX(nf_sockopt_mutex);
1077+
1078+struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
1079+static LIST_HEAD(nf_sockopts);
1080+static spinlock_t nf_hook_lock = SPIN_LOCK_UNLOCKED;
1081+
1082+/*
1083+ * A queue handler may be registered for each protocol. Each is protected by
1084+ * long term mutex. The handler must provide an an outfn() to accept packets
1085+ * for queueing and must reinject all packets it receives, no matter what.
1086+ */
1087+static struct nf_queue_handler_t {
1088+ nf_queue_outfn_t outfn;
1089+ void *data;
1090+} queue_handler[NPROTO];
1091+static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
1092+
1093+int nf_register_hook(struct nf_hook_ops *reg)
1094+{
1095+ struct list_head *i;
1096+
1097+ spin_lock_bh(&nf_hook_lock);
1098+ list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
1099+ if (reg->priority < ((struct nf_hook_ops *)i)->priority)
1100+ break;
1101+ }
1102+ list_add_rcu(&reg->list, i->prev);
1103+ spin_unlock_bh(&nf_hook_lock);
1104+
1105+ synchronize_net();
1106+ return 0;
1107+}
1108+
1109+void nf_unregister_hook(struct nf_hook_ops *reg)
1110+{
1111+ spin_lock_bh(&nf_hook_lock);
1112+ list_del_rcu(&reg->list);
1113+ spin_unlock_bh(&nf_hook_lock);
1114+
1115+ synchronize_net();
1116+}
1117+
1118+/* Do exclusive ranges overlap? */
1119+static inline int overlap(int min1, int max1, int min2, int max2)
1120+{
1121+ return max1 > min2 && min1 < max2;
1122+}
1123+
1124+/* Functions to register sockopt ranges (exclusive). */
1125+int nf_register_sockopt(struct nf_sockopt_ops *reg)
1126+{
1127+ struct list_head *i;
1128+ int ret = 0;
1129+
1130+ if (down_interruptible(&nf_sockopt_mutex) != 0)
1131+ return -EINTR;
1132+
1133+ list_for_each(i, &nf_sockopts) {
1134+ struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
1135+ if (ops->pf == reg->pf
1136+ && (overlap(ops->set_optmin, ops->set_optmax,
1137+ reg->set_optmin, reg->set_optmax)
1138+ || overlap(ops->get_optmin, ops->get_optmax,
1139+ reg->get_optmin, reg->get_optmax))) {
1140+ NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
1141+ ops->set_optmin, ops->set_optmax,
1142+ ops->get_optmin, ops->get_optmax,
1143+ reg->set_optmin, reg->set_optmax,
1144+ reg->get_optmin, reg->get_optmax);
1145+ ret = -EBUSY;
1146+ goto out;
1147+ }
1148+ }
1149+
1150+ list_add(&reg->list, &nf_sockopts);
1151+out:
1152+ up(&nf_sockopt_mutex);
1153+ return ret;
1154+}
1155+
1156+void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
1157+{
1158+ /* No point being interruptible: we're probably in cleanup_module() */
1159+ restart:
1160+ down(&nf_sockopt_mutex);
1161+ if (reg->use != 0) {
1162+ /* To be woken by nf_sockopt call... */
1163+ /* FIXME: Stuart Young's name appears gratuitously. */
1164+ set_current_state(TASK_UNINTERRUPTIBLE);
1165+ reg->cleanup_task = current;
1166+ up(&nf_sockopt_mutex);
1167+ schedule();
1168+ goto restart;
1169+ }
1170+ list_del(&reg->list);
1171+ up(&nf_sockopt_mutex);
1172+}
1173+
1174+#ifdef CONFIG_NETFILTER_DEBUG
1175+#include <net/ip.h>
1176+#include <net/tcp.h>
1177+#include <linux/netfilter_ipv4.h>
1178+
1179+static void debug_print_hooks_ip(unsigned int nf_debug)
1180+{
1181+ if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
1182+ printk("PRE_ROUTING ");
1183+ nf_debug ^= (1 << NF_IP_PRE_ROUTING);
1184+ }
1185+ if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
1186+ printk("LOCAL_IN ");
1187+ nf_debug ^= (1 << NF_IP_LOCAL_IN);
1188+ }
1189+ if (nf_debug & (1 << NF_IP_FORWARD)) {
1190+ printk("FORWARD ");
1191+ nf_debug ^= (1 << NF_IP_FORWARD);
1192+ }
1193+ if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
1194+ printk("LOCAL_OUT ");
1195+ nf_debug ^= (1 << NF_IP_LOCAL_OUT);
1196+ }
1197+ if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
1198+ printk("POST_ROUTING ");
1199+ nf_debug ^= (1 << NF_IP_POST_ROUTING);
1200+ }
1201+ if (nf_debug)
1202+ printk("Crap bits: 0x%04X", nf_debug);
1203+ printk("\n");
1204+}
1205+
1206+void nf_dump_skb(int pf, struct sk_buff *skb)
1207+{
1208+ printk("skb: pf=%i %s dev=%s len=%u\n",
1209+ pf,
1210+ skb->sk ? "(owned)" : "(unowned)",
1211+ skb->dev ? skb->dev->name : "(no dev)",
1212+ skb->len);
1213+ switch (pf) {
1214+ case PF_INET: {
1215+ const struct iphdr *ip = skb->nh.iph;
1216+ __u32 *opt = (__u32 *) (ip + 1);
1217+ int opti;
1218+ __u16 src_port = 0, dst_port = 0;
1219+
1220+ if (ip->protocol == IPPROTO_TCP
1221+ || ip->protocol == IPPROTO_UDP) {
1222+ struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
1223+ src_port = ntohs(tcp->source);
1224+ dst_port = ntohs(tcp->dest);
1225+ }
1226+
1227+ printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
1228+ " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
1229+ ip->protocol, NIPQUAD(ip->saddr),
1230+ src_port, NIPQUAD(ip->daddr),
1231+ dst_port,
1232+ ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
1233+ ntohs(ip->frag_off), ip->ttl);
1234+
1235+ for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
1236+ printk(" O=0x%8.8X", *opt++);
1237+ printk("\n");
1238+ }
1239+ }
1240+}
1241+
1242+void nf_debug_ip_local_deliver(struct sk_buff *skb)
1243+{
1244+ /* If it's a loopback packet, it must have come through
1245+ * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and
1246+ * NF_IP_LOCAL_IN. Otherwise, must have gone through
1247+ * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */
1248+ if (!skb->dev) {
1249+ printk("ip_local_deliver: skb->dev is NULL.\n");
1250+ }
1251+ else if (strcmp(skb->dev->name, "lo") == 0) {
1252+ if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
1253+ | (1 << NF_IP_POST_ROUTING)
1254+ | (1 << NF_IP_PRE_ROUTING)
1255+ | (1 << NF_IP_LOCAL_IN))) {
1256+ printk("ip_local_deliver: bad loopback skb: ");
1257+ debug_print_hooks_ip(skb->nf_debug);
1258+ nf_dump_skb(PF_INET, skb);
1259+ }
1260+ }
1261+ else {
1262+ if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)
1263+ | (1<<NF_IP_LOCAL_IN))) {
1264+ printk("ip_local_deliver: bad non-lo skb: ");
1265+ debug_print_hooks_ip(skb->nf_debug);
1266+ nf_dump_skb(PF_INET, skb);
1267+ }
1268+ }
1269+}
1270+
1271+void nf_debug_ip_loopback_xmit(struct sk_buff *newskb)
1272+{
1273+ if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
1274+ | (1 << NF_IP_POST_ROUTING))) {
1275+ printk("ip_dev_loopback_xmit: bad owned skb = %p: ",
1276+ newskb);
1277+ debug_print_hooks_ip(newskb->nf_debug);
1278+ nf_dump_skb(PF_INET, newskb);
1279+ }
1280+ /* Clear to avoid confusing input check */
1281+ newskb->nf_debug = 0;
1282+}
1283+
1284+void nf_debug_ip_finish_output2(struct sk_buff *skb)
1285+{
1286+ /* If it's owned, it must have gone through the
1287+ * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING.
1288+ * Otherwise, must have gone through
1289+ * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING.
1290+ */
1291+ if (skb->sk) {
1292+ if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
1293+ | (1 << NF_IP_POST_ROUTING))) {
1294+ printk("ip_finish_output: bad owned skb = %p: ", skb);
1295+ debug_print_hooks_ip(skb->nf_debug);
1296+ nf_dump_skb(PF_INET, skb);
1297+ }
1298+ } else {
1299+ if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING)
1300+ | (1 << NF_IP_FORWARD)
1301+ | (1 << NF_IP_POST_ROUTING))) {
1302+ /* Fragments, entunnelled packets, TCP RSTs
1303+ generated by ipt_REJECT will have no
1304+ owners, but still may be local */
1305+ if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
1306+ | (1 << NF_IP_POST_ROUTING))){
1307+ printk("ip_finish_output:"
1308+ " bad unowned skb = %p: ",skb);
1309+ debug_print_hooks_ip(skb->nf_debug);
1310+ nf_dump_skb(PF_INET, skb);
1311+ }
1312+ }
1313+ }
1314+}
1315+#endif /*CONFIG_NETFILTER_DEBUG*/
1316+
1317+/* Call get/setsockopt() */
1318+static int nf_sockopt(struct sock *sk, int pf, int val,
1319+ char *opt, int *len, int get)
1320+{
1321+ struct list_head *i;
1322+ struct nf_sockopt_ops *ops;
1323+ int ret;
1324+
1325+ if (down_interruptible(&nf_sockopt_mutex) != 0)
1326+ return -EINTR;
1327+
1328+ list_for_each(i, &nf_sockopts) {
1329+ ops = (struct nf_sockopt_ops *)i;
1330+ if (ops->pf == pf) {
1331+ if (get) {
1332+ if (val >= ops->get_optmin
1333+ && val < ops->get_optmax) {
1334+ ops->use++;
1335+ up(&nf_sockopt_mutex);
1336+ ret = ops->get(sk, val, opt, len);
1337+ goto out;
1338+ }
1339+ } else {
1340+ if (val >= ops->set_optmin
1341+ && val < ops->set_optmax) {
1342+ ops->use++;
1343+ up(&nf_sockopt_mutex);
1344+ ret = ops->set(sk, val, opt, *len);
1345+ goto out;
1346+ }
1347+ }
1348+ }
1349+ }
1350+ up(&nf_sockopt_mutex);
1351+ return -ENOPROTOOPT;
1352+
1353+ out:
1354+ down(&nf_sockopt_mutex);
1355+ ops->use--;
1356+ if (ops->cleanup_task)
1357+ wake_up_process(ops->cleanup_task);
1358+ up(&nf_sockopt_mutex);
1359+ return ret;
1360+}
1361+
1362+int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
1363+ int len)
1364+{
1365+ return nf_sockopt(sk, pf, val, opt, &len, 0);
1366+}
1367+
1368+int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
1369+{
1370+ return nf_sockopt(sk, pf, val, opt, len, 1);
1371+}
1372+
1373+static unsigned int nf_iterate(struct list_head *head,
1374+ struct sk_buff **skb,
1375+ int hook,
1376+ const struct net_device *indev,
1377+ const struct net_device *outdev,
1378+ struct list_head **i,
1379+ int (*okfn)(struct sk_buff *),
1380+ int hook_thresh)
1381+{
1382+ /*
1383+ * The caller must not block between calls to this
1384+ * function because of risk of continuing from deleted element.
1385+ */
1386+ list_for_each_continue_rcu(*i, head) {
1387+ struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
1388+
1389+ if (hook_thresh > elem->priority)
1390+ continue;
1391+
1392+ /* Optimization: we don't need to hold module
1393+ reference here, since function can't sleep. --RR */
1394+ switch (elem->hook(hook, skb, indev, outdev, okfn)) {
1395+ case NF_QUEUE:
1396+ return NF_QUEUE;
1397+
1398+ case NF_STOLEN:
1399+ return NF_STOLEN;
1400+
1401+ case NF_DROP:
1402+ return NF_DROP;
1403+
1404+ case NF_REPEAT:
1405+ *i = (*i)->prev;
1406+ break;
1407+
1408+#ifdef CONFIG_NETFILTER_DEBUG
1409+ case NF_ACCEPT:
1410+ break;
1411+
1412+ default:
1413+ NFDEBUG("Evil return from %p(%u).\n",
1414+ elem->hook, hook);
1415+#endif
1416+ }
1417+ }
1418+ return NF_ACCEPT;
1419+}
1420+
1421+int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
1422+{
1423+ int ret;
1424+
1425+ write_lock_bh(&queue_handler_lock);
1426+ if (queue_handler[pf].outfn)
1427+ ret = -EBUSY;
1428+ else {
1429+ queue_handler[pf].outfn = outfn;
1430+ queue_handler[pf].data = data;
1431+ ret = 0;
1432+ }
1433+ write_unlock_bh(&queue_handler_lock);
1434+
1435+ return ret;
1436+}
1437+
1438+/* The caller must flush their queue before this */
1439+int nf_unregister_queue_handler(int pf)
1440+{
1441+ write_lock_bh(&queue_handler_lock);
1442+ queue_handler[pf].outfn = NULL;
1443+ queue_handler[pf].data = NULL;
1444+ write_unlock_bh(&queue_handler_lock);
1445+
1446+ return 0;
1447+}
1448+
1449+/*
1450+ * Any packet that leaves via this function must come back
1451+ * through nf_reinject().
1452+ */
1453+static int nf_queue(struct sk_buff *skb,
1454+ struct list_head *elem,
1455+ int pf, unsigned int hook,
1456+ struct net_device *indev,
1457+ struct net_device *outdev,
1458+ int (*okfn)(struct sk_buff *))
1459+{
1460+ int status;
1461+ struct nf_info *info;
1462+#ifdef CONFIG_BRIDGE_NETFILTER
1463+ struct net_device *physindev = NULL;
1464+ struct net_device *physoutdev = NULL;
1465+#endif
1466+
1467+ /* QUEUE == DROP if noone is waiting, to be safe. */
1468+ read_lock(&queue_handler_lock);
1469+ if (!queue_handler[pf].outfn) {
1470+ read_unlock(&queue_handler_lock);
1471+ kfree_skb(skb);
1472+ return 1;
1473+ }
1474+
1475+ info = kmalloc(sizeof(*info), GFP_ATOMIC);
1476+ if (!info) {
1477+ if (net_ratelimit())
1478+ printk(KERN_ERR "OOM queueing packet %p\n",
1479+ skb);
1480+ read_unlock(&queue_handler_lock);
1481+ kfree_skb(skb);
1482+ return 1;
1483+ }
1484+
1485+ *info = (struct nf_info) {
1486+ (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
1487+
1488+ /* If it's going away, ignore hook. */
1489+ if (!try_module_get(info->elem->owner)) {
1490+ read_unlock(&queue_handler_lock);
1491+ kfree(info);
1492+ return 0;
1493+ }
1494+
1495+ /* Bump dev refs so they don't vanish while packet is out */
1496+ if (indev) dev_hold(indev);
1497+ if (outdev) dev_hold(outdev);
1498+
1499+#ifdef CONFIG_BRIDGE_NETFILTER
1500+ if (skb->nf_bridge) {
1501+ physindev = skb->nf_bridge->physindev;
1502+ if (physindev) dev_hold(physindev);
1503+ physoutdev = skb->nf_bridge->physoutdev;
1504+ if (physoutdev) dev_hold(physoutdev);
1505+ }
1506+#endif
1507+
1508+ status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
1509+ read_unlock(&queue_handler_lock);
1510+
1511+ if (status < 0) {
1512+ /* James M doesn't say fuck enough. */
1513+ if (indev) dev_put(indev);
1514+ if (outdev) dev_put(outdev);
1515+#ifdef CONFIG_BRIDGE_NETFILTER
1516+ if (physindev) dev_put(physindev);
1517+ if (physoutdev) dev_put(physoutdev);
1518+#endif
1519+ module_put(info->elem->owner);
1520+ kfree(info);
1521+ kfree_skb(skb);
1522+ return 1;
1523+ }
1524+ return 1;
1525+}
1526+
1527+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
1528+ struct net_device *indev,
1529+ struct net_device *outdev,
1530+ int (*okfn)(struct sk_buff *),
1531+ int hook_thresh)
1532+{
1533+ struct list_head *elem;
1534+ unsigned int verdict;
1535+ int ret = 0;
1536+
1537+ if (skb->ip_summed == CHECKSUM_HW) {
1538+ if (outdev == NULL) {
1539+ skb->ip_summed = CHECKSUM_NONE;
1540+ } else {
1541+ skb_checksum_help(skb);
1542+ }
1543+ }
1544+
1545+ /* We may already have this, but read-locks nest anyway */
1546+ rcu_read_lock();
1547+
1548+#ifdef CONFIG_NETFILTER_DEBUG
1549+ if (skb->nf_debug & (1 << hook)) {
1550+ printk("nf_hook: hook %i already set.\n", hook);
1551+ nf_dump_skb(pf, skb);
1552+ }
1553+ skb->nf_debug |= (1 << hook);
1554+#endif
1555+
1556+ elem = &nf_hooks[pf][hook];
1557+ next_hook:
1558+ verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
1559+ outdev, &elem, okfn, hook_thresh);
1560+ if (verdict == NF_QUEUE) {
1561+ NFDEBUG("nf_hook: Verdict = QUEUE.\n");
1562+ if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn))
1563+ goto next_hook;
1564+ }
1565+
1566+ switch (verdict) {
1567+ case NF_ACCEPT:
1568+ ret = okfn(skb);
1569+ break;
1570+
1571+ case NF_DROP:
1572+ kfree_skb(skb);
1573+ ret = -EPERM;
1574+ break;
1575+ }
1576+
1577+ rcu_read_unlock();
1578+ return ret;
1579+}
1580+
1581+void nf_reinject(struct sk_buff *skb, struct nf_info *info,
1582+ unsigned int verdict)
1583+{
1584+ struct list_head *elem = &info->elem->list;
1585+ struct list_head *i;
1586+
1587+ rcu_read_lock();
1588+
1589+ /* Release those devices we held, or Alexey will kill me. */
1590+ if (info->indev) dev_put(info->indev);
1591+ if (info->outdev) dev_put(info->outdev);
1592+#ifdef CONFIG_BRIDGE_NETFILTER
1593+ if (skb->nf_bridge) {
1594+ if (skb->nf_bridge->physindev)
1595+ dev_put(skb->nf_bridge->physindev);
1596+ if (skb->nf_bridge->physoutdev)
1597+ dev_put(skb->nf_bridge->physoutdev);
1598+ }
1599+#endif
1600+
1601+ /* Drop reference to owner of hook which queued us. */
1602+ module_put(info->elem->owner);
1603+
1604+ list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
1605+ if (i == elem)
1606+ break;
1607+ }
1608+
1609+ if (elem == &nf_hooks[info->pf][info->hook]) {
1610+ /* The module which sent it to userspace is gone. */
1611+ NFDEBUG("%s: module disappeared, dropping packet.\n",
1612+ __FUNCTION__);
1613+ verdict = NF_DROP;
1614+ }
1615+
1616+ /* Continue traversal iff userspace said ok... */
1617+ if (verdict == NF_REPEAT) {
1618+ elem = elem->prev;
1619+ verdict = NF_ACCEPT;
1620+ }
1621+
1622+ if (verdict == NF_ACCEPT) {
1623+ next_hook:
1624+ verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
1625+ &skb, info->hook,
1626+ info->indev, info->outdev, &elem,
1627+ info->okfn, INT_MIN);
1628+ }
1629+
1630+ switch (verdict) {
1631+ case NF_ACCEPT:
1632+ info->okfn(skb);
1633+ break;
1634+
1635+ case NF_QUEUE:
1636+ if (!nf_queue(skb, elem, info->pf, info->hook,
1637+ info->indev, info->outdev, info->okfn))
1638+ goto next_hook;
1639+ break;
1640+ }
1641+ rcu_read_unlock();
1642+
1643+ if (verdict == NF_DROP)
1644+ kfree_skb(skb);
1645+
1646+ kfree(info);
1647+ return;
1648+}
1649+
1650+#ifdef CONFIG_INET
1651+/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
1652+int ip_route_me_harder(struct sk_buff **pskb)
1653+{
1654+ struct iphdr *iph = (*pskb)->nh.iph;
1655+ struct rtable *rt;
1656+ struct flowi fl = {};
1657+ struct dst_entry *odst;
1658+ unsigned int hh_len;
1659+
1660+ /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
1661+ * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
1662+ */
1663+ if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
1664+ fl.nl_u.ip4_u.daddr = iph->daddr;
1665+ fl.nl_u.ip4_u.saddr = iph->saddr;
1666+ fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
1667+ fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
1668+#ifdef CONFIG_IP_ROUTE_FWMARK
1669+ fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
1670+#endif
1671+ if (ip_route_output_key(&rt, &fl) != 0)
1672+ return -1;
1673+
1674+ /* Drop old route. */
1675+ dst_release((*pskb)->dst);
1676+ (*pskb)->dst = &rt->u.dst;
1677+ } else {
1678+ /* non-local src, find valid iif to satisfy
1679+ * rp-filter when calling ip_route_input. */
1680+ fl.nl_u.ip4_u.daddr = iph->saddr;
1681+ if (ip_route_output_key(&rt, &fl) != 0)
1682+ return -1;
1683+
1684+ odst = (*pskb)->dst;
1685+ if (ip_route_input(*pskb, iph->daddr, iph->saddr,
1686+ RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
1687+ dst_release(&rt->u.dst);
1688+ return -1;
1689+ }
1690+ dst_release(&rt->u.dst);
1691+ dst_release(odst);
1692+ }
1693+
1694+ if ((*pskb)->dst->error)
1695+ return -1;
1696+
1697+ /* Change in oif may mean change in hh_len. */
1698+ hh_len = (*pskb)->dst->dev->hard_header_len;
1699+ if (skb_headroom(*pskb) < hh_len) {
1700+ struct sk_buff *nskb;
1701+
1702+ nskb = skb_realloc_headroom(*pskb, hh_len);
1703+ if (!nskb)
1704+ return -1;
1705+ if ((*pskb)->sk)
1706+ skb_set_owner_w(nskb, (*pskb)->sk);
1707+ kfree_skb(*pskb);
1708+ *pskb = nskb;
1709+ }
1710+
1711+ return 0;
1712+}
1713+
1714+int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
1715+{
1716+ struct sk_buff *nskb;
1717+ unsigned int iplen;
1718+
1719+ if (writable_len > (*pskb)->len)
1720+ return 0;
1721+
1722+ /* Not exclusive use of packet? Must copy. */
1723+ if (skb_shared(*pskb) || skb_cloned(*pskb))
1724+ goto copy_skb;
1725+
1726+ /* Alexey says IP hdr is always modifiable and linear, so ok. */
1727+ if (writable_len <= (*pskb)->nh.iph->ihl*4)
1728+ return 1;
1729+
1730+ iplen = writable_len - (*pskb)->nh.iph->ihl*4;
1731+
1732+ /* DaveM says protocol headers are also modifiable. */
1733+ switch ((*pskb)->nh.iph->protocol) {
1734+ case IPPROTO_TCP: {
1735+ struct tcphdr hdr;
1736+ if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
1737+ &hdr, sizeof(hdr)) != 0)
1738+ goto copy_skb;
1739+ if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
1740+ goto pull_skb;
1741+ goto copy_skb;
1742+ }
1743+ case IPPROTO_UDP:
1744+ if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
1745+ goto pull_skb;
1746+ goto copy_skb;
1747+ case IPPROTO_ICMP:
1748+ if (writable_len
1749+ <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
1750+ goto pull_skb;
1751+ goto copy_skb;
1752+ /* Insert other cases here as desired */
1753+ }
1754+
1755+copy_skb:
1756+ nskb = skb_copy(*pskb, GFP_ATOMIC);
1757+ if (!nskb)
1758+ return 0;
1759+ BUG_ON(skb_is_nonlinear(nskb));
1760+
1761+ /* Rest of kernel will get very unhappy if we pass it a
1762+ suddenly-orphaned skbuff */
1763+ if ((*pskb)->sk)
1764+ skb_set_owner_w(nskb, (*pskb)->sk);
1765+ kfree_skb(*pskb);
1766+ *pskb = nskb;
1767+ return 1;
1768+
1769+pull_skb:
1770+ return pskb_may_pull(*pskb, writable_len);
1771+}
1772+EXPORT_SYMBOL(skb_ip_make_writable);
1773+#endif /*CONFIG_INET*/
1774+
1775+/* Internal logging interface, which relies on the real
1776+ LOG target modules */
1777+
1778+#define NF_LOG_PREFIXLEN 128
1779+
1780+static nf_logfn *nf_logging[NPROTO]; /* = NULL */
1781+static int reported = 0;
1782+static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
1783+
1784+int nf_log_register(int pf, nf_logfn *logfn)
1785+{
1786+ int ret = -EBUSY;
1787+
1788+ /* Any setup of logging members must be done before
1789+ * substituting pointer. */
1790+ smp_wmb();
1791+ spin_lock(&nf_log_lock);
1792+ if (!nf_logging[pf]) {
1793+ nf_logging[pf] = logfn;
1794+ ret = 0;
1795+ }
1796+ spin_unlock(&nf_log_lock);
1797+ return ret;
1798+}
1799+
1800+void nf_log_unregister(int pf, nf_logfn *logfn)
1801+{
1802+ spin_lock(&nf_log_lock);
1803+ if (nf_logging[pf] == logfn)
1804+ nf_logging[pf] = NULL;
1805+ spin_unlock(&nf_log_lock);
1806+
1807+ /* Give time to concurrent readers. */
1808+ synchronize_net();
1809+}
1810+
1811+void nf_log_packet(int pf,
1812+ unsigned int hooknum,
1813+ const struct sk_buff *skb,
1814+ const struct net_device *in,
1815+ const struct net_device *out,
1816+ const char *fmt, ...)
1817+{
1818+ va_list args;
1819+ char prefix[NF_LOG_PREFIXLEN];
1820+ nf_logfn *logfn;
1821+
1822+ rcu_read_lock();
1823+ logfn = nf_logging[pf];
1824+ if (logfn) {
1825+ va_start(args, fmt);
1826+ vsnprintf(prefix, sizeof(prefix), fmt, args);
1827+ va_end(args);
1828+ /* We must read logging before nf_logfn[pf] */
1829+ smp_read_barrier_depends();
1830+ logfn(hooknum, skb, in, out, prefix);
1831+ } else if (!reported) {
1832+ printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
1833+ "no backend logging module loaded in!\n");
1834+ reported++;
1835+ }
1836+ rcu_read_unlock();
1837+}
1838+
1839+/* This does not belong here, but ipt_REJECT needs it if connection
1840+ tracking in use: without this, connection may not be in hash table,
1841+ and hence manufactured ICMP or RST packets will not be associated
1842+ with it. */
1843+void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
1844+
1845+void __init netfilter_init(void)
1846+{
1847+ int i, h;
1848+
1849+ for (i = 0; i < NPROTO; i++) {
1850+ for (h = 0; h < NF_MAX_HOOKS; h++)
1851+ INIT_LIST_HEAD(&nf_hooks[i][h]);
1852+ }
1853+}
1854+
1855+EXPORT_SYMBOL(ip_ct_attach);
1856+EXPORT_SYMBOL(ip_route_me_harder);
1857+EXPORT_SYMBOL(nf_getsockopt);
1858+EXPORT_SYMBOL(nf_hook_slow);
1859+EXPORT_SYMBOL(nf_hooks);
1860+EXPORT_SYMBOL(nf_register_hook);
1861+EXPORT_SYMBOL(nf_register_queue_handler);
1862+EXPORT_SYMBOL(nf_register_sockopt);
1863+EXPORT_SYMBOL(nf_reinject);
1864+EXPORT_SYMBOL(nf_setsockopt);
1865+EXPORT_SYMBOL(nf_unregister_hook);
1866+EXPORT_SYMBOL(nf_unregister_queue_handler);
1867+EXPORT_SYMBOL(nf_unregister_sockopt);
1868diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/Kconfig linux-2.6.0-test9/net/ipv4/netfilter/Kconfig
1869--- linux-2.6.0-test9.org/net/ipv4/netfilter/Kconfig 2003-11-13 11:07:50.000000000 +0100
1870+++ linux-2.6.0-test9/net/ipv4/netfilter/Kconfig 2003-11-13 11:01:48.000000000 +0100
1871@@ -197,6 +197,15 @@
1872
1873 To compile it as a module, choose M here. If unsure, say N.
1874
1875+config IP_NF_MATCH_SCTP
1876+ tristate "SCTP match support"
1877+ depends on IP_NF_IPTABLES
1878+ help
1879+ This match allows iptables to match on the SCTP header.
1880+
1881+ If you want to compile it as a module, say M here and read
1882+ <file:Documentation/modules.txt>. If unsure, say `N'.
1883+
1884 config IP_NF_MATCH_LENGTH
1885 tristate "LENGTH match support"
1886 depends on IP_NF_IPTABLES
1887@@ -527,6 +536,42 @@
1888
1889 To compile it as a module, choose M here. If unsure, say N.
1890
1891+config IP_NF_RAW
1892+ tristate "Raw table"
1893+ depends on IP_NF_IPTABLES
1894+ help
1895+ This option adds a `raw' table to iptables: see the man page for
1896+ iptables(8). This table is the very first in the netfilter
1897+ framework and hooks in at the PREROUTING and OUTPUT chains.
1898+ The TRACE and NOTRACK targets can be used in this table only.
1899+
1900+ To compile it as a module, choose M here. If unsure, say N.
1901+
1902+config IP_NF_TARGET_TRACE
1903+ tristate "TRACE target support"
1904+ depends on IP_NF_RAW
1905+ help
1906+ The TRACE target allows packets to be traced as those matches
1907+ any subsequent rule in any table/rule. The matched rule and
1908+ the packet is logged with the prefix
1909+
1910+ TRACE: tablename/chainname/rulenum
1911+
1912+ if the ipt_LOG or ipt_ULOG targets are loaded in.
1913+
1914+ To compile it as a module, choose M here. If unsure, say N.
1915+
1916+config IP_NF_TARGET_NOTRACK
1917+ tristate "NOTRACK target support"
1918+ depends on IP_NF_RAW
1919+ help
1920+ The NOTRACK target allows a select rule to specify which
1921+ packets *not* to enter the conntrack/NAT subsystems
1922+ with all the consequences (no ICMP error tracking,
1923+ no protocol helpers for the selected packets).
1924+
1925+ To compile it as a module, choose M here. If unsure, say N.
1926+
1927 config IP_NF_ARPTABLES
1928 tristate "ARP tables support"
1929
1930diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/Kconfig.orig linux-2.6.0-test9/net/ipv4/netfilter/Kconfig.orig
1931--- linux-2.6.0-test9.org/net/ipv4/netfilter/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100
1932+++ linux-2.6.0-test9/net/ipv4/netfilter/Kconfig.orig 2003-11-13 11:01:38.000000000 +0100
1933@@ -0,0 +1,606 @@
1934+#
1935+# IP netfilter configuration
1936+#
1937+
1938+menu "IP: Netfilter Configuration"
1939+ depends on INET && NETFILTER
1940+
1941+config IP_NF_CONNTRACK
1942+ tristate "Connection tracking (required for masq/NAT)"
1943+ ---help---
1944+ Connection tracking keeps a record of what packets have passed
1945+ through your machine, in order to figure out how they are related
1946+ into connections.
1947+
1948+ This is required to do Masquerading or other kinds of Network
1949+ Address Translation (except for Fast NAT). It can also be used to
1950+ enhance packet filtering (see `Connection state match support'
1951+ below).
1952+
1953+ To compile it as a module, choose M here. If unsure, say N.
1954+
1955+config IP_NF_FTP
1956+ tristate "FTP protocol support"
1957+ depends on IP_NF_CONNTRACK
1958+ help
1959+ Tracking FTP connections is problematic: special helpers are
1960+ required for tracking them, and doing masquerading and other forms
1961+ of Network Address Translation on them.
1962+
1963+ To compile it as a module, choose M here. If unsure, say Y.
1964+
1965+config IP_NF_IRC
1966+ tristate "IRC protocol support"
1967+ depends on IP_NF_CONNTRACK
1968+ ---help---
1969+ There is a commonly-used extension to IRC called
1970+ Direct Client-to-Client Protocol (DCC). This enables users to send
1971+ files to each other, and also chat to each other without the need
1972+ of a server. DCC Sending is used anywhere you send files over IRC,
1973+ and DCC Chat is most commonly used by Eggdrop bots. If you are
1974+ using NAT, this extension will enable you to send files and initiate
1975+ chats. Note that you do NOT need this extension to get files or
1976+ have others initiate chats, or everything else in IRC.
1977+
1978+ To compile it as a module, choose M here. If unsure, say Y.
1979+
1980+config IP_NF_TFTP
1981+ tristate "TFTP protocol support"
1982+ depends on IP_NF_CONNTRACK
1983+ help
1984+ TFTP connection tracking helper, this is required depending
1985+ on how restrictive your ruleset is.
1986+ If you are using a tftp client behind -j SNAT or -j MASQUERADING
1987+ you will need this.
1988+
1989+ To compile it as a module, choose M here. If unsure, say Y.
1990+
1991+config IP_NF_AMANDA
1992+ tristate "Amanda backup protocol support"
1993+ depends on IP_NF_CONNTRACK
1994+ help
1995+ If you are running the Amanda backup package <http://www.amanda.org/>
1996+ on this machine or machines that will be MASQUERADED through this
1997+ machine, then you may want to enable this feature. This allows the
1998+ connection tracking and natting code to allow the sub-channels that
1999+ Amanda requires for communication of the backup data, messages and
2000+ index.
2001+
2002+ To compile it as a module, choose M here. If unsure, say Y.
2003+
2004+config IP_NF_QUEUE
2005+ tristate "Userspace queueing via NETLINK"
2006+ help
2007+ Netfilter has the ability to queue packets to user space: the
2008+ netlink device can be used to access them using this driver.
2009+
2010+ To compile it as a module, choose M here. If unsure, say N.
2011+
2012+config IP_NF_IPTABLES
2013+ tristate "IP tables support (required for filtering/masq/NAT)"
2014+ help
2015+ iptables is a general, extensible packet identification framework.
2016+ The packet filtering and full NAT (masquerading, port forwarding,
2017+ etc) subsystems now use this: say `Y' or `M' here if you want to use
2018+ either of those.
2019+
2020+ To compile it as a module, choose M here. If unsure, say N.
2021+
2022+# The simple matches.
2023+config IP_NF_MATCH_LIMIT
2024+ tristate "limit match support"
2025+ depends on IP_NF_IPTABLES
2026+ help
2027+ limit matching allows you to control the rate at which a rule can be
2028+ matched: mainly useful in combination with the LOG target ("LOG
2029+ target support", below) and to avoid some Denial of Service attacks.
2030+
2031+ To compile it as a module, choose M here. If unsure, say N.
2032+
2033+config IP_NF_MATCH_IPRANGE
2034+ tristate "IP range match support"
2035+ depends on IP_NF_IPTABLES
2036+ help
2037+ This option makes possible to match IP addresses against IP address
2038+ ranges.
2039+
2040+ To compile it as a module, choose M here. If unsure, say N.
2041+
2042+config IP_NF_MATCH_MAC
2043+ tristate "MAC address match support"
2044+ depends on IP_NF_IPTABLES
2045+ help
2046+ MAC matching allows you to match packets based on the source
2047+ Ethernet address of the packet.
2048+
2049+ To compile it as a module, choose M here. If unsure, say N.
2050+
2051+config IP_NF_MATCH_PKTTYPE
2052+ tristate "Packet type match support"
2053+ depends on IP_NF_IPTABLES
2054+ help
2055+ Packet type matching allows you to match a packet by
2056+ its "class", eg. BROADCAST, MULTICAST, ...
2057+
2058+ Typical usage:
2059+ iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
2060+
2061+ To compile it as a module, choose M here. If unsure, say N.
2062+
2063+config IP_NF_MATCH_MARK
2064+ tristate "netfilter MARK match support"
2065+ depends on IP_NF_IPTABLES
2066+ help
2067+ Netfilter mark matching allows you to match packets based on the
2068+ `nfmark' value in the packet. This can be set by the MARK target
2069+ (see below).
2070+
2071+ To compile it as a module, choose M here. If unsure, say N.
2072+
2073+config IP_NF_MATCH_MULTIPORT
2074+ tristate "Multiple port match support"
2075+ depends on IP_NF_IPTABLES
2076+ help
2077+ Multiport matching allows you to match TCP or UDP packets based on
2078+ a series of source or destination ports: normally a rule can only
2079+ match a single range of ports.
2080+
2081+ To compile it as a module, choose M here. If unsure, say N.
2082+
2083+config IP_NF_MATCH_TOS
2084+ tristate "TOS match support"
2085+ depends on IP_NF_IPTABLES
2086+ help
2087+ TOS matching allows you to match packets based on the Type Of
2088+ Service fields of the IP packet.
2089+
2090+ To compile it as a module, choose M here. If unsure, say N.
2091+
2092+config IP_NF_MATCH_RECENT
2093+ tristate "recent match support"
2094+ depends on IP_NF_IPTABLES
2095+ help
2096+ This match is used for creating one or many lists of recently
2097+ used addresses and then matching against that/those list(s).
2098+
2099+ Short options are available by using 'iptables -m recent -h'
2100+ Official Website: <http://snowman.net/projects/ipt_recent/>
2101+
2102+ To compile it as a module, choose M here. If unsure, say N.
2103+
2104+config IP_NF_MATCH_ECN
2105+ tristate "ECN match support"
2106+ depends on IP_NF_IPTABLES
2107+ help
2108+ This option adds a `ECN' match, which allows you to match against
2109+ the IPv4 and TCP header ECN fields.
2110+
2111+ To compile it as a module, choose M here. If unsure, say N.
2112+
2113+config IP_NF_MATCH_DSCP
2114+ tristate "DSCP match support"
2115+ depends on IP_NF_IPTABLES
2116+ help
2117+ This option adds a `DSCP' match, which allows you to match against
2118+ the IPv4 header DSCP field (DSCP codepoint).
2119+
2120+ The DSCP codepoint can have any value between 0x0 and 0x4f.
2121+
2122+ To compile it as a module, choose M here. If unsure, say N.
2123+
2124+config IP_NF_MATCH_AH_ESP
2125+ tristate "AH/ESP match support"
2126+ depends on IP_NF_IPTABLES
2127+ help
2128+ These two match extensions (`ah' and `esp') allow you to match a
2129+ range of SPIs inside AH or ESP headers of IPSec packets.
2130+
2131+ To compile it as a module, choose M here. If unsure, say N.
2132+
2133+config IP_NF_MATCH_LENGTH
2134+ tristate "LENGTH match support"
2135+ depends on IP_NF_IPTABLES
2136+ help
2137+ This option allows you to match the length of a packet against a
2138+ specific value or range of values.
2139+
2140+ To compile it as a module, choose M here. If unsure, say N.
2141+
2142+config IP_NF_MATCH_TTL
2143+ tristate "TTL match support"
2144+ depends on IP_NF_IPTABLES
2145+ help
2146+ This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
2147+ to match packets by their TTL value.
2148+
2149+ To compile it as a module, choose M here. If unsure, say N.
2150+
2151+config IP_NF_MATCH_TCPMSS
2152+ tristate "tcpmss match support"
2153+ depends on IP_NF_IPTABLES
2154+ help
2155+ This option adds a `tcpmss' match, which allows you to examine the
2156+ MSS value of TCP SYN packets, which control the maximum packet size
2157+ for that connection.
2158+
2159+ To compile it as a module, choose M here. If unsure, say N.
2160+
2161+config IP_NF_MATCH_HELPER
2162+ tristate "Helper match support"
2163+ depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
2164+ help
2165+ Helper matching allows you to match packets in dynamic connections
2166+ tracked by a conntrack-helper, ie. ip_conntrack_ftp
2167+
2168+ To compile it as a module, choose M here. If unsure, say Y.
2169+
2170+config IP_NF_MATCH_STATE
2171+ tristate "Connection state match support"
2172+ depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
2173+ help
2174+ Connection state matching allows you to match packets based on their
2175+ relationship to a tracked connection (ie. previous packets). This
2176+ is a powerful tool for packet classification.
2177+
2178+ To compile it as a module, choose M here. If unsure, say N.
2179+
2180+config IP_NF_MATCH_CONNTRACK
2181+ tristate "Connection tracking match support"
2182+ depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
2183+ help
2184+ This is a general conntrack match module, a superset of the state match.
2185+
2186+ It allows matching on additional conntrack information, which is
2187+ useful in complex configurations, such as NAT gateways with multiple
2188+ internet links or tunnels.
2189+
2190+ To compile it as a module, choose M here. If unsure, say N.
2191+
2192+config IP_NF_MATCH_OWNER
2193+ tristate "Owner match support"
2194+ depends on IP_NF_IPTABLES
2195+ help
2196+ Packet owner matching allows you to match locally-generated packets
2197+ based on who created them: the user, group, process or session.
2198+
2199+ To compile it as a module, choose M here. If unsure, say N.
2200+
2201+config IP_NF_MATCH_PHYSDEV
2202+ tristate "Physdev match support"
2203+ depends on IP_NF_IPTABLES && BRIDGE_NETFILTER
2204+ help
2205+ Physdev packet matching matches against the physical bridge ports
2206+ the IP packet arrived on or will leave by.
2207+
2208+ To compile it as a module, choose M here. If unsure, say N.
2209+
2210+# The targets
2211+config IP_NF_FILTER
2212+ tristate "Packet filtering"
2213+ depends on IP_NF_IPTABLES
2214+ help
2215+ Packet filtering defines a table `filter', which has a series of
2216+ rules for simple packet filtering at local input, forwarding and
2217+ local output. See the man page for iptables(8).
2218+
2219+ To compile it as a module, choose M here. If unsure, say N.
2220+
2221+config IP_NF_TARGET_REJECT
2222+ tristate "REJECT target support"
2223+ depends on IP_NF_FILTER
2224+ help
2225+ The REJECT target allows a filtering rule to specify that an ICMP
2226+ error should be issued in response to an incoming packet, rather
2227+ than silently being dropped.
2228+
2229+ To compile it as a module, choose M here. If unsure, say N.
2230+
2231+config IP_NF_NAT
2232+ tristate "Full NAT"
2233+ depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
2234+ help
2235+ The Full NAT option allows masquerading, port forwarding and other
2236+ forms of full Network Address Port Translation. It is controlled by
2237+ the `nat' table in iptables: see the man page for iptables(8).
2238+
2239+ To compile it as a module, choose M here. If unsure, say N.
2240+
2241+config IP_NF_NAT_NEEDED
2242+ bool
2243+ depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y && (IP_NF_COMPAT_IPCHAINS!=y && IP_NF_COMPAT_IPFWADM || IP_NF_COMPAT_IPCHAINS) || IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT
2244+ default y
2245+
2246+config IP_NF_TARGET_MASQUERADE
2247+ tristate "MASQUERADE target support"
2248+ depends on IP_NF_NAT
2249+ help
2250+ Masquerading is a special case of NAT: all outgoing connections are
2251+ changed to seem to come from a particular interface's address, and
2252+ if the interface goes down, those connections are lost. This is
2253+ only useful for dialup accounts with dynamic IP address (ie. your IP
2254+ address will be different on next dialup).
2255+
2256+ To compile it as a module, choose M here. If unsure, say N.
2257+
2258+config IP_NF_TARGET_REDIRECT
2259+ tristate "REDIRECT target support"
2260+ depends on IP_NF_NAT
2261+ help
2262+ REDIRECT is a special case of NAT: all incoming connections are
2263+ mapped onto the incoming interface's address, causing the packets to
2264+ come to the local machine instead of passing through. This is
2265+ useful for transparent proxies.
2266+
2267+ To compile it as a module, choose M here. If unsure, say N.
2268+
2269+config IP_NF_TARGET_NETMAP
2270+ tristate "NETMAP target support"
2271+ depends on IP_NF_NAT
2272+ help
2273+ NETMAP is an implementation of static 1:1 NAT mapping of network
2274+ addresses. It maps the network address part, while keeping the host
2275+ address part intact. It is similar to Fast NAT, except that
2276+ Netfilter's connection tracking doesn't work well with Fast NAT.
2277+
2278+ To compile it as a module, choose M here. If unsure, say N.
2279+
2280+config IP_NF_TARGET_SAME
2281+ tristate "SAME target support"
2282+ depends on IP_NF_NAT
2283+ help
2284+ This option adds a `SAME' target, which works like the standard SNAT
2285+ target, but attempts to give clients the same IP for all connections.
2286+
2287+ To compile it as a module, choose M here. If unsure, say N.
2288+
2289+config IP_NF_NAT_LOCAL
2290+ bool "NAT of local connections (READ HELP)"
2291+ depends on IP_NF_NAT
2292+ help
2293+ This option enables support for NAT of locally originated connections.
2294+ Enable this if you need to use destination NAT on connections
2295+ originating from local processes on the nat box itself.
2296+
2297+ Please note that you will need a recent version (>= 1.2.6a)
2298+ of the iptables userspace program in order to use this feature.
2299+ See http://www.iptables.org/ for download instructions.
2300+
2301+ If unsure, say 'N'.
2302+
2303+config IP_NF_NAT_SNMP_BASIC
2304+ tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
2305+ depends on EXPERIMENTAL && IP_NF_NAT
2306+ ---help---
2307+
2308+ This module implements an Application Layer Gateway (ALG) for
2309+ SNMP payloads. In conjunction with NAT, it allows a network
2310+ management system to access multiple private networks with
2311+ conflicting addresses. It works by modifying IP addresses
2312+ inside SNMP payloads to match IP-layer NAT mapping.
2313+
2314+ This is the "basic" form of SNMP-ALG, as described in RFC 2962
2315+
2316+ To compile it as a module, choose M here. If unsure, say N.
2317+
2318+config IP_NF_NAT_IRC
2319+ tristate
2320+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
2321+ default IP_NF_NAT if IP_NF_IRC=y
2322+ default m if IP_NF_IRC=m
2323+
2324+# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
2325+# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh.
2326+config IP_NF_NAT_FTP
2327+ tristate
2328+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
2329+ default IP_NF_NAT if IP_NF_FTP=y
2330+ default m if IP_NF_FTP=m
2331+
2332+config IP_NF_NAT_TFTP
2333+ tristate
2334+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
2335+ default IP_NF_NAT if IP_NF_TFTP=y
2336+ default m if IP_NF_TFTP=m
2337+
2338+config IP_NF_NAT_AMANDA
2339+ tristate
2340+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
2341+ default IP_NF_NAT if IP_NF_AMANDA=y
2342+ default m if IP_NF_AMANDA=m
2343+
2344+config IP_NF_MANGLE
2345+ tristate "Packet mangling"
2346+ depends on IP_NF_IPTABLES
2347+ help
2348+ This option adds a `mangle' table to iptables: see the man page for
2349+ iptables(8). This table is used for various packet alterations
2350+ which can effect how the packet is routed.
2351+
2352+ To compile it as a module, choose M here. If unsure, say N.
2353+
2354+config IP_NF_TARGET_TOS
2355+ tristate "TOS target support"
2356+ depends on IP_NF_MANGLE
2357+ help
2358+ This option adds a `TOS' target, which allows you to create rules in
2359+ the `mangle' table which alter the Type Of Service field of an IP
2360+ packet prior to routing.
2361+
2362+ To compile it as a module, choose M here. If unsure, say N.
2363+
2364+config IP_NF_TARGET_ECN
2365+ tristate "ECN target support"
2366+ depends on IP_NF_MANGLE
2367+ ---help---
2368+ This option adds a `ECN' target, which can be used in the iptables mangle
2369+ table.
2370+
2371+ You can use this target to remove the ECN bits from the IPv4 header of
2372+ an IP packet. This is particularly useful, if you need to work around
2373+ existing ECN blackholes on the internet, but don't want to disable
2374+ ECN support in general.
2375+
2376+ To compile it as a module, choose M here. If unsure, say N.
2377+
2378+config IP_NF_TARGET_DSCP
2379+ tristate "DSCP target support"
2380+ depends on IP_NF_MANGLE
2381+ help
2382+ This option adds a `DSCP' match, which allows you to match against
2383+ the IPv4 header DSCP field (DSCP codepoint).
2384+
2385+ The DSCP codepoint can have any value between 0x0 and 0x4f.
2386+
2387+ To compile it as a module, choose M here. If unsure, say N.
2388+
2389+config IP_NF_TARGET_MARK
2390+ tristate "MARK target support"
2391+ depends on IP_NF_MANGLE
2392+ help
2393+ This option adds a `MARK' target, which allows you to create rules
2394+ in the `mangle' table which alter the netfilter mark (nfmark) field
2395+ associated with the packet prior to routing. This can change
2396+ the routing method (see `Use netfilter MARK value as routing
2397+ key') and can also be used by other subsystems to change their
2398+ behavior.
2399+
2400+ To compile it as a module, choose M here. If unsure, say N.
2401+
2402+config IP_NF_TARGET_CLASSIFY
2403+ tristate "CLASSIFY target support"
2404+ depends on IP_NF_MANGLE
2405+ help
2406+ This option adds a `CLASSIFY' target, which enables the user to set
2407+ the priority of a packet. Some qdiscs can use this value for
2408+ classification, among these are:
2409+
2410+ atm, cbq, dsmark, pfifo_fast, htb, prio
2411+
2412+ To compile it as a module, choose M here. If unsure, say N.
2413+
2414+config IP_NF_TARGET_LOG
2415+ tristate "LOG target support"
2416+ depends on IP_NF_IPTABLES
2417+ help
2418+ This option adds a `LOG' target, which allows you to create rules in
2419+ any iptables table which records the packet header to the syslog.
2420+
2421+ To compile it as a module, choose M here. If unsure, say N.
2422+
2423+config IP_NF_TARGET_ULOG
2424+ tristate "ULOG target support"
2425+ depends on IP_NF_IPTABLES
2426+ ---help---
2427+ This option adds a `ULOG' target, which allows you to create rules in
2428+ any iptables table. The packet is passed to a userspace logging
2429+ daemon using netlink multicast sockets; unlike the LOG target
2430+ which can only be viewed through syslog.
2431+
2432+ The apropriate userspace logging daemon (ulogd) may be obtained from
2433+ http://www.gnumonks.org/projects/ulogd
2434+
2435+ To compile it as a module, choose M here. If unsure, say N.
2436+
2437+config IP_NF_TARGET_TCPMSS
2438+ tristate "TCPMSS target support"
2439+ depends on IP_NF_IPTABLES
2440+ ---help---
2441+ This option adds a `TCPMSS' target, which allows you to alter the
2442+ MSS value of TCP SYN packets, to control the maximum size for that
2443+ connection (usually limiting it to your outgoing interface's MTU
2444+ minus 40).
2445+
2446+ This is used to overcome criminally braindead ISPs or servers which
2447+ block ICMP Fragmentation Needed packets. The symptoms of this
2448+ problem are that everything works fine from your Linux
2449+ firewall/router, but machines behind it can never exchange large
2450+ packets:
2451+ 1) Web browsers connect, then hang with no data received.
2452+ 2) Small mail works fine, but large emails hang.
2453+ 3) ssh works fine, but scp hangs after initial handshaking.
2454+
2455+ Workaround: activate this option and add a rule to your firewall
2456+ configuration like:
2457+
2458+ iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
2459+ -j TCPMSS --clamp-mss-to-pmtu
2460+
2461+ To compile it as a module, choose M here. If unsure, say N.
2462+
2463+config IP_NF_RAW
2464+ tristate "Raw table"
2465+ depends on IP_NF_IPTABLES
2466+ help
2467+ This option adds a `raw' table to iptables: see the man page for
2468+ iptables(8). This table is the very first in the netfilter
2469+ framework and hooks in at the PREROUTING and OUTPUT chains.
2470+ The TRACE and NOTRACK targets can be used in this table only.
2471+
2472+ To compile it as a module, choose M here. If unsure, say N.
2473+
2474+config IP_NF_TARGET_TRACE
2475+ tristate "TRACE target support"
2476+ depends on IP_NF_RAW
2477+ help
2478+ The TRACE target allows packets to be traced as those matches
2479+ any subsequent rule in any table/rule. The matched rule and
2480+ the packet is logged with the prefix
2481+
2482+ TRACE: tablename/chainname/rulenum
2483+
2484+ if the ipt_LOG or ipt_ULOG targets are loaded in.
2485+
2486+ To compile it as a module, choose M here. If unsure, say N.
2487+
2488+config IP_NF_TARGET_NOTRACK
2489+ tristate "NOTRACK target support"
2490+ depends on IP_NF_RAW
2491+ help
2492+ The NOTRACK target allows a select rule to specify which
2493+ packets *not* to enter the conntrack/NAT subsystems
2494+ with all the consequences (no ICMP error tracking,
2495+ no protocol helpers for the selected packets).
2496+
2497+ To compile it as a module, choose M here. If unsure, say N.
2498+
2499+config IP_NF_ARPTABLES
2500+ tristate "ARP tables support"
2501+
2502+config IP_NF_ARPFILTER
2503+ tristate "ARP packet filtering"
2504+ depends on IP_NF_ARPTABLES
2505+
2506+config IP_NF_ARP_MANGLE
2507+ tristate "ARP payload mangling"
2508+ depends on IP_NF_ARPTABLES
2509+ help
2510+ Allows altering the ARP packet payload: source and destination
2511+ hardware and network addresses.
2512+
2513+# Backwards compatibility modules: only if you don't build in the others.
2514+config IP_NF_COMPAT_IPCHAINS
2515+ tristate "ipchains (2.2-style) support"
2516+ depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y
2517+ help
2518+ This option places ipchains (with masquerading and redirection
2519+ support) back into the kernel, using the new netfilter
2520+ infrastructure. It is not recommended for new installations (see
2521+ `Packet filtering'). With this enabled, you should be able to use
2522+ the ipchains tool exactly as in 2.2 kernels.
2523+
2524+ To compile it as a module, choose M here. If unsure, say N.
2525+
2526+config IP_NF_COMPAT_IPFWADM
2527+ tristate "ipfwadm (2.0-style) support"
2528+ depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y && IP_NF_COMPAT_IPCHAINS!=y
2529+ help
2530+ This option places ipfwadm (with masquerading and redirection
2531+ support) back into the kernel, using the new netfilter
2532+ infrastructure. It is not recommended for new installations (see
2533+ `Packet filtering'). With this enabled, you should be able to use
2534+ the ipfwadm tool exactly as in 2.0 kernels.
2535+
2536+ To compile it as a module, choose M here. If unsure, say N.
2537+
2538+endmenu
2539+
2540diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/Makefile linux-2.6.0-test9/net/ipv4/netfilter/Makefile
2541--- linux-2.6.0-test9.org/net/ipv4/netfilter/Makefile 2003-10-25 20:43:07.000000000 +0200
2542+++ linux-2.6.0-test9/net/ipv4/netfilter/Makefile 2003-11-13 11:01:48.000000000 +0100
2543@@ -34,12 +34,14 @@
2544 # generic IP tables
2545 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
2546
2547-# the three instances of ip_tables
2548+# the four instances of ip_tables
2549 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
2550 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
2551 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
2552+obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
2553
2554 # matches
2555+obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
2556 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
2557 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
2558 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
2559@@ -81,6 +83,8 @@
2560 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
2561 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
2562 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
2563+obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
2564+obj-$(CONFIG_IP_NF_TARGET_TRACE) += ipt_TRACE.o
2565
2566 # generic ARP tables
2567 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
2568diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_core.c
2569--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_core.c 2003-10-25 20:42:41.000000000 +0200
2570+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_core.c 2003-11-13 11:01:39.000000000 +0100
2571@@ -29,8 +29,7 @@
2572 #include <linux/slab.h>
2573 #include <linux/random.h>
2574 #include <linux/jhash.h>
2575-/* For ERR_PTR(). Yeah, I know... --RR */
2576-#include <linux/fs.h>
2577+#include <linux/err.h>
2578
2579 /* This rwlock protects the main hash table, protocol/helper/expected
2580 registrations, conntrack timers*/
2581@@ -63,6 +62,7 @@
2582 static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
2583 struct list_head *ip_conntrack_hash;
2584 static kmem_cache_t *ip_conntrack_cachep;
2585+struct ip_conntrack ip_conntrack_untracked;
2586
2587 extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
2588
2589@@ -808,18 +808,10 @@
2590 }
2591 #endif
2592
2593- /* Previously seen (loopback)? Ignore. Do this before
2594- fragment check. */
2595+ /* Previously seen (loopback or untracked)? Ignore. */
2596 if ((*pskb)->nfct)
2597 return NF_ACCEPT;
2598
2599- /* Gather fragments. */
2600- if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
2601- *pskb = ip_ct_gather_frags(*pskb);
2602- if (!*pskb)
2603- return NF_STOLEN;
2604- }
2605-
2606 proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2607
2608 /* It may be an icmp error... */
2609@@ -953,7 +945,6 @@
2610 }
2611 } else if (related_to->helper->max_expected &&
2612 related_to->expecting >= related_to->helper->max_expected) {
2613- struct list_head *cur_item;
2614 /* old == NULL */
2615 if (!(related_to->helper->flags &
2616 IP_CT_HELPER_F_REUSE_EXPECT)) {
2617@@ -978,21 +969,14 @@
2618 NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
2619
2620 /* choose the the oldest expectation to evict */
2621- list_for_each(cur_item, &related_to->sibling_list) {
2622- struct ip_conntrack_expect *cur;
2623-
2624- cur = list_entry(cur_item,
2625- struct ip_conntrack_expect,
2626- expected_list);
2627- if (cur->sibling == NULL) {
2628- old = cur;
2629+ list_for_each_entry(old, &related_to->sibling_list,
2630+ expected_list)
2631+ if (old->sibling == NULL)
2632 break;
2633- }
2634- }
2635
2636- /* (!old) cannot happen, since related_to->expecting is the
2637- * number of unconfirmed expects */
2638- IP_NF_ASSERT(old);
2639+ /* We cannot fail since related_to->expecting is the number
2640+ * of unconfirmed expectations */
2641+ IP_NF_ASSERT(old && old->sibling == NULL);
2642
2643 /* newnat14 does not reuse the real allocated memory
2644 * structures but rather unexpects the old and
2645@@ -1024,7 +1008,7 @@
2646 atomic_set(&new->use, 1);
2647
2648 /* add to expected list for this connection */
2649- list_add(&new->expected_list, &related_to->sibling_list);
2650+ list_add_tail(&new->expected_list, &related_to->sibling_list);
2651 /* add to global list of expectations */
2652 list_prepend(&ip_conntrack_expect_list, &new->list);
2653 /* add and start timer if required */
2654@@ -1419,6 +1403,15 @@
2655
2656 /* For use by ipt_REJECT */
2657 ip_ct_attach = ip_conntrack_attach;
2658+
2659+ /* Set up fake conntrack:
2660+ - to never be deleted, not in any hashes */
2661+ atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
2662+ /* - and look it like as a confirmed connection */
2663+ set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
2664+ /* - and prepare the ctinfo field for NAT. */
2665+ ip_conntrack_untracked.infos[IP_CT_NEW].master = &ip_conntrack_untracked.ct_general;
2666+
2667 return ret;
2668
2669 err_free_hash:
2670diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_core.c.orig
2671--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 01:00:00.000000000 +0100
2672+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_core.c.orig 2003-11-13 11:01:27.000000000 +0100
2673@@ -0,0 +1,1421 @@
2674+/* Connection state tracking for netfilter. This is separated from,
2675+ but required by, the NAT layer; it can also be used by an iptables
2676+ extension. */
2677+
2678+/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
2679+ * Public Licence.
2680+ *
2681+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
2682+ * - new API and handling of conntrack/nat helpers
2683+ * - now capable of multiple expectations for one master
2684+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
2685+ * - add usage/reference counts to ip_conntrack_expect
2686+ * - export ip_conntrack[_expect]_{find_get,put} functions
2687+ * */
2688+
2689+#include <linux/config.h>
2690+#include <linux/types.h>
2691+#include <linux/icmp.h>
2692+#include <linux/ip.h>
2693+#include <linux/netfilter.h>
2694+#include <linux/netfilter_ipv4.h>
2695+#include <linux/module.h>
2696+#include <linux/skbuff.h>
2697+#include <linux/proc_fs.h>
2698+#include <linux/vmalloc.h>
2699+#include <net/checksum.h>
2700+#include <linux/stddef.h>
2701+#include <linux/sysctl.h>
2702+#include <linux/slab.h>
2703+#include <linux/random.h>
2704+#include <linux/jhash.h>
2705+#include <linux/err.h>
2706+
2707+/* This rwlock protects the main hash table, protocol/helper/expected
2708+ registrations, conntrack timers*/
2709+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
2710+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
2711+
2712+#include <linux/netfilter_ipv4/ip_conntrack.h>
2713+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
2714+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
2715+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
2716+#include <linux/netfilter_ipv4/listhelp.h>
2717+
2718+#define IP_CONNTRACK_VERSION "2.1"
2719+
2720+#if 0
2721+#define DEBUGP printk
2722+#else
2723+#define DEBUGP(format, args...)
2724+#endif
2725+
2726+DECLARE_RWLOCK(ip_conntrack_lock);
2727+DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
2728+
2729+void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
2730+LIST_HEAD(ip_conntrack_expect_list);
2731+LIST_HEAD(protocol_list);
2732+static LIST_HEAD(helpers);
2733+unsigned int ip_conntrack_htable_size = 0;
2734+int ip_conntrack_max;
2735+static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
2736+struct list_head *ip_conntrack_hash;
2737+static kmem_cache_t *ip_conntrack_cachep;
2738+
2739+extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
2740+
2741+static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
2742+ u_int8_t protocol)
2743+{
2744+ return protocol == curr->proto;
2745+}
2746+
2747+struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
2748+{
2749+ struct ip_conntrack_protocol *p;
2750+
2751+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2752+ p = LIST_FIND(&protocol_list, proto_cmpfn,
2753+ struct ip_conntrack_protocol *, protocol);
2754+ if (!p)
2755+ p = &ip_conntrack_generic_protocol;
2756+
2757+ return p;
2758+}
2759+
2760+struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
2761+{
2762+ struct ip_conntrack_protocol *p;
2763+
2764+ READ_LOCK(&ip_conntrack_lock);
2765+ p = __ip_ct_find_proto(protocol);
2766+ READ_UNLOCK(&ip_conntrack_lock);
2767+ return p;
2768+}
2769+
2770+inline void
2771+ip_conntrack_put(struct ip_conntrack *ct)
2772+{
2773+ IP_NF_ASSERT(ct);
2774+ IP_NF_ASSERT(ct->infos[0].master);
2775+ /* nf_conntrack_put wants to go via an info struct, so feed it
2776+ one at random. */
2777+ nf_conntrack_put(&ct->infos[0]);
2778+}
2779+
2780+static int ip_conntrack_hash_rnd_initted;
2781+static unsigned int ip_conntrack_hash_rnd;
2782+
2783+static u_int32_t
2784+hash_conntrack(const struct ip_conntrack_tuple *tuple)
2785+{
2786+#if 0
2787+ dump_tuple(tuple);
2788+#endif
2789+ return (jhash_3words(tuple->src.ip,
2790+ (tuple->dst.ip ^ tuple->dst.protonum),
2791+ (tuple->src.u.all | (tuple->dst.u.all << 16)),
2792+ ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
2793+}
2794+
2795+int
2796+get_tuple(const struct iphdr *iph,
2797+ const struct sk_buff *skb,
2798+ unsigned int dataoff,
2799+ struct ip_conntrack_tuple *tuple,
2800+ const struct ip_conntrack_protocol *protocol)
2801+{
2802+ /* Never happen */
2803+ if (iph->frag_off & htons(IP_OFFSET)) {
2804+ printk("ip_conntrack_core: Frag of proto %u.\n",
2805+ iph->protocol);
2806+ return 0;
2807+ }
2808+
2809+ tuple->src.ip = iph->saddr;
2810+ tuple->dst.ip = iph->daddr;
2811+ tuple->dst.protonum = iph->protocol;
2812+
2813+ return protocol->pkt_to_tuple(skb, dataoff, tuple);
2814+}
2815+
2816+static int
2817+invert_tuple(struct ip_conntrack_tuple *inverse,
2818+ const struct ip_conntrack_tuple *orig,
2819+ const struct ip_conntrack_protocol *protocol)
2820+{
2821+ inverse->src.ip = orig->dst.ip;
2822+ inverse->dst.ip = orig->src.ip;
2823+ inverse->dst.protonum = orig->dst.protonum;
2824+
2825+ return protocol->invert_tuple(inverse, orig);
2826+}
2827+
2828+
2829+/* ip_conntrack_expect helper functions */
2830+
2831+/* Compare tuple parts depending on mask. */
2832+static inline int expect_cmp(const struct ip_conntrack_expect *i,
2833+ const struct ip_conntrack_tuple *tuple)
2834+{
2835+ MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2836+ return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
2837+}
2838+
2839+static void
2840+destroy_expect(struct ip_conntrack_expect *exp)
2841+{
2842+ DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
2843+ IP_NF_ASSERT(atomic_read(&exp->use));
2844+ IP_NF_ASSERT(!timer_pending(&exp->timeout));
2845+
2846+ kfree(exp);
2847+}
2848+
2849+
2850+inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
2851+{
2852+ IP_NF_ASSERT(exp);
2853+
2854+ if (atomic_dec_and_test(&exp->use)) {
2855+ /* usage count dropped to zero */
2856+ destroy_expect(exp);
2857+ }
2858+}
2859+
2860+static inline struct ip_conntrack_expect *
2861+__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
2862+{
2863+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2864+ MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2865+ return LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
2866+ struct ip_conntrack_expect *, tuple);
2867+}
2868+
2869+/* Find a expectation corresponding to a tuple. */
2870+struct ip_conntrack_expect *
2871+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
2872+{
2873+ struct ip_conntrack_expect *exp;
2874+
2875+ READ_LOCK(&ip_conntrack_lock);
2876+ READ_LOCK(&ip_conntrack_expect_tuple_lock);
2877+ exp = __ip_ct_expect_find(tuple);
2878+ if (exp)
2879+ atomic_inc(&exp->use);
2880+ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2881+ READ_UNLOCK(&ip_conntrack_lock);
2882+
2883+ return exp;
2884+}
2885+
2886+/* remove one specific expectation from all lists and drop refcount,
2887+ * does _NOT_ delete the timer. */
2888+static void __unexpect_related(struct ip_conntrack_expect *expect)
2889+{
2890+ DEBUGP("unexpect_related(%p)\n", expect);
2891+ MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2892+
2893+ /* we're not allowed to unexpect a confirmed expectation! */
2894+ IP_NF_ASSERT(!expect->sibling);
2895+
2896+ /* delete from global and local lists */
2897+ list_del(&expect->list);
2898+ list_del(&expect->expected_list);
2899+
2900+ /* decrement expect-count of master conntrack */
2901+ if (expect->expectant)
2902+ expect->expectant->expecting--;
2903+
2904+ ip_conntrack_expect_put(expect);
2905+}
2906+
2907+/* remove one specific expecatation from all lists, drop refcount
2908+ * and expire timer.
2909+ * This function can _NOT_ be called for confirmed expects! */
2910+static void unexpect_related(struct ip_conntrack_expect *expect)
2911+{
2912+ IP_NF_ASSERT(expect->expectant);
2913+ IP_NF_ASSERT(expect->expectant->helper);
2914+ /* if we are supposed to have a timer, but we can't delete
2915+ * it: race condition. __unexpect_related will
2916+ * be calledd by timeout function */
2917+ if (expect->expectant->helper->timeout
2918+ && !del_timer(&expect->timeout))
2919+ return;
2920+
2921+ __unexpect_related(expect);
2922+}
2923+
2924+/* delete all unconfirmed expectations for this conntrack */
2925+static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
2926+{
2927+ struct list_head *exp_entry, *next;
2928+ struct ip_conntrack_expect *exp;
2929+
2930+ DEBUGP("remove_expectations(%p)\n", ct);
2931+
2932+ list_for_each_safe(exp_entry, next, &ct->sibling_list) {
2933+ exp = list_entry(exp_entry, struct ip_conntrack_expect,
2934+ expected_list);
2935+
2936+ /* we skip established expectations, as we want to delete
2937+ * the un-established ones only */
2938+ if (exp->sibling) {
2939+ DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
2940+ if (drop_refcount) {
2941+ /* Indicate that this expectations parent is dead */
2942+ ip_conntrack_put(exp->expectant);
2943+ exp->expectant = NULL;
2944+ }
2945+ continue;
2946+ }
2947+
2948+ IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
2949+ IP_NF_ASSERT(exp->expectant == ct);
2950+
2951+ /* delete expectation from global and private lists */
2952+ unexpect_related(exp);
2953+ }
2954+}
2955+
2956+static void
2957+clean_from_lists(struct ip_conntrack *ct)
2958+{
2959+ unsigned int ho, hr;
2960+
2961+ DEBUGP("clean_from_lists(%p)\n", ct);
2962+ MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2963+
2964+ ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
2965+ hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
2966+ LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
2967+ LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
2968+
2969+ /* Destroy all un-established, pending expectations */
2970+ remove_expectations(ct, 1);
2971+}
2972+
2973+static void
2974+destroy_conntrack(struct nf_conntrack *nfct)
2975+{
2976+ struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
2977+ struct ip_conntrack_protocol *proto;
2978+
2979+ DEBUGP("destroy_conntrack(%p)\n", ct);
2980+ IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
2981+ IP_NF_ASSERT(!timer_pending(&ct->timeout));
2982+
2983+ /* To make sure we don't get any weird locking issues here:
2984+ * destroy_conntrack() MUST NOT be called with a write lock
2985+ * to ip_conntrack_lock!!! -HW */
2986+ proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
2987+ if (proto && proto->destroy)
2988+ proto->destroy(ct);
2989+
2990+ if (ip_conntrack_destroyed)
2991+ ip_conntrack_destroyed(ct);
2992+
2993+ WRITE_LOCK(&ip_conntrack_lock);
2994+ /* Delete us from our own list to prevent corruption later */
2995+ list_del(&ct->sibling_list);
2996+
2997+ /* Delete our master expectation */
2998+ if (ct->master) {
2999+ if (ct->master->expectant) {
3000+ /* can't call __unexpect_related here,
3001+ * since it would screw up expect_list */
3002+ list_del(&ct->master->expected_list);
3003+ master = ct->master->expectant;
3004+ }
3005+ kfree(ct->master);
3006+ }
3007+ WRITE_UNLOCK(&ip_conntrack_lock);
3008+
3009+ if (master)
3010+ ip_conntrack_put(master);
3011+
3012+ DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
3013+ kmem_cache_free(ip_conntrack_cachep, ct);
3014+ atomic_dec(&ip_conntrack_count);
3015+}
3016+
3017+static void death_by_timeout(unsigned long ul_conntrack)
3018+{
3019+ struct ip_conntrack *ct = (void *)ul_conntrack;
3020+
3021+ WRITE_LOCK(&ip_conntrack_lock);
3022+ clean_from_lists(ct);
3023+ WRITE_UNLOCK(&ip_conntrack_lock);
3024+ ip_conntrack_put(ct);
3025+}
3026+
3027+static inline int
3028+conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
3029+ const struct ip_conntrack_tuple *tuple,
3030+ const struct ip_conntrack *ignored_conntrack)
3031+{
3032+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3033+ return i->ctrack != ignored_conntrack
3034+ && ip_ct_tuple_equal(tuple, &i->tuple);
3035+}
3036+
3037+static struct ip_conntrack_tuple_hash *
3038+__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
3039+ const struct ip_conntrack *ignored_conntrack)
3040+{
3041+ struct ip_conntrack_tuple_hash *h;
3042+ unsigned int hash = hash_conntrack(tuple);
3043+
3044+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3045+ h = LIST_FIND(&ip_conntrack_hash[hash],
3046+ conntrack_tuple_cmp,
3047+ struct ip_conntrack_tuple_hash *,
3048+ tuple, ignored_conntrack);
3049+ return h;
3050+}
3051+
3052+/* Find a connection corresponding to a tuple. */
3053+struct ip_conntrack_tuple_hash *
3054+ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
3055+ const struct ip_conntrack *ignored_conntrack)
3056+{
3057+ struct ip_conntrack_tuple_hash *h;
3058+
3059+ READ_LOCK(&ip_conntrack_lock);
3060+ h = __ip_conntrack_find(tuple, ignored_conntrack);
3061+ if (h)
3062+ atomic_inc(&h->ctrack->ct_general.use);
3063+ READ_UNLOCK(&ip_conntrack_lock);
3064+
3065+ return h;
3066+}
3067+
3068+static inline struct ip_conntrack *
3069+__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
3070+{
3071+ struct ip_conntrack *ct
3072+ = (struct ip_conntrack *)nfct->master;
3073+
3074+ /* ctinfo is the index of the nfct inside the conntrack */
3075+ *ctinfo = nfct - ct->infos;
3076+ IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
3077+ return ct;
3078+}
3079+
3080+/* Return conntrack and conntrack_info given skb->nfct->master */
3081+struct ip_conntrack *
3082+ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
3083+{
3084+ if (skb->nfct)
3085+ return __ip_conntrack_get(skb->nfct, ctinfo);
3086+ return NULL;
3087+}
3088+
3089+/* Confirm a connection given skb->nfct; places it in hash table */
3090+int
3091+__ip_conntrack_confirm(struct nf_ct_info *nfct)
3092+{
3093+ unsigned int hash, repl_hash;
3094+ struct ip_conntrack *ct;
3095+ enum ip_conntrack_info ctinfo;
3096+
3097+ ct = __ip_conntrack_get(nfct, &ctinfo);
3098+
3099+ /* ipt_REJECT uses ip_conntrack_attach to attach related
3100+ ICMP/TCP RST packets in other direction. Actual packet
3101+ which created connection will be IP_CT_NEW or for an
3102+ expected connection, IP_CT_RELATED. */
3103+ if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
3104+ return NF_ACCEPT;
3105+
3106+ hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
3107+ repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
3108+
3109+ /* We're not in hash table, and we refuse to set up related
3110+ connections for unconfirmed conns. But packet copies and
3111+ REJECT will give spurious warnings here. */
3112+ /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
3113+
3114+ /* No external references means noone else could have
3115+ confirmed us. */
3116+ IP_NF_ASSERT(!is_confirmed(ct));
3117+ DEBUGP("Confirming conntrack %p\n", ct);
3118+
3119+ WRITE_LOCK(&ip_conntrack_lock);
3120+ /* See if there's one in the list already, including reverse:
3121+ NAT could have grabbed it without realizing, since we're
3122+ not in the hash. If there is, we lost race. */
3123+ if (!LIST_FIND(&ip_conntrack_hash[hash],
3124+ conntrack_tuple_cmp,
3125+ struct ip_conntrack_tuple_hash *,
3126+ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
3127+ && !LIST_FIND(&ip_conntrack_hash[repl_hash],
3128+ conntrack_tuple_cmp,
3129+ struct ip_conntrack_tuple_hash *,
3130+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
3131+ list_prepend(&ip_conntrack_hash[hash],
3132+ &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
3133+ list_prepend(&ip_conntrack_hash[repl_hash],
3134+ &ct->tuplehash[IP_CT_DIR_REPLY]);
3135+ /* Timer relative to confirmation time, not original
3136+ setting time, otherwise we'd get timer wrap in
3137+ weird delay cases. */
3138+ ct->timeout.expires += jiffies;
3139+ add_timer(&ct->timeout);
3140+ atomic_inc(&ct->ct_general.use);
3141+ set_bit(IPS_CONFIRMED_BIT, &ct->status);
3142+ WRITE_UNLOCK(&ip_conntrack_lock);
3143+ return NF_ACCEPT;
3144+ }
3145+
3146+ WRITE_UNLOCK(&ip_conntrack_lock);
3147+ return NF_DROP;
3148+}
3149+
3150+/* Returns true if a connection correspondings to the tuple (required
3151+ for NAT). */
3152+int
3153+ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
3154+ const struct ip_conntrack *ignored_conntrack)
3155+{
3156+ struct ip_conntrack_tuple_hash *h;
3157+
3158+ READ_LOCK(&ip_conntrack_lock);
3159+ h = __ip_conntrack_find(tuple, ignored_conntrack);
3160+ READ_UNLOCK(&ip_conntrack_lock);
3161+
3162+ return h != NULL;
3163+}
3164+
3165+/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
3166+struct ip_conntrack *
3167+icmp_error_track(struct sk_buff *skb,
3168+ enum ip_conntrack_info *ctinfo,
3169+ unsigned int hooknum)
3170+{
3171+ struct ip_conntrack_tuple innertuple, origtuple;
3172+ struct {
3173+ struct icmphdr icmp;
3174+ struct iphdr ip;
3175+ } inside;
3176+ struct ip_conntrack_protocol *innerproto;
3177+ struct ip_conntrack_tuple_hash *h;
3178+ int dataoff;
3179+
3180+ IP_NF_ASSERT(skb->nfct == NULL);
3181+
3182+ /* Not enough header? */
3183+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
3184+ return NULL;
3185+
3186+ if (inside.icmp.type != ICMP_DEST_UNREACH
3187+ && inside.icmp.type != ICMP_SOURCE_QUENCH
3188+ && inside.icmp.type != ICMP_TIME_EXCEEDED
3189+ && inside.icmp.type != ICMP_PARAMETERPROB
3190+ && inside.icmp.type != ICMP_REDIRECT)
3191+ return NULL;
3192+
3193+ /* Ignore ICMP's containing fragments (shouldn't happen) */
3194+ if (inside.ip.frag_off & htons(IP_OFFSET)) {
3195+ DEBUGP("icmp_error_track: fragment of proto %u\n",
3196+ inside.ip.protocol);
3197+ return NULL;
3198+ }
3199+
3200+ innerproto = ip_ct_find_proto(inside.ip.protocol);
3201+ dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
3202+ /* Are they talking about one of our connections? */
3203+ if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
3204+ DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
3205+ return NULL;
3206+ }
3207+
3208+ /* Ordinarily, we'd expect the inverted tupleproto, but it's
3209+ been preserved inside the ICMP. */
3210+ if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
3211+ DEBUGP("icmp_error_track: Can't invert tuple\n");
3212+ return NULL;
3213+ }
3214+
3215+ *ctinfo = IP_CT_RELATED;
3216+
3217+ h = ip_conntrack_find_get(&innertuple, NULL);
3218+ if (!h) {
3219+ /* Locally generated ICMPs will match inverted if they
3220+ haven't been SNAT'ed yet */
3221+ /* FIXME: NAT code has to handle half-done double NAT --RR */
3222+ if (hooknum == NF_IP_LOCAL_OUT)
3223+ h = ip_conntrack_find_get(&origtuple, NULL);
3224+
3225+ if (!h) {
3226+ DEBUGP("icmp_error_track: no match\n");
3227+ return NULL;
3228+ }
3229+ /* Reverse direction from that found */
3230+ if (DIRECTION(h) != IP_CT_DIR_REPLY)
3231+ *ctinfo += IP_CT_IS_REPLY;
3232+ } else {
3233+ if (DIRECTION(h) == IP_CT_DIR_REPLY)
3234+ *ctinfo += IP_CT_IS_REPLY;
3235+ }
3236+
3237+ /* Update skb to refer to this connection */
3238+ skb->nfct = &h->ctrack->infos[*ctinfo];
3239+ return h->ctrack;
3240+}
3241+
3242+/* There's a small race here where we may free a just-assured
3243+ connection. Too bad: we're in trouble anyway. */
3244+static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
3245+{
3246+ return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
3247+}
3248+
3249+static int early_drop(struct list_head *chain)
3250+{
3251+ /* Traverse backwards: gives us oldest, which is roughly LRU */
3252+ struct ip_conntrack_tuple_hash *h;
3253+ int dropped = 0;
3254+
3255+ READ_LOCK(&ip_conntrack_lock);
3256+ h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
3257+ if (h)
3258+ atomic_inc(&h->ctrack->ct_general.use);
3259+ READ_UNLOCK(&ip_conntrack_lock);
3260+
3261+ if (!h)
3262+ return dropped;
3263+
3264+ if (del_timer(&h->ctrack->timeout)) {
3265+ death_by_timeout((unsigned long)h->ctrack);
3266+ dropped = 1;
3267+ }
3268+ ip_conntrack_put(h->ctrack);
3269+ return dropped;
3270+}
3271+
3272+static inline int helper_cmp(const struct ip_conntrack_helper *i,
3273+ const struct ip_conntrack_tuple *rtuple)
3274+{
3275+ return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
3276+}
3277+
3278+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
3279+{
3280+ return LIST_FIND(&helpers, helper_cmp,
3281+ struct ip_conntrack_helper *,
3282+ tuple);
3283+}
3284+
3285+/* Allocate a new conntrack: we return -ENOMEM if classification
3286+ failed due to stress. Otherwise it really is unclassifiable. */
3287+static struct ip_conntrack_tuple_hash *
3288+init_conntrack(const struct ip_conntrack_tuple *tuple,
3289+ struct ip_conntrack_protocol *protocol,
3290+ struct sk_buff *skb)
3291+{
3292+ struct ip_conntrack *conntrack;
3293+ struct ip_conntrack_tuple repl_tuple;
3294+ size_t hash;
3295+ struct ip_conntrack_expect *expected;
3296+ int i;
3297+ static unsigned int drop_next;
3298+
3299+ if (!ip_conntrack_hash_rnd_initted) {
3300+ get_random_bytes(&ip_conntrack_hash_rnd, 4);
3301+ ip_conntrack_hash_rnd_initted = 1;
3302+ }
3303+
3304+ hash = hash_conntrack(tuple);
3305+
3306+ if (ip_conntrack_max &&
3307+ atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
3308+ /* Try dropping from random chain, or else from the
3309+ chain about to put into (in case they're trying to
3310+ bomb one hash chain). */
3311+ unsigned int next = (drop_next++)%ip_conntrack_htable_size;
3312+
3313+ if (!early_drop(&ip_conntrack_hash[next])
3314+ && !early_drop(&ip_conntrack_hash[hash])) {
3315+ if (net_ratelimit())
3316+ printk(KERN_WARNING
3317+ "ip_conntrack: table full, dropping"
3318+ " packet.\n");
3319+ return ERR_PTR(-ENOMEM);
3320+ }
3321+ }
3322+
3323+ if (!invert_tuple(&repl_tuple, tuple, protocol)) {
3324+ DEBUGP("Can't invert tuple.\n");
3325+ return NULL;
3326+ }
3327+
3328+ conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
3329+ if (!conntrack) {
3330+ DEBUGP("Can't allocate conntrack.\n");
3331+ return ERR_PTR(-ENOMEM);
3332+ }
3333+
3334+ memset(conntrack, 0, sizeof(*conntrack));
3335+ atomic_set(&conntrack->ct_general.use, 1);
3336+ conntrack->ct_general.destroy = destroy_conntrack;
3337+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
3338+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
3339+ conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
3340+ conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
3341+ for (i=0; i < IP_CT_NUMBER; i++)
3342+ conntrack->infos[i].master = &conntrack->ct_general;
3343+
3344+ if (!protocol->new(conntrack, skb)) {
3345+ kmem_cache_free(ip_conntrack_cachep, conntrack);
3346+ return NULL;
3347+ }
3348+ /* Don't set timer yet: wait for confirmation */
3349+ init_timer(&conntrack->timeout);
3350+ conntrack->timeout.data = (unsigned long)conntrack;
3351+ conntrack->timeout.function = death_by_timeout;
3352+
3353+ INIT_LIST_HEAD(&conntrack->sibling_list);
3354+
3355+ WRITE_LOCK(&ip_conntrack_lock);
3356+ /* Need finding and deleting of expected ONLY if we win race */
3357+ READ_LOCK(&ip_conntrack_expect_tuple_lock);
3358+ expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
3359+ struct ip_conntrack_expect *, tuple);
3360+ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
3361+
3362+ /* If master is not in hash table yet (ie. packet hasn't left
3363+ this machine yet), how can other end know about expected?
3364+ Hence these are not the droids you are looking for (if
3365+ master ct never got confirmed, we'd hold a reference to it
3366+ and weird things would happen to future packets). */
3367+ if (expected && !is_confirmed(expected->expectant))
3368+ expected = NULL;
3369+
3370+ /* Look up the conntrack helper for master connections only */
3371+ if (!expected)
3372+ conntrack->helper = ip_ct_find_helper(&repl_tuple);
3373+
3374+ /* If the expectation is dying, then this is a loser. */
3375+ if (expected
3376+ && expected->expectant->helper->timeout
3377+ && ! del_timer(&expected->timeout))
3378+ expected = NULL;
3379+
3380+ if (expected) {
3381+ DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
3382+ conntrack, expected);
3383+ /* Welcome, Mr. Bond. We've been expecting you... */
3384+ IP_NF_ASSERT(master_ct(conntrack));
3385+ __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
3386+ conntrack->master = expected;
3387+ expected->sibling = conntrack;
3388+ LIST_DELETE(&ip_conntrack_expect_list, expected);
3389+ expected->expectant->expecting--;
3390+ nf_conntrack_get(&master_ct(conntrack)->infos[0]);
3391+ }
3392+ atomic_inc(&ip_conntrack_count);
3393+ WRITE_UNLOCK(&ip_conntrack_lock);
3394+
3395+ if (expected && expected->expectfn)
3396+ expected->expectfn(conntrack);
3397+ return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
3398+}
3399+
3400+/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
3401+static inline struct ip_conntrack *
3402+resolve_normal_ct(struct sk_buff *skb,
3403+ struct ip_conntrack_protocol *proto,
3404+ int *set_reply,
3405+ unsigned int hooknum,
3406+ enum ip_conntrack_info *ctinfo)
3407+{
3408+ struct ip_conntrack_tuple tuple;
3409+ struct ip_conntrack_tuple_hash *h;
3410+
3411+ IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
3412+
3413+ if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
3414+ return NULL;
3415+
3416+ /* look for tuple match */
3417+ h = ip_conntrack_find_get(&tuple, NULL);
3418+ if (!h) {
3419+ h = init_conntrack(&tuple, proto, skb);
3420+ if (!h)
3421+ return NULL;
3422+ if (IS_ERR(h))
3423+ return (void *)h;
3424+ }
3425+
3426+ /* It exists; we have (non-exclusive) reference. */
3427+ if (DIRECTION(h) == IP_CT_DIR_REPLY) {
3428+ *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
3429+ /* Please set reply bit if this packet OK */
3430+ *set_reply = 1;
3431+ } else {
3432+ /* Once we've had two way comms, always ESTABLISHED. */
3433+ if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
3434+ DEBUGP("ip_conntrack_in: normal packet for %p\n",
3435+ h->ctrack);
3436+ *ctinfo = IP_CT_ESTABLISHED;
3437+ } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
3438+ DEBUGP("ip_conntrack_in: related packet for %p\n",
3439+ h->ctrack);
3440+ *ctinfo = IP_CT_RELATED;
3441+ } else {
3442+ DEBUGP("ip_conntrack_in: new packet for %p\n",
3443+ h->ctrack);
3444+ *ctinfo = IP_CT_NEW;
3445+ }
3446+ *set_reply = 0;
3447+ }
3448+ skb->nfct = &h->ctrack->infos[*ctinfo];
3449+ return h->ctrack;
3450+}
3451+
3452+/* Netfilter hook itself. */
3453+unsigned int ip_conntrack_in(unsigned int hooknum,
3454+ struct sk_buff **pskb,
3455+ const struct net_device *in,
3456+ const struct net_device *out,
3457+ int (*okfn)(struct sk_buff *))
3458+{
3459+ struct ip_conntrack *ct;
3460+ enum ip_conntrack_info ctinfo;
3461+ struct ip_conntrack_protocol *proto;
3462+ int set_reply;
3463+ int ret;
3464+
3465+ /* FIXME: Do this right please. --RR */
3466+ (*pskb)->nfcache |= NFC_UNKNOWN;
3467+
3468+/* Doesn't cover locally-generated broadcast, so not worth it. */
3469+#if 0
3470+ /* Ignore broadcast: no `connection'. */
3471+ if ((*pskb)->pkt_type == PACKET_BROADCAST) {
3472+ printk("Broadcast packet!\n");
3473+ return NF_ACCEPT;
3474+ } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
3475+ == htonl(0x000000FF)) {
3476+ printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
3477+ NIPQUAD((*pskb)->nh.iph->saddr),
3478+ NIPQUAD((*pskb)->nh.iph->daddr),
3479+ (*pskb)->sk, (*pskb)->pkt_type);
3480+ }
3481+#endif
3482+
3483+ /* Previously seen (loopback)? Ignore. Do this before
3484+ fragment check. */
3485+ if ((*pskb)->nfct)
3486+ return NF_ACCEPT;
3487+
3488+ /* Gather fragments. */
3489+ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
3490+ *pskb = ip_ct_gather_frags(*pskb);
3491+ if (!*pskb)
3492+ return NF_STOLEN;
3493+ }
3494+
3495+ proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
3496+
3497+ /* It may be an icmp error... */
3498+ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
3499+ && icmp_error_track(*pskb, &ctinfo, hooknum))
3500+ return NF_ACCEPT;
3501+
3502+ if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
3503+ /* Not valid part of a connection */
3504+ return NF_ACCEPT;
3505+
3506+ if (IS_ERR(ct))
3507+ /* Too stressed to deal. */
3508+ return NF_DROP;
3509+
3510+ IP_NF_ASSERT((*pskb)->nfct);
3511+
3512+ ret = proto->packet(ct, *pskb, ctinfo);
3513+ if (ret == -1) {
3514+ /* Invalid */
3515+ nf_conntrack_put((*pskb)->nfct);
3516+ (*pskb)->nfct = NULL;
3517+ return NF_ACCEPT;
3518+ }
3519+
3520+ if (ret != NF_DROP && ct->helper) {
3521+ ret = ct->helper->help(*pskb, ct, ctinfo);
3522+ if (ret == -1) {
3523+ /* Invalid */
3524+ nf_conntrack_put((*pskb)->nfct);
3525+ (*pskb)->nfct = NULL;
3526+ return NF_ACCEPT;
3527+ }
3528+ }
3529+ if (set_reply)
3530+ set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
3531+
3532+ return ret;
3533+}
3534+
3535+int invert_tuplepr(struct ip_conntrack_tuple *inverse,
3536+ const struct ip_conntrack_tuple *orig)
3537+{
3538+ return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
3539+}
3540+
3541+static inline int resent_expect(const struct ip_conntrack_expect *i,
3542+ const struct ip_conntrack_tuple *tuple,
3543+ const struct ip_conntrack_tuple *mask)
3544+{
3545+ DEBUGP("resent_expect\n");
3546+ DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
3547+ DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
3548+ DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
3549+ return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
3550+ || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
3551+ && ip_ct_tuple_equal(&i->mask, mask));
3552+}
3553+
3554+/* Would two expected things clash? */
3555+static inline int expect_clash(const struct ip_conntrack_expect *i,
3556+ const struct ip_conntrack_tuple *tuple,
3557+ const struct ip_conntrack_tuple *mask)
3558+{
3559+ /* Part covered by intersection of masks must be unequal,
3560+ otherwise they clash */
3561+ struct ip_conntrack_tuple intersect_mask
3562+ = { { i->mask.src.ip & mask->src.ip,
3563+ { i->mask.src.u.all & mask->src.u.all } },
3564+ { i->mask.dst.ip & mask->dst.ip,
3565+ { i->mask.dst.u.all & mask->dst.u.all },
3566+ i->mask.dst.protonum & mask->dst.protonum } };
3567+
3568+ return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
3569+}
3570+
3571+inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
3572+{
3573+ WRITE_LOCK(&ip_conntrack_lock);
3574+ unexpect_related(expect);
3575+ WRITE_UNLOCK(&ip_conntrack_lock);
3576+}
3577+
3578+static void expectation_timed_out(unsigned long ul_expect)
3579+{
3580+ struct ip_conntrack_expect *expect = (void *) ul_expect;
3581+
3582+ DEBUGP("expectation %p timed out\n", expect);
3583+ WRITE_LOCK(&ip_conntrack_lock);
3584+ __unexpect_related(expect);
3585+ WRITE_UNLOCK(&ip_conntrack_lock);
3586+}
3587+
3588+/* Add a related connection. */
3589+int ip_conntrack_expect_related(struct ip_conntrack *related_to,
3590+ struct ip_conntrack_expect *expect)
3591+{
3592+ struct ip_conntrack_expect *old, *new;
3593+ int ret = 0;
3594+
3595+ WRITE_LOCK(&ip_conntrack_lock);
3596+ /* Because of the write lock, no reader can walk the lists,
3597+ * so there is no need to use the tuple lock too */
3598+
3599+ DEBUGP("ip_conntrack_expect_related %p\n", related_to);
3600+ DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
3601+ DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
3602+
3603+ old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
3604+ struct ip_conntrack_expect *, &expect->tuple,
3605+ &expect->mask);
3606+ if (old) {
3607+ /* Helper private data may contain offsets but no pointers
3608+ pointing into the payload - otherwise we should have to copy
3609+ the data filled out by the helper over the old one */
3610+ DEBUGP("expect_related: resent packet\n");
3611+ if (related_to->helper->timeout) {
3612+ if (!del_timer(&old->timeout)) {
3613+ /* expectation is dying. Fall through */
3614+ old = NULL;
3615+ } else {
3616+ old->timeout.expires = jiffies +
3617+ related_to->helper->timeout * HZ;
3618+ add_timer(&old->timeout);
3619+ }
3620+ }
3621+
3622+ if (old) {
3623+ WRITE_UNLOCK(&ip_conntrack_lock);
3624+ return -EEXIST;
3625+ }
3626+ } else if (related_to->helper->max_expected &&
3627+ related_to->expecting >= related_to->helper->max_expected) {
3628+ /* old == NULL */
3629+ if (!(related_to->helper->flags &
3630+ IP_CT_HELPER_F_REUSE_EXPECT)) {
3631+ WRITE_UNLOCK(&ip_conntrack_lock);
3632+ if (net_ratelimit())
3633+ printk(KERN_WARNING
3634+ "ip_conntrack: max number of expected "
3635+ "connections %i of %s reached for "
3636+ "%u.%u.%u.%u->%u.%u.%u.%u\n",
3637+ related_to->helper->max_expected,
3638+ related_to->helper->name,
3639+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
3640+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
3641+ return -EPERM;
3642+ }
3643+ DEBUGP("ip_conntrack: max number of expected "
3644+ "connections %i of %s reached for "
3645+ "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
3646+ related_to->helper->max_expected,
3647+ related_to->helper->name,
3648+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
3649+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
3650+
3651+ /* choose the the oldest expectation to evict */
3652+ list_for_each_entry(old, &related_to->sibling_list,
3653+ expected_list)
3654+ if (old->sibling == NULL)
3655+ break;
3656+
3657+ /* We cannot fail since related_to->expecting is the number
3658+ * of unconfirmed expectations */
3659+ IP_NF_ASSERT(old && old->sibling == NULL);
3660+
3661+ /* newnat14 does not reuse the real allocated memory
3662+ * structures but rather unexpects the old and
3663+ * allocates a new. unexpect_related will decrement
3664+ * related_to->expecting.
3665+ */
3666+ unexpect_related(old);
3667+ ret = -EPERM;
3668+ } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
3669+ struct ip_conntrack_expect *, &expect->tuple,
3670+ &expect->mask)) {
3671+ WRITE_UNLOCK(&ip_conntrack_lock);
3672+ DEBUGP("expect_related: busy!\n");
3673+ return -EBUSY;
3674+ }
3675+
3676+ new = (struct ip_conntrack_expect *)
3677+ kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
3678+ if (!new) {
3679+ WRITE_UNLOCK(&ip_conntrack_lock);
3680+ DEBUGP("expect_relaed: OOM allocating expect\n");
3681+ return -ENOMEM;
3682+ }
3683+
3684+ DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
3685+ memcpy(new, expect, sizeof(*expect));
3686+ new->expectant = related_to;
3687+ new->sibling = NULL;
3688+ atomic_set(&new->use, 1);
3689+
3690+ /* add to expected list for this connection */
3691+ list_add_tail(&new->expected_list, &related_to->sibling_list);
3692+ /* add to global list of expectations */
3693+ list_prepend(&ip_conntrack_expect_list, &new->list);
3694+ /* add and start timer if required */
3695+ if (related_to->helper->timeout) {
3696+ init_timer(&new->timeout);
3697+ new->timeout.data = (unsigned long)new;
3698+ new->timeout.function = expectation_timed_out;
3699+ new->timeout.expires = jiffies +
3700+ related_to->helper->timeout * HZ;
3701+ add_timer(&new->timeout);
3702+ }
3703+ related_to->expecting++;
3704+
3705+ WRITE_UNLOCK(&ip_conntrack_lock);
3706+
3707+ return ret;
3708+}
3709+
3710+/* Change tuple in an existing expectation */
3711+int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
3712+ struct ip_conntrack_tuple *newtuple)
3713+{
3714+ int ret;
3715+
3716+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3717+ WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
3718+
3719+ DEBUGP("change_expect:\n");
3720+ DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
3721+ DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
3722+ DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
3723+ if (expect->ct_tuple.dst.protonum == 0) {
3724+ /* Never seen before */
3725+ DEBUGP("change expect: never seen before\n");
3726+ if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
3727+ && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
3728+ struct ip_conntrack_expect *, newtuple, &expect->mask)) {
3729+ /* Force NAT to find an unused tuple */
3730+ ret = -1;
3731+ } else {
3732+ memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
3733+ memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
3734+ ret = 0;
3735+ }
3736+ } else {
3737+ /* Resent packet */
3738+ DEBUGP("change expect: resent packet\n");
3739+ if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
3740+ ret = 0;
3741+ } else {
3742+ /* Force NAT to choose again the same port */
3743+ ret = -1;
3744+ }
3745+ }
3746+ WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
3747+
3748+ return ret;
3749+}
3750+
3751+/* Alter reply tuple (maybe alter helper). If it's already taken,
3752+ return 0 and don't do alteration. */
3753+int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
3754+ const struct ip_conntrack_tuple *newreply)
3755+{
3756+ WRITE_LOCK(&ip_conntrack_lock);
3757+ if (__ip_conntrack_find(newreply, conntrack)) {
3758+ WRITE_UNLOCK(&ip_conntrack_lock);
3759+ return 0;
3760+ }
3761+ /* Should be unconfirmed, so not in hash table yet */
3762+ IP_NF_ASSERT(!is_confirmed(conntrack));
3763+
3764+ DEBUGP("Altering reply tuple of %p to ", conntrack);
3765+ DUMP_TUPLE(newreply);
3766+
3767+ conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
3768+ if (!conntrack->master)
3769+ conntrack->helper = LIST_FIND(&helpers, helper_cmp,
3770+ struct ip_conntrack_helper *,
3771+ newreply);
3772+ WRITE_UNLOCK(&ip_conntrack_lock);
3773+
3774+ return 1;
3775+}
3776+
3777+int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
3778+{
3779+ WRITE_LOCK(&ip_conntrack_lock);
3780+ list_prepend(&helpers, me);
3781+ WRITE_UNLOCK(&ip_conntrack_lock);
3782+
3783+ return 0;
3784+}
3785+
3786+static inline int unhelp(struct ip_conntrack_tuple_hash *i,
3787+ const struct ip_conntrack_helper *me)
3788+{
3789+ if (i->ctrack->helper == me) {
3790+ /* Get rid of any expected. */
3791+ remove_expectations(i->ctrack, 0);
3792+ /* And *then* set helper to NULL */
3793+ i->ctrack->helper = NULL;
3794+ }
3795+ return 0;
3796+}
3797+
3798+void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
3799+{
3800+ unsigned int i;
3801+
3802+ /* Need write lock here, to delete helper. */
3803+ WRITE_LOCK(&ip_conntrack_lock);
3804+ LIST_DELETE(&helpers, me);
3805+
3806+ /* Get rid of expecteds, set helpers to NULL. */
3807+ for (i = 0; i < ip_conntrack_htable_size; i++)
3808+ LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
3809+ struct ip_conntrack_tuple_hash *, me);
3810+ WRITE_UNLOCK(&ip_conntrack_lock);
3811+
3812+ /* Someone could be still looking at the helper in a bh. */
3813+ synchronize_net();
3814+}
3815+
3816+/* Refresh conntrack for this many jiffies. */
3817+void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
3818+{
3819+ IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
3820+
3821+ WRITE_LOCK(&ip_conntrack_lock);
3822+ /* If not in hash table, timer will not be active yet */
3823+ if (!is_confirmed(ct))
3824+ ct->timeout.expires = extra_jiffies;
3825+ else {
3826+ /* Need del_timer for race avoidance (may already be dying). */
3827+ if (del_timer(&ct->timeout)) {
3828+ ct->timeout.expires = jiffies + extra_jiffies;
3829+ add_timer(&ct->timeout);
3830+ }
3831+ }
3832+ WRITE_UNLOCK(&ip_conntrack_lock);
3833+}
3834+
3835+/* Returns new sk_buff, or NULL */
3836+struct sk_buff *
3837+ip_ct_gather_frags(struct sk_buff *skb)
3838+{
3839+ struct sock *sk = skb->sk;
3840+#ifdef CONFIG_NETFILTER_DEBUG
3841+ unsigned int olddebug = skb->nf_debug;
3842+#endif
3843+ if (sk) {
3844+ sock_hold(sk);
3845+ skb_orphan(skb);
3846+ }
3847+
3848+ local_bh_disable();
3849+ skb = ip_defrag(skb);
3850+ local_bh_enable();
3851+
3852+ if (!skb) {
3853+ if (sk)
3854+ sock_put(sk);
3855+ return skb;
3856+ }
3857+
3858+ if (sk) {
3859+ skb_set_owner_w(skb, sk);
3860+ sock_put(sk);
3861+ }
3862+
3863+ ip_send_check(skb->nh.iph);
3864+ skb->nfcache |= NFC_ALTERED;
3865+#ifdef CONFIG_NETFILTER_DEBUG
3866+ /* Packet path as if nothing had happened. */
3867+ skb->nf_debug = olddebug;
3868+#endif
3869+ return skb;
3870+}
3871+
3872+/* Used by ipt_REJECT. */
3873+static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
3874+{
3875+ struct ip_conntrack *ct;
3876+ enum ip_conntrack_info ctinfo;
3877+
3878+ ct = __ip_conntrack_get(nfct, &ctinfo);
3879+
3880+ /* This ICMP is in reverse direction to the packet which
3881+ caused it */
3882+ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
3883+ ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
3884+ else
3885+ ctinfo = IP_CT_RELATED;
3886+
3887+ /* Attach new skbuff, and increment count */
3888+ nskb->nfct = &ct->infos[ctinfo];
3889+ atomic_inc(&ct->ct_general.use);
3890+}
3891+
3892+static inline int
3893+do_kill(const struct ip_conntrack_tuple_hash *i,
3894+ int (*kill)(const struct ip_conntrack *i, void *data),
3895+ void *data)
3896+{
3897+ return kill(i->ctrack, data);
3898+}
3899+
3900+/* Bring out ya dead! */
3901+static struct ip_conntrack_tuple_hash *
3902+get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
3903+ void *data)
3904+{
3905+ struct ip_conntrack_tuple_hash *h = NULL;
3906+ unsigned int i;
3907+
3908+ READ_LOCK(&ip_conntrack_lock);
3909+ for (i = 0; !h && i < ip_conntrack_htable_size; i++) {
3910+ h = LIST_FIND(&ip_conntrack_hash[i], do_kill,
3911+ struct ip_conntrack_tuple_hash *, kill, data);
3912+ }
3913+ if (h)
3914+ atomic_inc(&h->ctrack->ct_general.use);
3915+ READ_UNLOCK(&ip_conntrack_lock);
3916+
3917+ return h;
3918+}
3919+
3920+void
3921+ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
3922+ void *data)
3923+{
3924+ struct ip_conntrack_tuple_hash *h;
3925+
3926+ /* This is order n^2, by the way. */
3927+ while ((h = get_next_corpse(kill, data)) != NULL) {
3928+ /* Time to push up daises... */
3929+ if (del_timer(&h->ctrack->timeout))
3930+ death_by_timeout((unsigned long)h->ctrack);
3931+ /* ... else the timer will get him soon. */
3932+
3933+ ip_conntrack_put(h->ctrack);
3934+ }
3935+}
3936+
3937+/* Fast function for those who don't want to parse /proc (and I don't
3938+ blame them). */
3939+/* Reversing the socket's dst/src point of view gives us the reply
3940+ mapping. */
3941+static int
3942+getorigdst(struct sock *sk, int optval, void *user, int *len)
3943+{
3944+ struct inet_opt *inet = inet_sk(sk);
3945+ struct ip_conntrack_tuple_hash *h;
3946+ struct ip_conntrack_tuple tuple;
3947+
3948+ IP_CT_TUPLE_U_BLANK(&tuple);
3949+ tuple.src.ip = inet->rcv_saddr;
3950+ tuple.src.u.tcp.port = inet->sport;
3951+ tuple.dst.ip = inet->daddr;
3952+ tuple.dst.u.tcp.port = inet->dport;
3953+ tuple.dst.protonum = IPPROTO_TCP;
3954+
3955+ /* We only do TCP at the moment: is there a better way? */
3956+ if (strcmp(sk->sk_prot->name, "TCP")) {
3957+ DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
3958+ return -ENOPROTOOPT;
3959+ }
3960+
3961+ if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
3962+ DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
3963+ *len, sizeof(struct sockaddr_in));
3964+ return -EINVAL;
3965+ }
3966+
3967+ h = ip_conntrack_find_get(&tuple, NULL);
3968+ if (h) {
3969+ struct sockaddr_in sin;
3970+
3971+ sin.sin_family = AF_INET;
3972+ sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3973+ .tuple.dst.u.tcp.port;
3974+ sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3975+ .tuple.dst.ip;
3976+
3977+ DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
3978+ NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
3979+ ip_conntrack_put(h->ctrack);
3980+ if (copy_to_user(user, &sin, sizeof(sin)) != 0)
3981+ return -EFAULT;
3982+ else
3983+ return 0;
3984+ }
3985+ DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
3986+ NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
3987+ NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
3988+ return -ENOENT;
3989+}
3990+
3991+static struct nf_sockopt_ops so_getorigdst = {
3992+ .pf = PF_INET,
3993+ .get_optmin = SO_ORIGINAL_DST,
3994+ .get_optmax = SO_ORIGINAL_DST+1,
3995+ .get = &getorigdst,
3996+};
3997+
3998+static int kill_all(const struct ip_conntrack *i, void *data)
3999+{
4000+ return 1;
4001+}
4002+
4003+/* Mishearing the voices in his head, our hero wonders how he's
4004+ supposed to kill the mall. */
4005+void ip_conntrack_cleanup(void)
4006+{
4007+ ip_ct_attach = NULL;
4008+ /* This makes sure all current packets have passed through
4009+ netfilter framework. Roll on, two-stage module
4010+ delete... */
4011+ synchronize_net();
4012+
4013+ i_see_dead_people:
4014+ ip_ct_selective_cleanup(kill_all, NULL);
4015+ if (atomic_read(&ip_conntrack_count) != 0) {
4016+ schedule();
4017+ goto i_see_dead_people;
4018+ }
4019+
4020+ kmem_cache_destroy(ip_conntrack_cachep);
4021+ vfree(ip_conntrack_hash);
4022+ nf_unregister_sockopt(&so_getorigdst);
4023+}
4024+
4025+static int hashsize;
4026+MODULE_PARM(hashsize, "i");
4027+
4028+int __init ip_conntrack_init(void)
4029+{
4030+ unsigned int i;
4031+ int ret;
4032+
4033+ /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
4034+ * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
4035+ if (hashsize) {
4036+ ip_conntrack_htable_size = hashsize;
4037+ } else {
4038+ ip_conntrack_htable_size
4039+ = (((num_physpages << PAGE_SHIFT) / 16384)
4040+ / sizeof(struct list_head));
4041+ if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
4042+ ip_conntrack_htable_size = 8192;
4043+ if (ip_conntrack_htable_size < 16)
4044+ ip_conntrack_htable_size = 16;
4045+ }
4046+ ip_conntrack_max = 8 * ip_conntrack_htable_size;
4047+
4048+ printk("ip_conntrack version %s (%u buckets, %d max)"
4049+ " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
4050+ ip_conntrack_htable_size, ip_conntrack_max,
4051+ sizeof(struct ip_conntrack));
4052+
4053+ ret = nf_register_sockopt(&so_getorigdst);
4054+ if (ret != 0) {
4055+ printk(KERN_ERR "Unable to register netfilter socket option\n");
4056+ return ret;
4057+ }
4058+
4059+ ip_conntrack_hash = vmalloc(sizeof(struct list_head)
4060+ * ip_conntrack_htable_size);
4061+ if (!ip_conntrack_hash) {
4062+ printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
4063+ goto err_unreg_sockopt;
4064+ }
4065+
4066+ ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
4067+ sizeof(struct ip_conntrack), 0,
4068+ SLAB_HWCACHE_ALIGN, NULL, NULL);
4069+ if (!ip_conntrack_cachep) {
4070+ printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
4071+ goto err_free_hash;
4072+ }
4073+ /* Don't NEED lock here, but good form anyway. */
4074+ WRITE_LOCK(&ip_conntrack_lock);
4075+ /* Sew in builtin protocols. */
4076+ list_append(&protocol_list, &ip_conntrack_protocol_tcp);
4077+ list_append(&protocol_list, &ip_conntrack_protocol_udp);
4078+ list_append(&protocol_list, &ip_conntrack_protocol_icmp);
4079+ WRITE_UNLOCK(&ip_conntrack_lock);
4080+
4081+ for (i = 0; i < ip_conntrack_htable_size; i++)
4082+ INIT_LIST_HEAD(&ip_conntrack_hash[i]);
4083+
4084+ /* For use by ipt_REJECT */
4085+ ip_ct_attach = ip_conntrack_attach;
4086+ return ret;
4087+
4088+err_free_hash:
4089+ vfree(ip_conntrack_hash);
4090+err_unreg_sockopt:
4091+ nf_unregister_sockopt(&so_getorigdst);
4092+
4093+ return -ENOMEM;
4094+}
4095diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_standalone.c
4096--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2003-10-25 20:43:32.000000000 +0200
4097+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_standalone.c 2003-11-13 11:01:39.000000000 +0100
4098@@ -186,6 +186,26 @@
4099 return ip_conntrack_confirm(*pskb);
4100 }
4101
4102+static unsigned int ip_conntrack_defrag(unsigned int hooknum,
4103+ struct sk_buff **pskb,
4104+ const struct net_device *in,
4105+ const struct net_device *out,
4106+ int (*okfn)(struct sk_buff *))
4107+{
4108+ /* Previously seen (loopback)? Ignore. Do this before
4109+ fragment check. */
4110+ if ((*pskb)->nfct)
4111+ return NF_ACCEPT;
4112+
4113+ /* Gather fragments. */
4114+ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
4115+ *pskb = ip_ct_gather_frags(*pskb);
4116+ if (!*pskb)
4117+ return NF_STOLEN;
4118+ }
4119+ return NF_ACCEPT;
4120+}
4121+
4122 static unsigned int ip_refrag(unsigned int hooknum,
4123 struct sk_buff **pskb,
4124 const struct net_device *in,
4125@@ -225,6 +245,15 @@
4126 return ip_conntrack_in(hooknum, pskb, in, out, okfn);
4127 }
4128
4129+/* At the very first: defragment */
4130+static struct nf_hook_ops ip_conntrack_defrag_ops = {
4131+ .hook = ip_conntrack_defrag,
4132+ .owner = THIS_MODULE,
4133+ .pf = PF_INET,
4134+ .hooknum = NF_IP_PRE_ROUTING,
4135+ .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
4136+};
4137+
4138 /* Connection tracking may drop packets, but never alters them, so
4139 make it the first hook. */
4140 static struct nf_hook_ops ip_conntrack_in_ops = {
4141@@ -367,10 +396,15 @@
4142 if (!proc) goto cleanup_init;
4143 proc->owner = THIS_MODULE;
4144
4145+ ret = nf_register_hook(&ip_conntrack_defrag_ops);
4146+ if (ret < 0) {
4147+ printk("ip_conntrack: can't register pre-routing hook to defrag.\n");
4148+ goto cleanup_proc;
4149+ }
4150 ret = nf_register_hook(&ip_conntrack_in_ops);
4151 if (ret < 0) {
4152 printk("ip_conntrack: can't register pre-routing hook.\n");
4153- goto cleanup_proc;
4154+ goto cleanup_defragops;
4155 }
4156 ret = nf_register_hook(&ip_conntrack_local_out_ops);
4157 if (ret < 0) {
4158@@ -408,6 +442,8 @@
4159 nf_unregister_hook(&ip_conntrack_local_out_ops);
4160 cleanup_inops:
4161 nf_unregister_hook(&ip_conntrack_in_ops);
4162+ cleanup_defragops:
4163+ nf_unregister_hook(&ip_conntrack_defrag_ops);
4164 cleanup_proc:
4165 proc_net_remove("ip_conntrack");
4166 cleanup_init:
4167@@ -499,5 +535,6 @@
4168 EXPORT_SYMBOL(ip_conntrack_expect_list);
4169 EXPORT_SYMBOL(ip_conntrack_lock);
4170 EXPORT_SYMBOL(ip_conntrack_hash);
4171+EXPORT_SYMBOL(ip_conntrack_untracked);
4172 EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
4173 EXPORT_SYMBOL_GPL(ip_conntrack_put);
4174diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_standalone.c.orig
4175--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 1970-01-01 01:00:00.000000000 +0100
4176+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 2003-10-25 20:43:32.000000000 +0200
4177@@ -0,0 +1,503 @@
4178+/* This file contains all the functions required for the standalone
4179+ ip_conntrack module.
4180+
4181+ These are not required by the compatibility layer.
4182+*/
4183+
4184+/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
4185+ Public Licence. */
4186+
4187+#include <linux/config.h>
4188+#include <linux/types.h>
4189+#include <linux/ip.h>
4190+#include <linux/netfilter.h>
4191+#include <linux/netfilter_ipv4.h>
4192+#include <linux/module.h>
4193+#include <linux/skbuff.h>
4194+#include <linux/proc_fs.h>
4195+#ifdef CONFIG_SYSCTL
4196+#include <linux/sysctl.h>
4197+#endif
4198+#include <net/checksum.h>
4199+
4200+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
4201+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
4202+
4203+#include <linux/netfilter_ipv4/ip_conntrack.h>
4204+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
4205+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
4206+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
4207+#include <linux/netfilter_ipv4/listhelp.h>
4208+
4209+#if 0
4210+#define DEBUGP printk
4211+#else
4212+#define DEBUGP(format, args...)
4213+#endif
4214+
4215+MODULE_LICENSE("GPL");
4216+
4217+static int kill_proto(const struct ip_conntrack *i, void *data)
4218+{
4219+ return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
4220+ *((u_int8_t *) data));
4221+}
4222+
4223+static unsigned int
4224+print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple,
4225+ struct ip_conntrack_protocol *proto)
4226+{
4227+ int len;
4228+
4229+ len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
4230+ NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
4231+
4232+ len += proto->print_tuple(buffer + len, tuple);
4233+
4234+ return len;
4235+}
4236+
4237+/* FIXME: Don't print source proto part. --RR */
4238+static unsigned int
4239+print_expect(char *buffer, const struct ip_conntrack_expect *expect)
4240+{
4241+ unsigned int len;
4242+
4243+ if (expect->expectant->helper->timeout)
4244+ len = sprintf(buffer, "EXPECTING: %lu ",
4245+ timer_pending(&expect->timeout)
4246+ ? (expect->timeout.expires - jiffies)/HZ : 0);
4247+ else
4248+ len = sprintf(buffer, "EXPECTING: - ");
4249+ len += sprintf(buffer + len, "use=%u proto=%u ",
4250+ atomic_read(&expect->use), expect->tuple.dst.protonum);
4251+ len += print_tuple(buffer + len, &expect->tuple,
4252+ __ip_ct_find_proto(expect->tuple.dst.protonum));
4253+ len += sprintf(buffer + len, "\n");
4254+ return len;
4255+}
4256+
4257+static unsigned int
4258+print_conntrack(char *buffer, struct ip_conntrack *conntrack)
4259+{
4260+ unsigned int len;
4261+ struct ip_conntrack_protocol *proto
4262+ = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4263+ .tuple.dst.protonum);
4264+
4265+ len = sprintf(buffer, "%-8s %u %lu ",
4266+ proto->name,
4267+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4268+ .tuple.dst.protonum,
4269+ timer_pending(&conntrack->timeout)
4270+ ? (conntrack->timeout.expires - jiffies)/HZ : 0);
4271+
4272+ len += proto->print_conntrack(buffer + len, conntrack);
4273+ len += print_tuple(buffer + len,
4274+ &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
4275+ proto);
4276+ if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
4277+ len += sprintf(buffer + len, "[UNREPLIED] ");
4278+ len += print_tuple(buffer + len,
4279+ &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
4280+ proto);
4281+ if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
4282+ len += sprintf(buffer + len, "[ASSURED] ");
4283+ len += sprintf(buffer + len, "use=%u ",
4284+ atomic_read(&conntrack->ct_general.use));
4285+ len += sprintf(buffer + len, "\n");
4286+
4287+ return len;
4288+}
4289+
4290+/* Returns true when finished. */
4291+static inline int
4292+conntrack_iterate(const struct ip_conntrack_tuple_hash *hash,
4293+ char *buffer, off_t offset, off_t *upto,
4294+ unsigned int *len, unsigned int maxlen)
4295+{
4296+ unsigned int newlen;
4297+ IP_NF_ASSERT(hash->ctrack);
4298+
4299+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
4300+
4301+ /* Only count originals */
4302+ if (DIRECTION(hash))
4303+ return 0;
4304+
4305+ if ((*upto)++ < offset)
4306+ return 0;
4307+
4308+ newlen = print_conntrack(buffer + *len, hash->ctrack);
4309+ if (*len + newlen > maxlen)
4310+ return 1;
4311+ else *len += newlen;
4312+
4313+ return 0;
4314+}
4315+
4316+static int
4317+list_conntracks(char *buffer, char **start, off_t offset, int length)
4318+{
4319+ unsigned int i;
4320+ unsigned int len = 0;
4321+ off_t upto = 0;
4322+ struct list_head *e;
4323+
4324+ READ_LOCK(&ip_conntrack_lock);
4325+ /* Traverse hash; print originals then reply. */
4326+ for (i = 0; i < ip_conntrack_htable_size; i++) {
4327+ if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
4328+ struct ip_conntrack_tuple_hash *,
4329+ buffer, offset, &upto, &len, length))
4330+ goto finished;
4331+ }
4332+
4333+ /* Now iterate through expecteds. */
4334+ list_for_each(e, &ip_conntrack_expect_list) {
4335+ unsigned int last_len;
4336+ struct ip_conntrack_expect *expect
4337+ = (struct ip_conntrack_expect *)e;
4338+ if (upto++ < offset) continue;
4339+
4340+ last_len = len;
4341+ len += print_expect(buffer + len, expect);
4342+ if (len > length) {
4343+ len = last_len;
4344+ goto finished;
4345+ }
4346+ }
4347+
4348+ finished:
4349+ READ_UNLOCK(&ip_conntrack_lock);
4350+
4351+ /* `start' hack - see fs/proc/generic.c line ~165 */
4352+ *start = (char *)((unsigned int)upto - offset);
4353+ return len;
4354+}
4355+
4356+static unsigned int ip_confirm(unsigned int hooknum,
4357+ struct sk_buff **pskb,
4358+ const struct net_device *in,
4359+ const struct net_device *out,
4360+ int (*okfn)(struct sk_buff *))
4361+{
4362+ /* We've seen it coming out the other side: confirm it */
4363+ return ip_conntrack_confirm(*pskb);
4364+}
4365+
4366+static unsigned int ip_refrag(unsigned int hooknum,
4367+ struct sk_buff **pskb,
4368+ const struct net_device *in,
4369+ const struct net_device *out,
4370+ int (*okfn)(struct sk_buff *))
4371+{
4372+ struct rtable *rt = (struct rtable *)(*pskb)->dst;
4373+
4374+ /* We've seen it coming out the other side: confirm */
4375+ if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
4376+ return NF_DROP;
4377+
4378+ /* Local packets are never produced too large for their
4379+ interface. We degfragment them at LOCAL_OUT, however,
4380+ so we have to refragment them here. */
4381+ if ((*pskb)->len > dst_pmtu(&rt->u.dst)) {
4382+ /* No hook can be after us, so this should be OK. */
4383+ ip_fragment(*pskb, okfn);
4384+ return NF_STOLEN;
4385+ }
4386+ return NF_ACCEPT;
4387+}
4388+
4389+static unsigned int ip_conntrack_local(unsigned int hooknum,
4390+ struct sk_buff **pskb,
4391+ const struct net_device *in,
4392+ const struct net_device *out,
4393+ int (*okfn)(struct sk_buff *))
4394+{
4395+ /* root is playing with raw sockets. */
4396+ if ((*pskb)->len < sizeof(struct iphdr)
4397+ || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
4398+ if (net_ratelimit())
4399+ printk("ipt_hook: happy cracking.\n");
4400+ return NF_ACCEPT;
4401+ }
4402+ return ip_conntrack_in(hooknum, pskb, in, out, okfn);
4403+}
4404+
4405+/* Connection tracking may drop packets, but never alters them, so
4406+ make it the first hook. */
4407+static struct nf_hook_ops ip_conntrack_in_ops = {
4408+ .hook = ip_conntrack_in,
4409+ .owner = THIS_MODULE,
4410+ .pf = PF_INET,
4411+ .hooknum = NF_IP_PRE_ROUTING,
4412+ .priority = NF_IP_PRI_CONNTRACK,
4413+};
4414+
4415+static struct nf_hook_ops ip_conntrack_local_out_ops = {
4416+ .hook = ip_conntrack_local,
4417+ .owner = THIS_MODULE,
4418+ .pf = PF_INET,
4419+ .hooknum = NF_IP_LOCAL_OUT,
4420+ .priority = NF_IP_PRI_CONNTRACK,
4421+};
4422+
4423+/* Refragmenter; last chance. */
4424+static struct nf_hook_ops ip_conntrack_out_ops = {
4425+ .hook = ip_refrag,
4426+ .owner = THIS_MODULE,
4427+ .pf = PF_INET,
4428+ .hooknum = NF_IP_POST_ROUTING,
4429+ .priority = NF_IP_PRI_LAST,
4430+};
4431+
4432+static struct nf_hook_ops ip_conntrack_local_in_ops = {
4433+ .hook = ip_confirm,
4434+ .owner = THIS_MODULE,
4435+ .pf = PF_INET,
4436+ .hooknum = NF_IP_LOCAL_IN,
4437+ .priority = NF_IP_PRI_LAST-1,
4438+};
4439+
4440+/* Sysctl support */
4441+
4442+#ifdef CONFIG_SYSCTL
4443+
4444+/* From ip_conntrack_core.c */
4445+extern int ip_conntrack_max;
4446+
4447+/* From ip_conntrack_proto_tcp.c */
4448+extern unsigned long ip_ct_tcp_timeout_syn_sent;
4449+extern unsigned long ip_ct_tcp_timeout_syn_recv;
4450+extern unsigned long ip_ct_tcp_timeout_established;
4451+extern unsigned long ip_ct_tcp_timeout_fin_wait;
4452+extern unsigned long ip_ct_tcp_timeout_close_wait;
4453+extern unsigned long ip_ct_tcp_timeout_last_ack;
4454+extern unsigned long ip_ct_tcp_timeout_time_wait;
4455+extern unsigned long ip_ct_tcp_timeout_close;
4456+
4457+/* From ip_conntrack_proto_udp.c */
4458+extern unsigned long ip_ct_udp_timeout;
4459+extern unsigned long ip_ct_udp_timeout_stream;
4460+
4461+/* From ip_conntrack_proto_icmp.c */
4462+extern unsigned long ip_ct_icmp_timeout;
4463+
4464+/* From ip_conntrack_proto_icmp.c */
4465+extern unsigned long ip_ct_generic_timeout;
4466+
4467+static struct ctl_table_header *ip_ct_sysctl_header;
4468+
4469+static ctl_table ip_ct_sysctl_table[] = {
4470+ {NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max",
4471+ &ip_conntrack_max, sizeof(int), 0644, NULL,
4472+ &proc_dointvec},
4473+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, "ip_conntrack_tcp_timeout_syn_sent",
4474+ &ip_ct_tcp_timeout_syn_sent, sizeof(unsigned int), 0644, NULL,
4475+ &proc_dointvec_jiffies},
4476+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, "ip_conntrack_tcp_timeout_syn_recv",
4477+ &ip_ct_tcp_timeout_syn_recv, sizeof(unsigned int), 0644, NULL,
4478+ &proc_dointvec_jiffies},
4479+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, "ip_conntrack_tcp_timeout_established",
4480+ &ip_ct_tcp_timeout_established, sizeof(unsigned int), 0644, NULL,
4481+ &proc_dointvec_jiffies},
4482+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, "ip_conntrack_tcp_timeout_fin_wait",
4483+ &ip_ct_tcp_timeout_fin_wait, sizeof(unsigned int), 0644, NULL,
4484+ &proc_dointvec_jiffies},
4485+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, "ip_conntrack_tcp_timeout_close_wait",
4486+ &ip_ct_tcp_timeout_close_wait, sizeof(unsigned int), 0644, NULL,
4487+ &proc_dointvec_jiffies},
4488+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, "ip_conntrack_tcp_timeout_last_ack",
4489+ &ip_ct_tcp_timeout_last_ack, sizeof(unsigned int), 0644, NULL,
4490+ &proc_dointvec_jiffies},
4491+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, "ip_conntrack_tcp_timeout_time_wait",
4492+ &ip_ct_tcp_timeout_time_wait, sizeof(unsigned int), 0644, NULL,
4493+ &proc_dointvec_jiffies},
4494+ {NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, "ip_conntrack_tcp_timeout_close",
4495+ &ip_ct_tcp_timeout_close, sizeof(unsigned int), 0644, NULL,
4496+ &proc_dointvec_jiffies},
4497+ {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, "ip_conntrack_udp_timeout",
4498+ &ip_ct_udp_timeout, sizeof(unsigned int), 0644, NULL,
4499+ &proc_dointvec_jiffies},
4500+ {NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, "ip_conntrack_udp_timeout_stream",
4501+ &ip_ct_udp_timeout_stream, sizeof(unsigned int), 0644, NULL,
4502+ &proc_dointvec_jiffies},
4503+ {NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, "ip_conntrack_icmp_timeout",
4504+ &ip_ct_icmp_timeout, sizeof(unsigned int), 0644, NULL,
4505+ &proc_dointvec_jiffies},
4506+ {NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, "ip_conntrack_generic_timeout",
4507+ &ip_ct_generic_timeout, sizeof(unsigned int), 0644, NULL,
4508+ &proc_dointvec_jiffies},
4509+ {0}
4510+};
4511+
4512+#define NET_IP_CONNTRACK_MAX 2089
4513+
4514+static ctl_table ip_ct_netfilter_table[] = {
4515+ {NET_IPV4_NETFILTER, "netfilter", NULL, 0, 0555, ip_ct_sysctl_table, 0, 0, 0, 0, 0},
4516+ {NET_IP_CONNTRACK_MAX, "ip_conntrack_max",
4517+ &ip_conntrack_max, sizeof(int), 0644, NULL,
4518+ &proc_dointvec},
4519+ {0}
4520+};
4521+
4522+static ctl_table ip_ct_ipv4_table[] = {
4523+ {NET_IPV4, "ipv4", NULL, 0, 0555, ip_ct_netfilter_table, 0, 0, 0, 0, 0},
4524+ {0}
4525+};
4526+
4527+static ctl_table ip_ct_net_table[] = {
4528+ {CTL_NET, "net", NULL, 0, 0555, ip_ct_ipv4_table, 0, 0, 0, 0, 0},
4529+ {0}
4530+};
4531+#endif
4532+static int init_or_cleanup(int init)
4533+{
4534+ struct proc_dir_entry *proc;
4535+ int ret = 0;
4536+
4537+ if (!init) goto cleanup;
4538+
4539+ ret = ip_conntrack_init();
4540+ if (ret < 0)
4541+ goto cleanup_nothing;
4542+
4543+ proc = proc_net_create("ip_conntrack",0,list_conntracks);
4544+ if (!proc) goto cleanup_init;
4545+ proc->owner = THIS_MODULE;
4546+
4547+ ret = nf_register_hook(&ip_conntrack_in_ops);
4548+ if (ret < 0) {
4549+ printk("ip_conntrack: can't register pre-routing hook.\n");
4550+ goto cleanup_proc;
4551+ }
4552+ ret = nf_register_hook(&ip_conntrack_local_out_ops);
4553+ if (ret < 0) {
4554+ printk("ip_conntrack: can't register local out hook.\n");
4555+ goto cleanup_inops;
4556+ }
4557+ ret = nf_register_hook(&ip_conntrack_out_ops);
4558+ if (ret < 0) {
4559+ printk("ip_conntrack: can't register post-routing hook.\n");
4560+ goto cleanup_inandlocalops;
4561+ }
4562+ ret = nf_register_hook(&ip_conntrack_local_in_ops);
4563+ if (ret < 0) {
4564+ printk("ip_conntrack: can't register local in hook.\n");
4565+ goto cleanup_inoutandlocalops;
4566+ }
4567+#ifdef CONFIG_SYSCTL
4568+ ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
4569+ if (ip_ct_sysctl_header == NULL) {
4570+ printk("ip_conntrack: can't register to sysctl.\n");
4571+ goto cleanup;
4572+ }
4573+#endif
4574+
4575+ return ret;
4576+
4577+ cleanup:
4578+#ifdef CONFIG_SYSCTL
4579+ unregister_sysctl_table(ip_ct_sysctl_header);
4580+#endif
4581+ nf_unregister_hook(&ip_conntrack_local_in_ops);
4582+ cleanup_inoutandlocalops:
4583+ nf_unregister_hook(&ip_conntrack_out_ops);
4584+ cleanup_inandlocalops:
4585+ nf_unregister_hook(&ip_conntrack_local_out_ops);
4586+ cleanup_inops:
4587+ nf_unregister_hook(&ip_conntrack_in_ops);
4588+ cleanup_proc:
4589+ proc_net_remove("ip_conntrack");
4590+ cleanup_init:
4591+ ip_conntrack_cleanup();
4592+ cleanup_nothing:
4593+ return ret;
4594+}
4595+
4596+/* FIXME: Allow NULL functions and sub in pointers to generic for
4597+ them. --RR */
4598+int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
4599+{
4600+ int ret = 0;
4601+ struct list_head *i;
4602+
4603+ WRITE_LOCK(&ip_conntrack_lock);
4604+ list_for_each(i, &protocol_list) {
4605+ if (((struct ip_conntrack_protocol *)i)->proto
4606+ == proto->proto) {
4607+ ret = -EBUSY;
4608+ goto out;
4609+ }
4610+ }
4611+
4612+ list_prepend(&protocol_list, proto);
4613+
4614+ out:
4615+ WRITE_UNLOCK(&ip_conntrack_lock);
4616+ return ret;
4617+}
4618+
4619+void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
4620+{
4621+ WRITE_LOCK(&ip_conntrack_lock);
4622+
4623+ /* ip_ct_find_proto() returns proto_generic in case there is no protocol
4624+ * helper. So this should be enough - HW */
4625+ LIST_DELETE(&protocol_list, proto);
4626+ WRITE_UNLOCK(&ip_conntrack_lock);
4627+
4628+ /* Somebody could be still looking at the proto in bh. */
4629+ synchronize_net();
4630+
4631+ /* Remove all contrack entries for this protocol */
4632+ ip_ct_selective_cleanup(kill_proto, &proto->proto);
4633+}
4634+
4635+static int __init init(void)
4636+{
4637+ return init_or_cleanup(1);
4638+}
4639+
4640+static void __exit fini(void)
4641+{
4642+ init_or_cleanup(0);
4643+}
4644+
4645+module_init(init);
4646+module_exit(fini);
4647+
4648+/* Some modules need us, but don't depend directly on any symbol.
4649+ They should call this. */
4650+void need_ip_conntrack(void)
4651+{
4652+}
4653+
4654+EXPORT_SYMBOL(ip_conntrack_protocol_register);
4655+EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
4656+EXPORT_SYMBOL(invert_tuplepr);
4657+EXPORT_SYMBOL(ip_conntrack_alter_reply);
4658+EXPORT_SYMBOL(ip_conntrack_destroyed);
4659+EXPORT_SYMBOL(ip_conntrack_get);
4660+EXPORT_SYMBOL(need_ip_conntrack);
4661+EXPORT_SYMBOL(ip_conntrack_helper_register);
4662+EXPORT_SYMBOL(ip_conntrack_helper_unregister);
4663+EXPORT_SYMBOL(ip_ct_selective_cleanup);
4664+EXPORT_SYMBOL(ip_ct_refresh);
4665+EXPORT_SYMBOL(ip_ct_find_proto);
4666+EXPORT_SYMBOL(__ip_ct_find_proto);
4667+EXPORT_SYMBOL(ip_ct_find_helper);
4668+EXPORT_SYMBOL(ip_conntrack_expect_related);
4669+EXPORT_SYMBOL(ip_conntrack_change_expect);
4670+EXPORT_SYMBOL(ip_conntrack_unexpect_related);
4671+EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
4672+EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
4673+EXPORT_SYMBOL(ip_conntrack_tuple_taken);
4674+EXPORT_SYMBOL(ip_ct_gather_frags);
4675+EXPORT_SYMBOL(ip_conntrack_htable_size);
4676+EXPORT_SYMBOL(ip_conntrack_expect_list);
4677+EXPORT_SYMBOL(ip_conntrack_lock);
4678+EXPORT_SYMBOL(ip_conntrack_hash);
4679+EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
4680+EXPORT_SYMBOL_GPL(ip_conntrack_put);
4681diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_tftp.c
4682--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_conntrack_tftp.c 2003-10-25 20:43:19.000000000 +0200
4683+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_conntrack_tftp.c 2003-11-13 11:01:08.000000000 +0100
4684@@ -97,8 +97,6 @@
4685
4686 for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
4687 /* Create helper structure */
4688- memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
4689-
4690 tftp[i].tuple.dst.protonum = IPPROTO_UDP;
4691 tftp[i].tuple.src.u.udp.port = htons(ports[i]);
4692 tftp[i].mask.dst.protonum = 0xFFFF;
4693diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_amanda.c linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_amanda.c
4694--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_amanda.c 2003-10-25 20:43:06.000000000 +0200
4695+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_amanda.c 2003-11-13 11:01:08.000000000 +0100
4696@@ -195,8 +195,6 @@
4697 struct ip_nat_helper *hlpr;
4698
4699 hlpr = &ip_nat_amanda_helper;
4700- memset(hlpr, 0, sizeof(struct ip_nat_helper));
4701-
4702 hlpr->tuple.dst.protonum = IPPROTO_UDP;
4703 hlpr->tuple.src.u.udp.port = htons(10080);
4704 hlpr->mask.src.u.udp.port = 0xFFFF;
4705diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_core.c
4706--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_core.c 2003-11-13 11:07:50.000000000 +0100
4707+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_core.c 2003-11-13 11:01:39.000000000 +0100
4708@@ -810,7 +810,7 @@
4709
4710 /* Have to grab read lock before sibling_list traversal */
4711 READ_LOCK(&ip_conntrack_lock);
4712- list_for_each(cur_item, &ct->sibling_list) {
4713+ list_for_each_prev(cur_item, &ct->sibling_list) {
4714 exp = list_entry(cur_item, struct ip_conntrack_expect,
4715 expected_list);
4716
4717@@ -1010,7 +1010,11 @@
4718 /* FIXME: Man, this is a hack. <SIGH> */
4719 IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
4720 ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
4721-
4722+
4723+ /* Initialize fake conntrack so that NAT will skip it */
4724+ ip_conntrack_untracked.nat.info.initialized |=
4725+ (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST);
4726+
4727 return 0;
4728 }
4729
4730diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_core.c.orig linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_core.c.orig
4731--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_core.c.orig 1970-01-01 01:00:00.000000000 +0100
4732+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_core.c.orig 2003-11-13 11:01:27.000000000 +0100
4733@@ -0,0 +1,1030 @@
4734+/* NAT for netfilter; shared with compatibility layer. */
4735+
4736+/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
4737+ Public Licence. */
4738+#include <linux/module.h>
4739+#include <linux/types.h>
4740+#include <linux/timer.h>
4741+#include <linux/skbuff.h>
4742+#include <linux/netfilter_ipv4.h>
4743+#include <linux/vmalloc.h>
4744+#include <net/checksum.h>
4745+#include <net/icmp.h>
4746+#include <net/ip.h>
4747+#include <net/tcp.h> /* For tcp_prot in getorigdst */
4748+#include <linux/icmp.h>
4749+#include <linux/udp.h>
4750+
4751+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
4752+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
4753+
4754+#include <linux/netfilter_ipv4/ip_conntrack.h>
4755+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
4756+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
4757+#include <linux/netfilter_ipv4/ip_nat.h>
4758+#include <linux/netfilter_ipv4/ip_nat_protocol.h>
4759+#include <linux/netfilter_ipv4/ip_nat_core.h>
4760+#include <linux/netfilter_ipv4/ip_nat_helper.h>
4761+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
4762+#include <linux/netfilter_ipv4/listhelp.h>
4763+
4764+#if 0
4765+#define DEBUGP printk
4766+#else
4767+#define DEBUGP(format, args...)
4768+#endif
4769+
4770+DECLARE_RWLOCK(ip_nat_lock);
4771+DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
4772+
4773+/* Calculated at init based on memory size */
4774+static unsigned int ip_nat_htable_size;
4775+
4776+static struct list_head *bysource;
4777+static struct list_head *byipsproto;
4778+LIST_HEAD(protos);
4779+LIST_HEAD(helpers);
4780+
4781+extern struct ip_nat_protocol unknown_nat_protocol;
4782+
4783+/* We keep extra hashes for each conntrack, for fast searching. */
4784+static inline size_t
4785+hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto)
4786+{
4787+ /* Modified src and dst, to ensure we don't create two
4788+ identical streams. */
4789+ return (src + dst + proto) % ip_nat_htable_size;
4790+}
4791+
4792+static inline size_t
4793+hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
4794+{
4795+ /* Original src, to ensure we map it consistently if poss. */
4796+ return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
4797+}
4798+
4799+/* Noone using conntrack by the time this called. */
4800+static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
4801+{
4802+ struct ip_nat_info *info = &conn->nat.info;
4803+ unsigned int hs, hp;
4804+
4805+ if (!info->initialized)
4806+ return;
4807+
4808+ IP_NF_ASSERT(info->bysource.conntrack);
4809+ IP_NF_ASSERT(info->byipsproto.conntrack);
4810+
4811+ hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
4812+ conn->tuplehash[IP_CT_DIR_ORIGINAL]
4813+ .tuple.dst.protonum);
4814+
4815+ hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
4816+ conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
4817+ conn->tuplehash[IP_CT_DIR_REPLY]
4818+ .tuple.dst.protonum);
4819+
4820+ WRITE_LOCK(&ip_nat_lock);
4821+ LIST_DELETE(&bysource[hs], &info->bysource);
4822+ LIST_DELETE(&byipsproto[hp], &info->byipsproto);
4823+ WRITE_UNLOCK(&ip_nat_lock);
4824+}
4825+
4826+/* We do checksum mangling, so if they were wrong before they're still
4827+ * wrong. Also works for incomplete packets (eg. ICMP dest
4828+ * unreachables.) */
4829+u_int16_t
4830+ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
4831+{
4832+ u_int32_t diffs[] = { oldvalinv, newval };
4833+ return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
4834+ oldcheck^0xFFFF));
4835+}
4836+
4837+static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
4838+{
4839+ return i->protonum == proto;
4840+}
4841+
4842+struct ip_nat_protocol *
4843+find_nat_proto(u_int16_t protonum)
4844+{
4845+ struct ip_nat_protocol *i;
4846+
4847+ MUST_BE_READ_LOCKED(&ip_nat_lock);
4848+ i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
4849+ if (!i)
4850+ i = &unknown_nat_protocol;
4851+ return i;
4852+}
4853+
4854+/* Is this tuple already taken? (not by us) */
4855+int
4856+ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
4857+ const struct ip_conntrack *ignored_conntrack)
4858+{
4859+ /* Conntrack tracking doesn't keep track of outgoing tuples; only
4860+ incoming ones. NAT means they don't have a fixed mapping,
4861+ so we invert the tuple and look for the incoming reply.
4862+
4863+ We could keep a separate hash if this proves too slow. */
4864+ struct ip_conntrack_tuple reply;
4865+
4866+ invert_tuplepr(&reply, tuple);
4867+ return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
4868+}
4869+
4870+/* Does tuple + the source manip come within the range mr */
4871+static int
4872+in_range(const struct ip_conntrack_tuple *tuple,
4873+ const struct ip_conntrack_manip *manip,
4874+ const struct ip_nat_multi_range *mr)
4875+{
4876+ struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
4877+ unsigned int i;
4878+ struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
4879+
4880+ for (i = 0; i < mr->rangesize; i++) {
4881+ /* If we are allowed to map IPs, then we must be in the
4882+ range specified, otherwise we must be unchanged. */
4883+ if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
4884+ if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
4885+ || (ntohl(newtuple.src.ip)
4886+ > ntohl(mr->range[i].max_ip)))
4887+ continue;
4888+ } else {
4889+ if (newtuple.src.ip != tuple->src.ip)
4890+ continue;
4891+ }
4892+
4893+ if (!(mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
4894+ || proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
4895+ &mr->range[i].min, &mr->range[i].max))
4896+ return 1;
4897+ }
4898+ return 0;
4899+}
4900+
4901+static inline int
4902+src_cmp(const struct ip_nat_hash *i,
4903+ const struct ip_conntrack_tuple *tuple,
4904+ const struct ip_nat_multi_range *mr)
4905+{
4906+ return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
4907+ == tuple->dst.protonum
4908+ && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
4909+ == tuple->src.ip
4910+ && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
4911+ == tuple->src.u.all
4912+ && in_range(tuple,
4913+ &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4914+ .tuple.src,
4915+ mr));
4916+}
4917+
4918+/* Only called for SRC manip */
4919+static struct ip_conntrack_manip *
4920+find_appropriate_src(const struct ip_conntrack_tuple *tuple,
4921+ const struct ip_nat_multi_range *mr)
4922+{
4923+ unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
4924+ struct ip_nat_hash *i;
4925+
4926+ MUST_BE_READ_LOCKED(&ip_nat_lock);
4927+ i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
4928+ if (i)
4929+ return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
4930+ else
4931+ return NULL;
4932+}
4933+
4934+#ifdef CONFIG_IP_NF_NAT_LOCAL
4935+/* If it's really a local destination manip, it may need to do a
4936+ source manip too. */
4937+static int
4938+do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
4939+{
4940+ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = var_ip } } };
4941+ struct rtable *rt;
4942+
4943+ /* FIXME: IPTOS_TOS(iph->tos) --RR */
4944+ if (ip_route_output_key(&rt, &fl) != 0) {
4945+ DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
4946+ NIPQUAD(var_ip));
4947+ return 0;
4948+ }
4949+
4950+ *other_ipp = rt->rt_src;
4951+ ip_rt_put(rt);
4952+ return 1;
4953+}
4954+#endif
4955+
4956+/* Simple way to iterate through all. */
4957+static inline int fake_cmp(const struct ip_nat_hash *i,
4958+ u_int32_t src, u_int32_t dst, u_int16_t protonum,
4959+ unsigned int *score,
4960+ const struct ip_conntrack *conntrack)
4961+{
4962+ /* Compare backwards: we're dealing with OUTGOING tuples, and
4963+ inside the conntrack is the REPLY tuple. Don't count this
4964+ conntrack. */
4965+ if (i->conntrack != conntrack
4966+ && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
4967+ && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
4968+ && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
4969+ == protonum))
4970+ (*score)++;
4971+ return 0;
4972+}
4973+
4974+static inline unsigned int
4975+count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
4976+ const struct ip_conntrack *conntrack)
4977+{
4978+ unsigned int score = 0;
4979+ unsigned int h;
4980+
4981+ MUST_BE_READ_LOCKED(&ip_nat_lock);
4982+ h = hash_by_ipsproto(src, dst, protonum);
4983+ LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
4984+ src, dst, protonum, &score, conntrack);
4985+
4986+ return score;
4987+}
4988+
4989+/* For [FUTURE] fragmentation handling, we want the least-used
4990+ src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
4991+ if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
4992+ 1-65535, we don't do pro-rata allocation based on ports; we choose
4993+ the ip with the lowest src-ip/dst-ip/proto usage.
4994+
4995+ If an allocation then fails (eg. all 6 ports used in the 1.2.3.4
4996+ range), we eliminate that and try again. This is not the most
4997+ efficient approach, but if you're worried about that, don't hand us
4998+ ranges you don't really have. */
4999+static struct ip_nat_range *
5000+find_best_ips_proto(struct ip_conntrack_tuple *tuple,
5001+ const struct ip_nat_multi_range *mr,
5002+ const struct ip_conntrack *conntrack,
5003+ unsigned int hooknum)
5004+{
5005+ unsigned int i;
5006+ struct {
5007+ const struct ip_nat_range *range;
5008+ unsigned int score;
5009+ struct ip_conntrack_tuple tuple;
5010+ } best = { NULL, 0xFFFFFFFF };
5011+ u_int32_t *var_ipp, *other_ipp, saved_ip, orig_dstip;
5012+ static unsigned int randomness;
5013+
5014+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
5015+ var_ipp = &tuple->src.ip;
5016+ saved_ip = tuple->dst.ip;
5017+ other_ipp = &tuple->dst.ip;
5018+ } else {
5019+ var_ipp = &tuple->dst.ip;
5020+ saved_ip = tuple->src.ip;
5021+ other_ipp = &tuple->src.ip;
5022+ }
5023+ /* Don't do do_extra_mangle unless necessary (overrides
5024+ explicit socket bindings, for example) */
5025+ orig_dstip = tuple->dst.ip;
5026+
5027+ IP_NF_ASSERT(mr->rangesize >= 1);
5028+ for (i = 0; i < mr->rangesize; i++) {
5029+ /* Host order */
5030+ u_int32_t minip, maxip, j;
5031+
5032+ /* Don't do ranges which are already eliminated. */
5033+ if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
5034+ continue;
5035+ }
5036+
5037+ if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
5038+ minip = ntohl(mr->range[i].min_ip);
5039+ maxip = ntohl(mr->range[i].max_ip);
5040+ } else
5041+ minip = maxip = ntohl(*var_ipp);
5042+
5043+ randomness++;
5044+ for (j = 0; j < maxip - minip + 1; j++) {
5045+ unsigned int score;
5046+
5047+ *var_ipp = htonl(minip + (randomness + j)
5048+ % (maxip - minip + 1));
5049+
5050+ /* Reset the other ip in case it was mangled by
5051+ * do_extra_mangle last time. */
5052+ *other_ipp = saved_ip;
5053+
5054+#ifdef CONFIG_IP_NF_NAT_LOCAL
5055+ if (hooknum == NF_IP_LOCAL_OUT
5056+ && *var_ipp != orig_dstip
5057+ && !do_extra_mangle(*var_ipp, other_ipp)) {
5058+ DEBUGP("Range %u %u.%u.%u.%u rt failed!\n",
5059+ i, NIPQUAD(*var_ipp));
5060+ /* Can't route? This whole range part is
5061+ * probably screwed, but keep trying
5062+ * anyway. */
5063+ continue;
5064+ }
5065+#endif
5066+
5067+ /* Count how many others map onto this. */
5068+ score = count_maps(tuple->src.ip, tuple->dst.ip,
5069+ tuple->dst.protonum, conntrack);
5070+ if (score < best.score) {
5071+ /* Optimization: doesn't get any better than
5072+ this. */
5073+ if (score == 0)
5074+ return (struct ip_nat_range *)
5075+ &mr->range[i];
5076+
5077+ best.score = score;
5078+ best.tuple = *tuple;
5079+ best.range = &mr->range[i];
5080+ }
5081+ }
5082+ }
5083+ *tuple = best.tuple;
5084+
5085+ /* Discard const. */
5086+ return (struct ip_nat_range *)best.range;
5087+}
5088+
5089+/* Fast version doesn't iterate through hash chains, but only handles
5090+ common case of single IP address (null NAT, masquerade) */
5091+static struct ip_nat_range *
5092+find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,
5093+ const struct ip_nat_multi_range *mr,
5094+ const struct ip_conntrack *conntrack,
5095+ unsigned int hooknum)
5096+{
5097+ if (mr->rangesize != 1
5098+ || (mr->range[0].flags & IP_NAT_RANGE_FULL)
5099+ || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
5100+ && mr->range[0].min_ip != mr->range[0].max_ip))
5101+ return find_best_ips_proto(tuple, mr, conntrack, hooknum);
5102+
5103+ if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
5104+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
5105+ tuple->src.ip = mr->range[0].min_ip;
5106+ else {
5107+ /* Only do extra mangle when required (breaks
5108+ socket binding) */
5109+#ifdef CONFIG_IP_NF_NAT_LOCAL
5110+ if (tuple->dst.ip != mr->range[0].min_ip
5111+ && hooknum == NF_IP_LOCAL_OUT
5112+ && !do_extra_mangle(mr->range[0].min_ip,
5113+ &tuple->src.ip))
5114+ return NULL;
5115+#endif
5116+ tuple->dst.ip = mr->range[0].min_ip;
5117+ }
5118+ }
5119+
5120+ /* Discard const. */
5121+ return (struct ip_nat_range *)&mr->range[0];
5122+}
5123+
5124+static int
5125+get_unique_tuple(struct ip_conntrack_tuple *tuple,
5126+ const struct ip_conntrack_tuple *orig_tuple,
5127+ const struct ip_nat_multi_range *mrr,
5128+ struct ip_conntrack *conntrack,
5129+ unsigned int hooknum)
5130+{
5131+ struct ip_nat_protocol *proto
5132+ = find_nat_proto(orig_tuple->dst.protonum);
5133+ struct ip_nat_range *rptr;
5134+ unsigned int i;
5135+ int ret;
5136+
5137+ /* We temporarily use flags for marking full parts, but we
5138+ always clean up afterwards */
5139+ struct ip_nat_multi_range *mr = (void *)mrr;
5140+
5141+ /* 1) If this srcip/proto/src-proto-part is currently mapped,
5142+ and that same mapping gives a unique tuple within the given
5143+ range, use that.
5144+
5145+ This is only required for source (ie. NAT/masq) mappings.
5146+ So far, we don't do local source mappings, so multiple
5147+ manips not an issue. */
5148+ if (hooknum == NF_IP_POST_ROUTING) {
5149+ struct ip_conntrack_manip *manip;
5150+
5151+ manip = find_appropriate_src(orig_tuple, mr);
5152+ if (manip) {
5153+ /* Apply same source manipulation. */
5154+ *tuple = ((struct ip_conntrack_tuple)
5155+ { *manip, orig_tuple->dst });
5156+ DEBUGP("get_unique_tuple: Found current src map\n");
5157+ if (!ip_nat_used_tuple(tuple, conntrack))
5158+ return 1;
5159+ }
5160+ }
5161+
5162+ /* 2) Select the least-used IP/proto combination in the given
5163+ range.
5164+ */
5165+ *tuple = *orig_tuple;
5166+ while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
5167+ != NULL) {
5168+ DEBUGP("Found best for "); DUMP_TUPLE(tuple);
5169+ /* 3) The per-protocol part of the manip is made to
5170+ map into the range to make a unique tuple. */
5171+
5172+ /* Only bother mapping if it's not already in range
5173+ and unique */
5174+ if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
5175+ || proto->in_range(tuple, HOOK2MANIP(hooknum),
5176+ &rptr->min, &rptr->max))
5177+ && !ip_nat_used_tuple(tuple, conntrack)) {
5178+ ret = 1;
5179+ goto clear_fulls;
5180+ } else {
5181+ if (proto->unique_tuple(tuple, rptr,
5182+ HOOK2MANIP(hooknum),
5183+ conntrack)) {
5184+ /* Must be unique. */
5185+ IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
5186+ conntrack));
5187+ ret = 1;
5188+ goto clear_fulls;
5189+ } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
5190+ /* Try implicit source NAT; protocol
5191+ may be able to play with ports to
5192+ make it unique. */
5193+ struct ip_nat_range r
5194+ = { IP_NAT_RANGE_MAP_IPS,
5195+ tuple->src.ip, tuple->src.ip,
5196+ { 0 }, { 0 } };
5197+ DEBUGP("Trying implicit mapping\n");
5198+ if (proto->unique_tuple(tuple, &r,
5199+ IP_NAT_MANIP_SRC,
5200+ conntrack)) {
5201+ /* Must be unique. */
5202+ IP_NF_ASSERT(!ip_nat_used_tuple
5203+ (tuple, conntrack));
5204+ ret = 1;
5205+ goto clear_fulls;
5206+ }
5207+ }
5208+ DEBUGP("Protocol can't get unique tuple %u.\n",
5209+ hooknum);
5210+ }
5211+
5212+ /* Eliminate that from range, and try again. */
5213+ rptr->flags |= IP_NAT_RANGE_FULL;
5214+ *tuple = *orig_tuple;
5215+ }
5216+
5217+ ret = 0;
5218+
5219+ clear_fulls:
5220+ /* Clear full flags. */
5221+ IP_NF_ASSERT(mr->rangesize >= 1);
5222+ for (i = 0; i < mr->rangesize; i++)
5223+ mr->range[i].flags &= ~IP_NAT_RANGE_FULL;
5224+
5225+ return ret;
5226+}
5227+
5228+static inline int
5229+helper_cmp(const struct ip_nat_helper *helper,
5230+ const struct ip_conntrack_tuple *tuple)
5231+{
5232+ return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
5233+}
5234+
5235+/* Where to manip the reply packets (will be reverse manip). */
5236+static unsigned int opposite_hook[NF_IP_NUMHOOKS]
5237+= { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
5238+ [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
5239+#ifdef CONFIG_IP_NF_NAT_LOCAL
5240+ [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
5241+ [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
5242+#endif
5243+};
5244+
5245+unsigned int
5246+ip_nat_setup_info(struct ip_conntrack *conntrack,
5247+ const struct ip_nat_multi_range *mr,
5248+ unsigned int hooknum)
5249+{
5250+ struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
5251+ struct ip_conntrack_tuple orig_tp;
5252+ struct ip_nat_info *info = &conntrack->nat.info;
5253+ int in_hashes = info->initialized;
5254+
5255+ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5256+ IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
5257+ || hooknum == NF_IP_POST_ROUTING
5258+ || hooknum == NF_IP_LOCAL_OUT);
5259+ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5260+ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
5261+
5262+ /* What we've got will look like inverse of reply. Normally
5263+ this is what is in the conntrack, except for prior
5264+ manipulations (future optimization: if num_manips == 0,
5265+ orig_tp =
5266+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
5267+ invert_tuplepr(&orig_tp,
5268+ &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
5269+
5270+#if 0
5271+ {
5272+ unsigned int i;
5273+
5274+ DEBUGP("Hook %u (%s), ", hooknum,
5275+ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");
5276+ DUMP_TUPLE(&orig_tp);
5277+ DEBUGP("Range %p: ", mr);
5278+ for (i = 0; i < mr->rangesize; i++) {
5279+ DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",
5280+ i,
5281+ (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)
5282+ ? " MAP_IPS" : "",
5283+ (mr->range[i].flags
5284+ & IP_NAT_RANGE_PROTO_SPECIFIED)
5285+ ? " PROTO_SPECIFIED" : "",
5286+ (mr->range[i].flags & IP_NAT_RANGE_FULL)
5287+ ? " FULL" : "",
5288+ NIPQUAD(mr->range[i].min_ip),
5289+ NIPQUAD(mr->range[i].max_ip),
5290+ mr->range[i].min.all,
5291+ mr->range[i].max.all);
5292+ }
5293+ }
5294+#endif
5295+
5296+ do {
5297+ if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
5298+ hooknum)) {
5299+ DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
5300+ conntrack);
5301+ return NF_DROP;
5302+ }
5303+
5304+#if 0
5305+ DEBUGP("Hook %u (%s) %p\n", hooknum,
5306+ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
5307+ conntrack);
5308+ DEBUGP("Original: ");
5309+ DUMP_TUPLE(&orig_tp);
5310+ DEBUGP("New: ");
5311+ DUMP_TUPLE(&new_tuple);
5312+#endif
5313+
5314+ /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
5315+ the original (A/B/C/D') and the mangled one (E/F/G/H').
5316+
5317+ We're only allowed to work with the SRC per-proto
5318+ part, so we create inverses of both to start, then
5319+ derive the other fields we need. */
5320+
5321+ /* Reply connection: simply invert the new tuple
5322+ (G/H/E/F') */
5323+ invert_tuplepr(&reply, &new_tuple);
5324+
5325+ /* Alter conntrack table so it recognizes replies.
5326+ If fail this race (reply tuple now used), repeat. */
5327+ } while (!ip_conntrack_alter_reply(conntrack, &reply));
5328+
5329+ /* FIXME: We can simply used existing conntrack reply tuple
5330+ here --RR */
5331+ /* Create inverse of original: C/D/A/B' */
5332+ invert_tuplepr(&inv_tuple, &orig_tp);
5333+
5334+ /* Has source changed?. */
5335+ if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {
5336+ /* In this direction, a source manip. */
5337+ info->manips[info->num_manips++] =
5338+ ((struct ip_nat_info_manip)
5339+ { IP_CT_DIR_ORIGINAL, hooknum,
5340+ IP_NAT_MANIP_SRC, new_tuple.src });
5341+
5342+ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5343+
5344+ /* In the reverse direction, a destination manip. */
5345+ info->manips[info->num_manips++] =
5346+ ((struct ip_nat_info_manip)
5347+ { IP_CT_DIR_REPLY, opposite_hook[hooknum],
5348+ IP_NAT_MANIP_DST, orig_tp.src });
5349+ IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
5350+ }
5351+
5352+ /* Has destination changed? */
5353+ if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {
5354+ /* In this direction, a destination manip */
5355+ info->manips[info->num_manips++] =
5356+ ((struct ip_nat_info_manip)
5357+ { IP_CT_DIR_ORIGINAL, hooknum,
5358+ IP_NAT_MANIP_DST, reply.src });
5359+
5360+ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5361+
5362+ /* In the reverse direction, a source manip. */
5363+ info->manips[info->num_manips++] =
5364+ ((struct ip_nat_info_manip)
5365+ { IP_CT_DIR_REPLY, opposite_hook[hooknum],
5366+ IP_NAT_MANIP_SRC, inv_tuple.src });
5367+ IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
5368+ }
5369+
5370+ /* If there's a helper, assign it; based on new tuple. */
5371+ if (!conntrack->master)
5372+ info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
5373+ &reply);
5374+
5375+ /* It's done. */
5376+ info->initialized |= (1 << HOOK2MANIP(hooknum));
5377+
5378+ if (in_hashes) {
5379+ IP_NF_ASSERT(info->bysource.conntrack);
5380+ replace_in_hashes(conntrack, info);
5381+ } else {
5382+ place_in_hashes(conntrack, info);
5383+ }
5384+
5385+ return NF_ACCEPT;
5386+}
5387+
5388+void replace_in_hashes(struct ip_conntrack *conntrack,
5389+ struct ip_nat_info *info)
5390+{
5391+ /* Source has changed, so replace in hashes. */
5392+ unsigned int srchash
5393+ = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5394+ .tuple.src,
5395+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5396+ .tuple.dst.protonum);
5397+ /* We place packet as seen OUTGOUNG in byips_proto hash
5398+ (ie. reverse dst and src of reply packet. */
5399+ unsigned int ipsprotohash
5400+ = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
5401+ .tuple.dst.ip,
5402+ conntrack->tuplehash[IP_CT_DIR_REPLY]
5403+ .tuple.src.ip,
5404+ conntrack->tuplehash[IP_CT_DIR_REPLY]
5405+ .tuple.dst.protonum);
5406+
5407+ IP_NF_ASSERT(info->bysource.conntrack == conntrack);
5408+ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5409+
5410+ list_del(&info->bysource.list);
5411+ list_del(&info->byipsproto.list);
5412+
5413+ list_prepend(&bysource[srchash], &info->bysource);
5414+ list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5415+}
5416+
5417+void place_in_hashes(struct ip_conntrack *conntrack,
5418+ struct ip_nat_info *info)
5419+{
5420+ unsigned int srchash
5421+ = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5422+ .tuple.src,
5423+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5424+ .tuple.dst.protonum);
5425+ /* We place packet as seen OUTGOUNG in byips_proto hash
5426+ (ie. reverse dst and src of reply packet. */
5427+ unsigned int ipsprotohash
5428+ = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
5429+ .tuple.dst.ip,
5430+ conntrack->tuplehash[IP_CT_DIR_REPLY]
5431+ .tuple.src.ip,
5432+ conntrack->tuplehash[IP_CT_DIR_REPLY]
5433+ .tuple.dst.protonum);
5434+
5435+ IP_NF_ASSERT(!info->bysource.conntrack);
5436+
5437+ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5438+ info->byipsproto.conntrack = conntrack;
5439+ info->bysource.conntrack = conntrack;
5440+
5441+ list_prepend(&bysource[srchash], &info->bysource);
5442+ list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5443+}
5444+
5445+/* Returns true if succeeded. */
5446+static int
5447+manip_pkt(u_int16_t proto,
5448+ struct sk_buff **pskb,
5449+ unsigned int iphdroff,
5450+ const struct ip_conntrack_manip *manip,
5451+ enum ip_nat_manip_type maniptype)
5452+{
5453+ struct iphdr *iph;
5454+
5455+ (*pskb)->nfcache |= NFC_ALTERED;
5456+ if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph)))
5457+ return 0;
5458+
5459+ iph = (void *)(*pskb)->data + iphdroff;
5460+
5461+ /* Manipulate protcol part. */
5462+ if (!find_nat_proto(proto)->manip_pkt(pskb,
5463+ iphdroff + iph->ihl*4,
5464+ manip, maniptype))
5465+ return 0;
5466+
5467+ iph = (void *)(*pskb)->data + iphdroff;
5468+
5469+ if (maniptype == IP_NAT_MANIP_SRC) {
5470+ iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
5471+ iph->check);
5472+ iph->saddr = manip->ip;
5473+ } else {
5474+ iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
5475+ iph->check);
5476+ iph->daddr = manip->ip;
5477+ }
5478+ return 1;
5479+}
5480+
5481+static inline int exp_for_packet(struct ip_conntrack_expect *exp,
5482+ struct sk_buff *skb)
5483+{
5484+ struct ip_conntrack_protocol *proto;
5485+ int ret = 1;
5486+
5487+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
5488+ proto = __ip_ct_find_proto(skb->nh.iph->protocol);
5489+ if (proto->exp_matches_pkt)
5490+ ret = proto->exp_matches_pkt(exp, skb);
5491+
5492+ return ret;
5493+}
5494+
5495+/* Do packet manipulations according to binding. */
5496+unsigned int
5497+do_bindings(struct ip_conntrack *ct,
5498+ enum ip_conntrack_info ctinfo,
5499+ struct ip_nat_info *info,
5500+ unsigned int hooknum,
5501+ struct sk_buff **pskb)
5502+{
5503+ unsigned int i;
5504+ struct ip_nat_helper *helper;
5505+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
5506+ int proto = (*pskb)->nh.iph->protocol;
5507+
5508+ /* Need nat lock to protect against modification, but neither
5509+ conntrack (referenced) and helper (deleted with
5510+ synchronize_bh()) can vanish. */
5511+ READ_LOCK(&ip_nat_lock);
5512+ for (i = 0; i < info->num_manips; i++) {
5513+ if (info->manips[i].direction == dir
5514+ && info->manips[i].hooknum == hooknum) {
5515+ DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
5516+ *pskb,
5517+ info->manips[i].maniptype == IP_NAT_MANIP_SRC
5518+ ? "SRC" : "DST",
5519+ NIPQUAD(info->manips[i].manip.ip),
5520+ htons(info->manips[i].manip.u.all));
5521+ if (!manip_pkt(proto, pskb, 0,
5522+ &info->manips[i].manip,
5523+ info->manips[i].maniptype)) {
5524+ READ_UNLOCK(&ip_nat_lock);
5525+ return NF_DROP;
5526+ }
5527+ }
5528+ }
5529+ helper = info->helper;
5530+ READ_UNLOCK(&ip_nat_lock);
5531+
5532+ if (helper) {
5533+ struct ip_conntrack_expect *exp = NULL;
5534+ struct list_head *cur_item;
5535+ int ret = NF_ACCEPT;
5536+ int helper_called = 0;
5537+
5538+ DEBUGP("do_bindings: helper existing for (%p)\n", ct);
5539+
5540+ /* Always defragged for helpers */
5541+ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
5542+ & htons(IP_MF|IP_OFFSET)));
5543+
5544+ /* Have to grab read lock before sibling_list traversal */
5545+ READ_LOCK(&ip_conntrack_lock);
5546+ list_for_each_prev(cur_item, &ct->sibling_list) {
5547+ exp = list_entry(cur_item, struct ip_conntrack_expect,
5548+ expected_list);
5549+
5550+ /* if this expectation is already established, skip */
5551+ if (exp->sibling)
5552+ continue;
5553+
5554+ if (exp_for_packet(exp, *pskb)) {
5555+ /* FIXME: May be true multiple times in the
5556+ * case of UDP!! */
5557+ DEBUGP("calling nat helper (exp=%p) for packet\n", exp);
5558+ ret = helper->help(ct, exp, info, ctinfo,
5559+ hooknum, pskb);
5560+ if (ret != NF_ACCEPT) {
5561+ READ_UNLOCK(&ip_conntrack_lock);
5562+ return ret;
5563+ }
5564+ helper_called = 1;
5565+ }
5566+ }
5567+ /* Helper might want to manip the packet even when there is no
5568+ * matching expectation for this packet */
5569+ if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
5570+ DEBUGP("calling nat helper for packet without expectation\n");
5571+ ret = helper->help(ct, NULL, info, ctinfo,
5572+ hooknum, pskb);
5573+ if (ret != NF_ACCEPT) {
5574+ READ_UNLOCK(&ip_conntrack_lock);
5575+ return ret;
5576+ }
5577+ }
5578+ READ_UNLOCK(&ip_conntrack_lock);
5579+
5580+ /* Adjust sequence number only once per packet
5581+ * (helper is called at all hooks) */
5582+ if (proto == IPPROTO_TCP
5583+ && (hooknum == NF_IP_POST_ROUTING
5584+ || hooknum == NF_IP_LOCAL_IN)) {
5585+ DEBUGP("ip_nat_core: adjusting sequence number\n");
5586+ /* future: put this in a l4-proto specific function,
5587+ * and call this function here. */
5588+ if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
5589+ ret = NF_DROP;
5590+ }
5591+
5592+ return ret;
5593+
5594+ } else
5595+ return NF_ACCEPT;
5596+
5597+ /* not reached */
5598+}
5599+
5600+int
5601+icmp_reply_translation(struct sk_buff **pskb,
5602+ struct ip_conntrack *conntrack,
5603+ unsigned int hooknum,
5604+ int dir)
5605+{
5606+ struct {
5607+ struct icmphdr icmp;
5608+ struct iphdr ip;
5609+ } *inside;
5610+ unsigned int i;
5611+ struct ip_nat_info *info = &conntrack->nat.info;
5612+ int hdrlen;
5613+
5614+ if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside)))
5615+ return 0;
5616+ inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
5617+
5618+ /* We're actually going to mangle it beyond trivial checksum
5619+ adjustment, so make sure the current checksum is correct. */
5620+ if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) {
5621+ hdrlen = (*pskb)->nh.iph->ihl * 4;
5622+ if ((u16)csum_fold(skb_checksum(*pskb, hdrlen,
5623+ (*pskb)->len - hdrlen, 0)))
5624+ return 0;
5625+ }
5626+
5627+ /* Must be RELATED */
5628+ IP_NF_ASSERT((*pskb)->nfct
5629+ - (struct ip_conntrack *)(*pskb)->nfct->master
5630+ == IP_CT_RELATED
5631+ || (*pskb)->nfct
5632+ - (struct ip_conntrack *)(*pskb)->nfct->master
5633+ == IP_CT_RELATED+IP_CT_IS_REPLY);
5634+
5635+ /* Redirects on non-null nats must be dropped, else they'll
5636+ start talking to each other without our translation, and be
5637+ confused... --RR */
5638+ if (inside->icmp.type == ICMP_REDIRECT) {
5639+ /* Don't care about races here. */
5640+ if (info->initialized
5641+ != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
5642+ || info->num_manips != 0)
5643+ return 0;
5644+ }
5645+
5646+ DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
5647+ *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
5648+ /* Note: May not be from a NAT'd host, but probably safest to
5649+ do translation always as if it came from the host itself
5650+ (even though a "host unreachable" coming from the host
5651+ itself is a bit weird).
5652+
5653+ More explanation: some people use NAT for anonymizing.
5654+ Also, CERT recommends dropping all packets from private IP
5655+ addresses (although ICMP errors from internal links with
5656+ such addresses are not too uncommon, as Alan Cox points
5657+ out) */
5658+
5659+ READ_LOCK(&ip_nat_lock);
5660+ for (i = 0; i < info->num_manips; i++) {
5661+ DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
5662+ i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?
5663+ "ORIG" : "REPLY", info->manips[i].hooknum);
5664+
5665+ if (info->manips[i].direction != dir)
5666+ continue;
5667+
5668+ /* Mapping the inner packet is just like a normal
5669+ packet, except it was never src/dst reversed, so
5670+ where we would normally apply a dst manip, we apply
5671+ a src, and vice versa. */
5672+ if (info->manips[i].hooknum == hooknum) {
5673+ DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
5674+ info->manips[i].maniptype == IP_NAT_MANIP_SRC
5675+ ? "DST" : "SRC",
5676+ NIPQUAD(info->manips[i].manip.ip),
5677+ ntohs(info->manips[i].manip.u.udp.port));
5678+ if (!manip_pkt(inside->ip.protocol, pskb,
5679+ (*pskb)->nh.iph->ihl*4
5680+ + sizeof(inside->icmp),
5681+ &info->manips[i].manip,
5682+ !info->manips[i].maniptype))
5683+ goto unlock_fail;
5684+
5685+ /* Outer packet needs to have IP header NATed like
5686+ it's a reply. */
5687+
5688+ /* Use mapping to map outer packet: 0 give no
5689+ per-proto mapping */
5690+ DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
5691+ info->manips[i].maniptype == IP_NAT_MANIP_SRC
5692+ ? "SRC" : "DST",
5693+ NIPQUAD(info->manips[i].manip.ip));
5694+ if (!manip_pkt(0, pskb, 0,
5695+ &info->manips[i].manip,
5696+ info->manips[i].maniptype))
5697+ goto unlock_fail;
5698+ }
5699+ }
5700+ READ_UNLOCK(&ip_nat_lock);
5701+
5702+ hdrlen = (*pskb)->nh.iph->ihl * 4;
5703+
5704+ inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
5705+
5706+ inside->icmp.checksum = 0;
5707+ inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
5708+ (*pskb)->len - hdrlen,
5709+ 0));
5710+ return 1;
5711+
5712+ unlock_fail:
5713+ READ_UNLOCK(&ip_nat_lock);
5714+ return 0;
5715+}
5716+
5717+int __init ip_nat_init(void)
5718+{
5719+ size_t i;
5720+
5721+ /* Leave them the same for the moment. */
5722+ ip_nat_htable_size = ip_conntrack_htable_size;
5723+
5724+ /* One vmalloc for both hash tables */
5725+ bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
5726+ if (!bysource) {
5727+ return -ENOMEM;
5728+ }
5729+ byipsproto = bysource + ip_nat_htable_size;
5730+
5731+ /* Sew in builtin protocols. */
5732+ WRITE_LOCK(&ip_nat_lock);
5733+ list_append(&protos, &ip_nat_protocol_tcp);
5734+ list_append(&protos, &ip_nat_protocol_udp);
5735+ list_append(&protos, &ip_nat_protocol_icmp);
5736+ WRITE_UNLOCK(&ip_nat_lock);
5737+
5738+ for (i = 0; i < ip_nat_htable_size; i++) {
5739+ INIT_LIST_HEAD(&bysource[i]);
5740+ INIT_LIST_HEAD(&byipsproto[i]);
5741+ }
5742+
5743+ /* FIXME: Man, this is a hack. <SIGH> */
5744+ IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
5745+ ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
5746+
5747+ return 0;
5748+}
5749+
5750+/* Clear NAT section of all conntracks, in case we're loaded again. */
5751+static int clean_nat(const struct ip_conntrack *i, void *data)
5752+{
5753+ memset((void *)&i->nat, 0, sizeof(i->nat));
5754+ return 0;
5755+}
5756+
5757+/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
5758+void ip_nat_cleanup(void)
5759+{
5760+ ip_ct_selective_cleanup(&clean_nat, NULL);
5761+ ip_conntrack_destroyed = NULL;
5762+ vfree(bysource);
5763+}
5764diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_rule.c linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_rule.c
5765--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_rule.c 2003-10-25 20:43:27.000000000 +0200
5766+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_rule.c 2003-11-13 11:01:39.000000000 +0100
5767@@ -67,7 +67,7 @@
5768 0,
5769 sizeof(struct ipt_entry),
5770 sizeof(struct ipt_standard),
5771- 0, { 0, 0 }, { } },
5772+ 0, NULL, 0, { 0, 0 }, { } },
5773 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
5774 -NF_ACCEPT - 1 } },
5775 /* POST_ROUTING */
5776@@ -75,7 +75,7 @@
5777 0,
5778 sizeof(struct ipt_entry),
5779 sizeof(struct ipt_standard),
5780- 0, { 0, 0 }, { } },
5781+ 0, NULL, 0, { 0, 0 }, { } },
5782 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
5783 -NF_ACCEPT - 1 } },
5784 /* LOCAL_OUT */
5785@@ -83,7 +83,7 @@
5786 0,
5787 sizeof(struct ipt_entry),
5788 sizeof(struct ipt_standard),
5789- 0, { 0, 0 }, { } },
5790+ 0, NULL, 0, { 0, 0 }, { } },
5791 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
5792 -NF_ACCEPT - 1 } }
5793 },
5794@@ -92,7 +92,7 @@
5795 0,
5796 sizeof(struct ipt_entry),
5797 sizeof(struct ipt_error),
5798- 0, { 0, 0 }, { } },
5799+ 0, NULL, 0, { 0, 0 }, { } },
5800 { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
5801 { } },
5802 "ERROR"
5803diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_tftp.c linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_tftp.c
5804--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_nat_tftp.c 2003-10-25 20:43:18.000000000 +0200
5805+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_nat_tftp.c 2003-11-13 11:01:08.000000000 +0100
5806@@ -164,8 +164,6 @@
5807 ports[0] = TFTP_PORT;
5808
5809 for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
5810- memset(&tftp[i], 0, sizeof(struct ip_nat_helper));
5811-
5812 tftp[i].tuple.dst.protonum = IPPROTO_UDP;
5813 tftp[i].tuple.src.u.udp.port = htons(ports[i]);
5814 tftp[i].mask.dst.protonum = 0xFFFF;
5815diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ip_tables.c linux-2.6.0-test9/net/ipv4/netfilter/ip_tables.c
5816--- linux-2.6.0-test9.org/net/ipv4/netfilter/ip_tables.c 2003-10-25 20:43:11.000000000 +0200
5817+++ linux-2.6.0-test9/net/ipv4/netfilter/ip_tables.c 2003-11-13 11:01:39.000000000 +0100
5818@@ -11,6 +11,7 @@
5819 #include <linux/config.h>
5820 #include <linux/cache.h>
5821 #include <linux/skbuff.h>
5822+#include <linux/socket.h>
5823 #include <linux/kmod.h>
5824 #include <linux/vmalloc.h>
5825 #include <linux/netdevice.h>
5826@@ -23,8 +24,17 @@
5827 #include <asm/semaphore.h>
5828 #include <linux/proc_fs.h>
5829
5830+#include <linux/netfilter.h>
5831 #include <linux/netfilter_ipv4/ip_tables.h>
5832
5833+static const char *hooknames[] = {
5834+ [NF_IP_PRE_ROUTING] "PREROUTING",
5835+ [NF_IP_LOCAL_IN] "INPUT",
5836+ [NF_IP_FORWARD] "FORWARD",
5837+ [NF_IP_LOCAL_OUT] "OUTPUT",
5838+ [NF_IP_POST_ROUTING] "POSTROUTING",
5839+};
5840+
5841 MODULE_LICENSE("GPL");
5842 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
5843 MODULE_DESCRIPTION("IPv4 packet filter");
5844@@ -322,6 +332,12 @@
5845
5846 t = ipt_get_target(e);
5847 IP_NF_ASSERT(t->u.kernel.target);
5848+
5849+ /* The packet traced and the rule isn't an unconditional return/END. */
5850+ if (((*pskb)->nfcache & NFC_TRACE) && e->rulenum) {
5851+ nf_log_packet(AF_INET, hook, *pskb, in, out, "TRACE: %s/%s/%u ",
5852+ table->name, e->chainname, e->rulenum);
5853+ }
5854 /* Standard target? */
5855 if (!t->u.kernel.target->target) {
5856 int v;
5857@@ -474,6 +490,29 @@
5858 return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex);
5859 }
5860
5861+static inline int
5862+find_error_target(struct ipt_entry *s,
5863+ struct ipt_entry *e,
5864+ char **chainname)
5865+{
5866+ struct ipt_entry_target *t;
5867+ static struct ipt_entry *found = NULL;
5868+
5869+ if (s == e) {
5870+ if (!found)
5871+ return 0;
5872+ t = ipt_get_target(found);
5873+ if (strcmp(t->u.user.name,
5874+ IPT_ERROR_TARGET) == 0) {
5875+ *chainname = t->data;
5876+ return 1;
5877+ }
5878+ } else
5879+ found = s;
5880+
5881+ return 0;
5882+}
5883+
5884 /* All zeroes == unconditional rule. */
5885 static inline int
5886 unconditional(const struct ipt_ip *ip)
5887@@ -493,6 +532,8 @@
5888 mark_source_chains(struct ipt_table_info *newinfo, unsigned int valid_hooks)
5889 {
5890 unsigned int hook;
5891+ char *chainname = NULL;
5892+ u_int32_t rulenum;
5893
5894 /* No recursion; use packet counter to save back ptrs (reset
5895 to 0 as we leave), and comefrom to save source hook bitmask */
5896@@ -506,6 +547,8 @@
5897
5898 /* Set initial back pointer. */
5899 e->counters.pcnt = pos;
5900+ rulenum = 1;
5901+ chainname = (char *) hooknames[hook];
5902
5903 for (;;) {
5904 struct ipt_standard_target *t
5905@@ -518,6 +561,8 @@
5906 }
5907 e->comefrom
5908 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
5909+ e->rulenum = rulenum++;
5910+ e->chainname = chainname;
5911
5912 /* Unconditional return/END. */
5913 if (e->target_offset == sizeof(struct ipt_entry)
5914@@ -527,6 +572,10 @@
5915 && unconditional(&e->ip)) {
5916 unsigned int oldpos, size;
5917
5918+ /* Set unconditional rulenum to zero. */
5919+ e->rulenum = 0;
5920+ e->counters.bcnt = 0;
5921+
5922 /* Return: backtrack through the last
5923 big jump. */
5924 do {
5925@@ -552,6 +601,11 @@
5926 (newinfo->entries + pos);
5927 } while (oldpos == pos + e->next_offset);
5928
5929+ /* Restore chainname, rulenum. */
5930+ chainname = e->chainname;
5931+ rulenum = e->counters.bcnt;
5932+ e->counters.bcnt = 0;
5933+
5934 /* Move along one */
5935 size = e->next_offset;
5936 e = (struct ipt_entry *)
5937@@ -567,6 +621,17 @@
5938 /* This a jump; chase it. */
5939 duprintf("Jump rule %u -> %u\n",
5940 pos, newpos);
5941+ e->counters.bcnt = rulenum++;
5942+ rulenum = 1;
5943+ e = (struct ipt_entry *)
5944+ (newinfo->entries + newpos);
5945+ if (IPT_ENTRY_ITERATE(newinfo->entries,
5946+ newinfo->size,
5947+ find_error_target,
5948+ e, &chainname) == 0) {
5949+ printk("ip_tables: table screwed up!\n");
5950+ return 0;
5951+ }
5952 } else {
5953 /* ... this is a fallthru */
5954 newpos = pos + e->next_offset;
5955diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_LOG.c linux-2.6.0-test9/net/ipv4/netfilter/ipt_LOG.c
5956--- linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_LOG.c 2003-10-25 20:44:37.000000000 +0200
5957+++ linux-2.6.0-test9/net/ipv4/netfilter/ipt_LOG.c 2003-11-13 11:01:18.000000000 +0100
5958@@ -4,12 +4,14 @@
5959 #include <linux/module.h>
5960 #include <linux/spinlock.h>
5961 #include <linux/skbuff.h>
5962+#include <linux/socket.h>
5963 #include <linux/ip.h>
5964 #include <net/icmp.h>
5965 #include <net/udp.h>
5966 #include <net/tcp.h>
5967 #include <net/route.h>
5968
5969+#include <linux/netfilter.h>
5970 #include <linux/netfilter_ipv4/ip_tables.h>
5971 #include <linux/netfilter_ipv4/ipt_LOG.h>
5972
5973@@ -17,6 +19,10 @@
5974 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
5975 MODULE_DESCRIPTION("iptables syslog logging module");
5976
5977+static unsigned int nflog = 1;
5978+MODULE_PARM(nflog, "i");
5979+MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
5980+
5981 #if 0
5982 #define DEBUGP printk
5983 #else
5984@@ -315,28 +321,25 @@
5985 /* maxlen = 230+ 91 + 230 + 252 = 803 */
5986 }
5987
5988-static unsigned int
5989-ipt_log_target(struct sk_buff **pskb,
5990+static void
5991+ipt_log_packet(unsigned int hooknum,
5992+ const struct sk_buff *skb,
5993 const struct net_device *in,
5994 const struct net_device *out,
5995- unsigned int hooknum,
5996- const void *targinfo,
5997- void *userinfo)
5998+ const struct ipt_log_info *loginfo,
5999+ const char *level_string,
6000+ const char *prefix)
6001 {
6002- const struct ipt_log_info *loginfo = targinfo;
6003- char level_string[4] = "< >";
6004-
6005- level_string[1] = '0' + (loginfo->level % 8);
6006 spin_lock_bh(&log_lock);
6007 printk(level_string);
6008 printk("%sIN=%s OUT=%s ",
6009- loginfo->prefix,
6010+ prefix == NULL ? loginfo->prefix : prefix,
6011 in ? in->name : "",
6012 out ? out->name : "");
6013 #ifdef CONFIG_BRIDGE_NETFILTER
6014- if ((*pskb)->nf_bridge) {
6015- struct net_device *physindev = (*pskb)->nf_bridge->physindev;
6016- struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
6017+ if (skb->nf_bridge) {
6018+ struct net_device *physindev = skb->nf_bridge->physindev;
6019+ struct net_device *physoutdev = skb->nf_bridge->physoutdev;
6020
6021 if (physindev && in != physindev)
6022 printk("PHYSIN=%s ", physindev->name);
6023@@ -348,25 +351,56 @@
6024 if (in && !out) {
6025 /* MAC logging for input chain only. */
6026 printk("MAC=");
6027- if ((*pskb)->dev && (*pskb)->dev->hard_header_len
6028- && (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
6029+ if (skb->dev && skb->dev->hard_header_len
6030+ && skb->mac.raw != (void*)skb->nh.iph) {
6031 int i;
6032- unsigned char *p = (*pskb)->mac.raw;
6033- for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
6034+ unsigned char *p = skb->mac.raw;
6035+ for (i = 0; i < skb->dev->hard_header_len; i++,p++)
6036 printk("%02x%c", *p,
6037- i==(*pskb)->dev->hard_header_len - 1
6038+ i==skb->dev->hard_header_len - 1
6039 ? ' ':':');
6040 } else
6041 printk(" ");
6042 }
6043
6044- dump_packet(loginfo, *pskb, 0);
6045+ dump_packet(loginfo, skb, 0);
6046 printk("\n");
6047 spin_unlock_bh(&log_lock);
6048+}
6049+
6050+static unsigned int
6051+ipt_log_target(struct sk_buff **pskb,
6052+ const struct net_device *in,
6053+ const struct net_device *out,
6054+ unsigned int hooknum,
6055+ const void *targinfo,
6056+ void *userinfo)
6057+{
6058+ const struct ipt_log_info *loginfo = targinfo;
6059+ char level_string[4] = "< >";
6060+
6061+ level_string[1] = '0' + (loginfo->level % 8);
6062+ ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
6063
6064 return IPT_CONTINUE;
6065 }
6066
6067+static void
6068+ipt_logfn(unsigned int hooknum,
6069+ const struct sk_buff *skb,
6070+ const struct net_device *in,
6071+ const struct net_device *out,
6072+ const char *prefix)
6073+{
6074+ struct ipt_log_info loginfo = {
6075+ .level = 0,
6076+ .logflags = IPT_LOG_MASK,
6077+ .prefix = ""
6078+ };
6079+
6080+ ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
6081+}
6082+
6083 static int ipt_log_checkentry(const char *tablename,
6084 const struct ipt_entry *e,
6085 void *targinfo,
6086@@ -406,12 +440,17 @@
6087 {
6088 if (ipt_register_target(&ipt_log_reg))
6089 return -EINVAL;
6090+ if (nflog)
6091+ nf_log_register(PF_INET, &ipt_logfn);
6092
6093 return 0;
6094 }
6095
6096 static void __exit fini(void)
6097 {
6098+ if (nflog)
6099+ nf_log_unregister(PF_INET, &ipt_logfn);
6100+
6101 ipt_unregister_target(&ipt_log_reg);
6102 }
6103
6104diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_NOTRACK.c linux-2.6.0-test9/net/ipv4/netfilter/ipt_NOTRACK.c
6105--- linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_NOTRACK.c 1970-01-01 01:00:00.000000000 +0100
6106+++ linux-2.6.0-test9/net/ipv4/netfilter/ipt_NOTRACK.c 2003-11-13 11:01:39.000000000 +0100
6107@@ -0,0 +1,79 @@
6108+/* This is a module which is used for setting up fake conntracks
6109+ * on packets so that they are not seen by the conntrack/NAT code.
6110+ */
6111+#include <linux/module.h>
6112+#include <linux/skbuff.h>
6113+
6114+#include <linux/netfilter_ipv4/ip_tables.h>
6115+#include <linux/netfilter_ipv4/ip_conntrack.h>
6116+
6117+static unsigned int
6118+target(struct sk_buff **pskb,
6119+ const struct net_device *in,
6120+ const struct net_device *out,
6121+ unsigned int hooknum,
6122+ const void *targinfo,
6123+ void *userinfo)
6124+{
6125+ /* Previously seen (loopback)? Ignore. */
6126+ if ((*pskb)->nfct != NULL)
6127+ return IPT_CONTINUE;
6128+
6129+ /* Attach fake conntrack entry.
6130+ If there is a real ct entry correspondig to this packet,
6131+ it'll hang aroun till timing out. We don't deal with it
6132+ for performance reasons. JK */
6133+ (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
6134+ nf_conntrack_get((*pskb)->nfct);
6135+
6136+ return IPT_CONTINUE;
6137+}
6138+
6139+static int
6140+checkentry(const char *tablename,
6141+ const struct ipt_entry *e,
6142+ void *targinfo,
6143+ unsigned int targinfosize,
6144+ unsigned int hook_mask)
6145+{
6146+ if (targinfosize != 0) {
6147+ printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
6148+ targinfosize);
6149+ return 0;
6150+ }
6151+
6152+ if (strcmp(tablename, "raw") != 0) {
6153+ printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
6154+ return 0;
6155+ }
6156+
6157+ return 1;
6158+}
6159+
6160+static struct ipt_target ipt_notrack_reg = {
6161+ .name = "NOTRACK",
6162+ .target = target,
6163+ .checkentry = checkentry,
6164+ .destroy = NULL,
6165+ .me = THIS_MODULE,
6166+};
6167+
6168+static int __init init(void)
6169+{
6170+ if (ipt_register_target(&ipt_notrack_reg))
6171+ return -EINVAL;
6172+
6173+ return 0;
6174+}
6175+
6176+static void __exit fini(void)
6177+{
6178+ ipt_unregister_target(&ipt_notrack_reg);
6179+}
6180+
6181+module_init(init);
6182+module_exit(fini);
6183+
6184+MODULE_LICENSE("GPL");
6185+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6186+MODULE_DESCRIPTION("IPv4 NOTRACK target");
6187diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_TRACE.c linux-2.6.0-test9/net/ipv4/netfilter/ipt_TRACE.c
6188--- linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_TRACE.c 1970-01-01 01:00:00.000000000 +0100
6189+++ linux-2.6.0-test9/net/ipv4/netfilter/ipt_TRACE.c 2003-11-13 11:01:39.000000000 +0100
6190@@ -0,0 +1,67 @@
6191+/* This is a module which is used for setting
6192+ * the NFC_TRACE flag in the nfcache field of an skb.
6193+ */
6194+#include <linux/module.h>
6195+#include <linux/skbuff.h>
6196+
6197+#include <linux/netfilter_ipv4/ip_tables.h>
6198+
6199+static unsigned int
6200+target(struct sk_buff **pskb,
6201+ const struct net_device *in,
6202+ const struct net_device *out,
6203+ unsigned int hooknum,
6204+ const void *targinfo,
6205+ void *userinfo)
6206+{
6207+ (*pskb)->nfcache |= NFC_TRACE;
6208+ return IPT_CONTINUE;
6209+}
6210+
6211+static int
6212+checkentry(const char *tablename,
6213+ const struct ipt_entry *e,
6214+ void *targinfo,
6215+ unsigned int targinfosize,
6216+ unsigned int hook_mask)
6217+{
6218+ if (targinfosize != 0) {
6219+ printk(KERN_WARNING "TRACE: targinfosize %u != 0\n",
6220+ targinfosize);
6221+ return 0;
6222+ }
6223+
6224+ if (strcmp(tablename, "raw") != 0) {
6225+ printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename);
6226+ return 0;
6227+ }
6228+
6229+ return 1;
6230+}
6231+
6232+static struct ipt_target ipt_trace_reg = {
6233+ .name = "TRACE",
6234+ .target = target,
6235+ .checkentry = checkentry,
6236+ .destroy = NULL,
6237+ .me = THIS_MODULE,
6238+};
6239+
6240+static int __init init(void)
6241+{
6242+ if (ipt_register_target(&ipt_trace_reg))
6243+ return -EINVAL;
6244+
6245+ return 0;
6246+}
6247+
6248+static void __exit fini(void)
6249+{
6250+ ipt_unregister_target(&ipt_trace_reg);
6251+}
6252+
6253+module_init(init);
6254+module_exit(fini);
6255+MODULE_LICENSE("GPL");
6256+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6257+MODULE_DESCRIPTION("IPv4 TRACE target");
6258diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_ULOG.c linux-2.6.0-test9/net/ipv4/netfilter/ipt_ULOG.c
6259--- linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_ULOG.c 2003-10-25 20:43:22.000000000 +0200
6260+++ linux-2.6.0-test9/net/ipv4/netfilter/ipt_ULOG.c 2003-11-13 11:01:18.000000000 +0100
6261@@ -45,6 +45,7 @@
6262 #include <linux/netlink.h>
6263 #include <linux/netdevice.h>
6264 #include <linux/mm.h>
6265+#include <linux/netfilter.h>
6266 #include <linux/netfilter_ipv4/ip_tables.h>
6267 #include <linux/netfilter_ipv4/ipt_ULOG.h>
6268 #include <linux/netfilter_ipv4/lockhelp.h>
6269@@ -75,6 +76,10 @@
6270 MODULE_PARM(flushtimeout, "i");
6271 MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
6272
6273+static unsigned int nflog = 1;
6274+MODULE_PARM(nflog, "i");
6275+MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
6276+
6277 /* global data structures */
6278
6279 typedef struct {
6280@@ -152,17 +157,17 @@
6281 return skb;
6282 }
6283
6284-static unsigned int ipt_ulog_target(struct sk_buff **pskb,
6285- const struct net_device *in,
6286- const struct net_device *out,
6287- unsigned int hooknum,
6288- const void *targinfo, void *userinfo)
6289+static void ipt_ulog_packet(unsigned int hooknum,
6290+ const struct sk_buff *skb,
6291+ const struct net_device *in,
6292+ const struct net_device *out,
6293+ const struct ipt_ulog_info *loginfo,
6294+ const char *prefix)
6295 {
6296 ulog_buff_t *ub;
6297 ulog_packet_msg_t *pm;
6298 size_t size, copy_len;
6299 struct nlmsghdr *nlh;
6300- struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
6301
6302 /* ffs == find first bit set, necessary because userspace
6303 * is already shifting groupnumber, but we need unshifted.
6304@@ -171,8 +176,8 @@
6305
6306 /* calculate the size of the skb needed */
6307 if ((loginfo->copy_range == 0) ||
6308- (loginfo->copy_range > (*pskb)->len)) {
6309- copy_len = (*pskb)->len;
6310+ (loginfo->copy_range > skb->len)) {
6311+ copy_len = skb->len;
6312 } else {
6313 copy_len = loginfo->copy_range;
6314 }
6315@@ -209,19 +214,21 @@
6316
6317 /* copy hook, prefix, timestamp, payload, etc. */
6318 pm->data_len = copy_len;
6319- pm->timestamp_sec = (*pskb)->stamp.tv_sec;
6320- pm->timestamp_usec = (*pskb)->stamp.tv_usec;
6321- pm->mark = (*pskb)->nfmark;
6322+ pm->timestamp_sec = skb->stamp.tv_sec;
6323+ pm->timestamp_usec = skb->stamp.tv_usec;
6324+ pm->mark = skb->nfmark;
6325 pm->hook = hooknum;
6326- if (loginfo->prefix[0] != '\0')
6327+ if (prefix != NULL)
6328+ strncpy(pm->prefix, prefix, sizeof(pm->prefix));
6329+ else if (loginfo->prefix[0] != '\0')
6330 strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
6331 else
6332 *(pm->prefix) = '\0';
6333
6334 if (in && in->hard_header_len > 0
6335- && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
6336+ && skb->mac.raw != (void *) skb->nh.iph
6337 && in->hard_header_len <= ULOG_MAC_LEN) {
6338- memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
6339+ memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
6340 pm->mac_len = in->hard_header_len;
6341 } else
6342 pm->mac_len = 0;
6343@@ -236,8 +243,8 @@
6344 else
6345 pm->outdev_name[0] = '\0';
6346
6347- /* copy_len <= (*pskb)->len, so can't fail. */
6348- if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
6349+ /* copy_len <= skb->len, so can't fail. */
6350+ if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
6351 BUG();
6352
6353 /* check if we are building multi-part messages */
6354@@ -261,8 +268,7 @@
6355
6356 UNLOCK_BH(&ulog_lock);
6357
6358- return IPT_CONTINUE;
6359-
6360+ return;
6361
6362 nlmsg_failure:
6363 PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
6364@@ -271,8 +277,35 @@
6365 PRINTR("ipt_ULOG: Error building netlink message\n");
6366
6367 UNLOCK_BH(&ulog_lock);
6368+}
6369+
6370+static unsigned int ipt_ulog_target(struct sk_buff **pskb,
6371+ const struct net_device *in,
6372+ const struct net_device *out,
6373+ unsigned int hooknum,
6374+ const void *targinfo, void *userinfo)
6375+{
6376+ struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
6377
6378- return IPT_CONTINUE;
6379+ ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
6380+
6381+ return IPT_CONTINUE;
6382+}
6383+
6384+static void ipt_logfn(unsigned int hooknum,
6385+ const struct sk_buff *skb,
6386+ const struct net_device *in,
6387+ const struct net_device *out,
6388+ const char *prefix)
6389+{
6390+ struct ipt_ulog_info loginfo = {
6391+ .nl_group = NFLOG_DEFAULT_NLGROUP,
6392+ .copy_range = 0,
6393+ .qthreshold = NFLOG_DEFAULT_QTHRESHOLD,
6394+ .prefix = ""
6395+ };
6396+
6397+ ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
6398 }
6399
6400 static int ipt_ulog_checkentry(const char *tablename,
6401@@ -337,6 +370,9 @@
6402 return -EINVAL;
6403 }
6404
6405+ if (nflog)
6406+ nf_log_register(PF_INET, &ipt_logfn);
6407+
6408 return 0;
6409 }
6410
6411@@ -347,6 +383,9 @@
6412
6413 DEBUGP("ipt_ULOG: cleanup_module\n");
6414
6415+ if (nflog)
6416+ nf_log_unregister(PF_INET, &ipt_logfn);
6417+
6418 ipt_unregister_target(&ipt_ulog_reg);
6419 sock_release(nflognl->sk_socket);
6420
6421diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.0-test9/net/ipv4/netfilter/ipt_conntrack.c
6422--- linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_conntrack.c 2003-10-25 20:44:42.000000000 +0200
6423+++ linux-2.6.0-test9/net/ipv4/netfilter/ipt_conntrack.c 2003-11-13 11:01:39.000000000 +0100
6424@@ -29,7 +29,9 @@
6425
6426 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
6427
6428- if (ct)
6429+ if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
6430+ statebit = IPT_CONNTRACK_STATE_UNTRACKED;
6431+ else if (ct)
6432 statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6433 else
6434 statebit = IPT_CONNTRACK_STATE_INVALID;
6435diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.0-test9/net/ipv4/netfilter/ipt_sctp.c
6436--- linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 01:00:00.000000000 +0100
6437+++ linux-2.6.0-test9/net/ipv4/netfilter/ipt_sctp.c 2003-11-13 11:01:48.000000000 +0100
6438@@ -0,0 +1,125 @@
6439+/* IP tables module for matching the SCTP header
6440+ *
6441+ * $ipt_sctp.c,v 1.3 2002/05/29 15:09:00 laforge Exp$
6442+ *
6443+ * (C) 2003 by Harald Welte <laforge@gnumonks.org>
6444+ *
6445+ * This software is distributed under the terms GNU GPL v2
6446+ */
6447+
6448+#include <linux/module.h>
6449+#include <linux/skbuff.h>
6450+#include <linux/sctp.h>
6451+
6452+#include <linux/netfilter_ipv4/ip_tables.h>
6453+#include <linux/netfilter_ipv4/ipt_sctp.h>
6454+
6455+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
6456+MODULE_DESCRIPTION("IP tables SCTP matching module");
6457+MODULE_LICENSE("GPL");
6458+
6459+/* Returns 1 if the port is matched by the range, 0 otherwise */
6460+static inline int
6461+port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
6462+{
6463+ int ret;
6464+
6465+ ret = (port >= min && port <= max) ^ invert;
6466+ return ret;
6467+}
6468+
6469+static int chunk_match(const struct sk_buff *skb, u_int32_t chunks, u_int32_t chunk_mask)
6470+{
6471+ sctp_chunkhdr_t *ch = (sctp_chunkhdr_t *) skb->data;
6472+
6473+ u_int32_t chunks_present = 0;
6474+
6475+ do {
6476+ u_int8_t *ch_end;
6477+ ch_end = ((u_int8_t *) ch) + WORD_ROUND(ntohs(ch->length));
6478+
6479+ if (ch->type < 32)
6480+ chunks_present |= (1 << ch_type);
6481+ else if (ch->type == SCTP_CID_ASCONF)
6482+ chunks_present |= (1 << 31);
6483+ else if (ch->type == SCTP_CID_ASCONF_ACK)
6484+ chunks_present |= (1 << 30);
6485+
6486+ ch = (sctp_chunkhdr_t *) ch_end;
6487+ } while (ch_end < skb->tail);
6488+
6489+ return ((chunks_present& chunk_mask) == chunks);
6490+}
6491+
6492+static int match(const struct sk_buff *skb, const struct net_device *in,
6493+ const struct net_device *out, const void *matchinfo,
6494+ int offset, const void *hdr, u_int16_t datalen,
6495+ int *hotdrop)
6496+{
6497+ const struct ipt_sctp_info *info = matchinfo;
6498+ const struct iphdr *iph = skb->nh.iph;
6499+ const struct sctphdr *sh = (struct sctphdr *) skb->h.raw;
6500+
6501+ if (iph->protocol != IPPROTO_SCTP)
6502+ return 0;
6503+
6504+ if (offset == 1) {
6505+ duprintf("Dropping evil SCTP offset=1 frag.\n");
6506+ *hotdrop = 1;
6507+ return 0;
6508+ } else if (offset == 0 && datalen < sizeof(struct sctphdr)) {
6509+ /* We've been askd o examine this packet, and we can't.
6510+ * Hence, no choice but to drop. */
6511+ duprintf("Dropping evil SCTP offset=0 tinygram.\n");
6512+ *hotdrop = 1;
6513+ return 0;
6514+ }
6515+
6516+ return (!offset
6517+ && port_match(info->spts[0], info->spts[1],
6518+ ntohs(sh->source),
6519+ !!(info->invflags & IPT_SCTP_INV_SRCPT))
6520+ && port_match(info->dpts[0], info->dpts[1],
6521+ ntohs(sh->dest),
6522+ !!(info->invflags & IPT_SCTP_INV_DSTPT))
6523+ && chunk_match(skb, info->chunks, info->chunk_mask)
6524+ );
6525+}
6526+
6527+static int checkentry(const char *tablename, const struct ipt_ip *ip,
6528+ void *matchinfo, unsigned int matchsize,
6529+ unsigned int hook_mask)
6530+{
6531+ const struct ipt_sctp_info *info = matchinfo;
6532+
6533+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_sctp_info)))
6534+ return 0;
6535+
6536+ if (ip->proto != IPPROTO_SCTP && !(ip->invflags & IPT_INV_PROTO))
6537+ return 0;
6538+
6539+ if !(info->invflags & ~IPT_SCTP_INV_MASK)
6540+ return 0;
6541+
6542+ return 1;
6543+}
6544+
6545+static struct ipt_match sctp_match = {
6546+ .name = "sctp",
6547+ .match = &match,
6548+ .checkentry = &checkentry,
6549+ .me = THIS_MODULE,
6550+};
6551+
6552+static int __init init(void)
6553+{
6554+ return ipt_register_match(&sctp_match);
6555+}
6556+
6557+static void __exit fini(void)
6558+{
6559+ ipt_unregister_match(&sctp_match);
6560+}
6561+
6562+module_init(init);
6563+module_exit(fini);
6564diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_state.c linux-2.6.0-test9/net/ipv4/netfilter/ipt_state.c
6565--- linux-2.6.0-test9.org/net/ipv4/netfilter/ipt_state.c 2003-10-25 20:44:59.000000000 +0200
6566+++ linux-2.6.0-test9/net/ipv4/netfilter/ipt_state.c 2003-11-13 11:01:39.000000000 +0100
6567@@ -23,10 +23,12 @@
6568 enum ip_conntrack_info ctinfo;
6569 unsigned int statebit;
6570
6571- if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
6572- statebit = IPT_STATE_INVALID;
6573- else
6574+ if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
6575+ statebit = IPT_STATE_UNTRACKED;
6576+ else if (ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
6577 statebit = IPT_STATE_BIT(ctinfo);
6578+ else
6579+ statebit = IPT_STATE_INVALID;
6580
6581 return (sinfo->statemask & statebit);
6582 }
6583diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/iptable_filter.c linux-2.6.0-test9/net/ipv4/netfilter/iptable_filter.c
6584--- linux-2.6.0-test9.org/net/ipv4/netfilter/iptable_filter.c 2003-10-25 20:43:23.000000000 +0200
6585+++ linux-2.6.0-test9/net/ipv4/netfilter/iptable_filter.c 2003-11-13 11:01:39.000000000 +0100
6586@@ -52,7 +52,7 @@
6587 0,
6588 sizeof(struct ipt_entry),
6589 sizeof(struct ipt_standard),
6590- 0, { 0, 0 }, { } },
6591+ 0, NULL, 0, { 0, 0 }, { } },
6592 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6593 -NF_ACCEPT - 1 } },
6594 /* FORWARD */
6595@@ -60,7 +60,7 @@
6596 0,
6597 sizeof(struct ipt_entry),
6598 sizeof(struct ipt_standard),
6599- 0, { 0, 0 }, { } },
6600+ 0, NULL, 0, { 0, 0 }, { } },
6601 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6602 -NF_ACCEPT - 1 } },
6603 /* LOCAL_OUT */
6604@@ -68,7 +68,7 @@
6605 0,
6606 sizeof(struct ipt_entry),
6607 sizeof(struct ipt_standard),
6608- 0, { 0, 0 }, { } },
6609+ 0, NULL, 0, { 0, 0 }, { } },
6610 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6611 -NF_ACCEPT - 1 } }
6612 },
6613@@ -77,7 +77,7 @@
6614 0,
6615 sizeof(struct ipt_entry),
6616 sizeof(struct ipt_error),
6617- 0, { 0, 0 }, { } },
6618+ 0, NULL, 0, { 0, 0 }, { } },
6619 { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
6620 { } },
6621 "ERROR"
6622diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/iptable_mangle.c linux-2.6.0-test9/net/ipv4/netfilter/iptable_mangle.c
6623--- linux-2.6.0-test9.org/net/ipv4/netfilter/iptable_mangle.c 2003-10-25 20:44:37.000000000 +0200
6624+++ linux-2.6.0-test9/net/ipv4/netfilter/iptable_mangle.c 2003-11-13 11:01:39.000000000 +0100
6625@@ -69,7 +69,7 @@
6626 0,
6627 sizeof(struct ipt_entry),
6628 sizeof(struct ipt_standard),
6629- 0, { 0, 0 }, { } },
6630+ 0, NULL, 0, { 0, 0 }, { } },
6631 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6632 -NF_ACCEPT - 1 } },
6633 /* LOCAL_IN */
6634@@ -77,7 +77,7 @@
6635 0,
6636 sizeof(struct ipt_entry),
6637 sizeof(struct ipt_standard),
6638- 0, { 0, 0 }, { } },
6639+ 0, NULL, 0, { 0, 0 }, { } },
6640 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6641 -NF_ACCEPT - 1 } },
6642 /* FORWARD */
6643@@ -85,7 +85,7 @@
6644 0,
6645 sizeof(struct ipt_entry),
6646 sizeof(struct ipt_standard),
6647- 0, { 0, 0 }, { } },
6648+ 0, NULL, 0, { 0, 0 }, { } },
6649 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6650 -NF_ACCEPT - 1 } },
6651 /* LOCAL_OUT */
6652@@ -93,7 +93,7 @@
6653 0,
6654 sizeof(struct ipt_entry),
6655 sizeof(struct ipt_standard),
6656- 0, { 0, 0 }, { } },
6657+ 0, NULL, 0, { 0, 0 }, { } },
6658 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6659 -NF_ACCEPT - 1 } },
6660 /* POST_ROUTING */
6661@@ -101,7 +101,7 @@
6662 0,
6663 sizeof(struct ipt_entry),
6664 sizeof(struct ipt_standard),
6665- 0, { 0, 0 }, { } },
6666+ 0, NULL, 0, { 0, 0 }, { } },
6667 { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6668 -NF_ACCEPT - 1 } },
6669 },
6670@@ -110,7 +110,7 @@
6671 0,
6672 sizeof(struct ipt_entry),
6673 sizeof(struct ipt_error),
6674- 0, { 0, 0 }, { } },
6675+ 0, NULL, 0, { 0, 0 }, { } },
6676 { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
6677 { } },
6678 "ERROR"
6679diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/iptable_raw.c linux-2.6.0-test9/net/ipv4/netfilter/iptable_raw.c
6680--- linux-2.6.0-test9.org/net/ipv4/netfilter/iptable_raw.c 1970-01-01 01:00:00.000000000 +0100
6681+++ linux-2.6.0-test9/net/ipv4/netfilter/iptable_raw.c 2003-11-13 11:01:39.000000000 +0100
6682@@ -0,0 +1,153 @@
6683+/*
6684+ * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
6685+ *
6686+ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
6687+ */
6688+#include <linux/module.h>
6689+#include <linux/netfilter_ipv4/ip_tables.h>
6690+
6691+#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
6692+
6693+/* Standard entry. */
6694+struct ipt_standard
6695+{
6696+ struct ipt_entry entry;
6697+ struct ipt_standard_target target;
6698+};
6699+
6700+struct ipt_error_target
6701+{
6702+ struct ipt_entry_target target;
6703+ char errorname[IPT_FUNCTION_MAXNAMELEN];
6704+};
6705+
6706+struct ipt_error
6707+{
6708+ struct ipt_entry entry;
6709+ struct ipt_error_target target;
6710+};
6711+
6712+static struct
6713+{
6714+ struct ipt_replace repl;
6715+ struct ipt_standard entries[2];
6716+ struct ipt_error term;
6717+} initial_table __initdata
6718+= { { "raw", RAW_VALID_HOOKS, 3,
6719+ sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
6720+ { [NF_IP_PRE_ROUTING] 0,
6721+ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
6722+ { [NF_IP_PRE_ROUTING] 0,
6723+ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
6724+ 0, NULL, { } },
6725+ {
6726+ /* PRE_ROUTING */
6727+ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
6728+ 0,
6729+ sizeof(struct ipt_entry),
6730+ sizeof(struct ipt_standard),
6731+ 0, NULL, 0, { 0, 0 }, { } },
6732+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6733+ -NF_ACCEPT - 1 } },
6734+ /* LOCAL_OUT */
6735+ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
6736+ 0,
6737+ sizeof(struct ipt_entry),
6738+ sizeof(struct ipt_standard),
6739+ 0, NULL, 0, { 0, 0 }, { } },
6740+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
6741+ -NF_ACCEPT - 1 } }
6742+ },
6743+ /* ERROR */
6744+ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
6745+ 0,
6746+ sizeof(struct ipt_entry),
6747+ sizeof(struct ipt_error),
6748+ 0, NULL, 0, { 0, 0 }, { } },
6749+ { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
6750+ { } },
6751+ "ERROR"
6752+ }
6753+ }
6754+};
6755+
6756+static struct ipt_table packet_raw = {
6757+ .name = "raw",
6758+ .table = &initial_table.repl,
6759+ .valid_hooks = RAW_VALID_HOOKS,
6760+ .lock = RW_LOCK_UNLOCKED,
6761+ .me = THIS_MODULE,
6762+};
6763+
6764+/* The work comes in here from netfilter.c. */
6765+static unsigned int
6766+ipt_hook(unsigned int hook,
6767+ struct sk_buff **pskb,
6768+ const struct net_device *in,
6769+ const struct net_device *out,
6770+ int (*okfn)(struct sk_buff *))
6771+{
6772+ return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
6773+}
6774+
6775+/* 'raw' is the very first table. */
6776+static struct nf_hook_ops ipt_ops[] = {
6777+ { /* PRE_ROUTING hook */
6778+ .hook = ipt_hook,
6779+ .owner = THIS_MODULE,
6780+ .pf = PF_INET,
6781+ .hooknum = NF_IP_PRE_ROUTING,
6782+ .priority = NF_IP_PRI_RAW,
6783+ },
6784+ { /* LOCAL_OUT hook */
6785+ .hook = ipt_hook,
6786+ .owner = THIS_MODULE,
6787+ .pf = PF_INET,
6788+ .hooknum = NF_IP_LOCAL_OUT,
6789+ .priority = NF_IP_PRI_RAW,
6790+ },
6791+};
6792+
6793+static int __init init(void)
6794+{
6795+ int ret;
6796+
6797+ /* Register table */
6798+ ret = ipt_register_table(&packet_raw);
6799+ if (ret < 0)
6800+ return ret;
6801+
6802+ /* Register hooks */
6803+ ret = nf_register_hook(&ipt_ops[0]);
6804+ if (ret < 0)
6805+ goto cleanup_table;
6806+
6807+ ret = nf_register_hook(&ipt_ops[1]);
6808+ if (ret < 0)
6809+ goto cleanup_hook0;
6810+
6811+ return ret;
6812+
6813+ cleanup_hook0:
6814+ nf_unregister_hook(&ipt_ops[0]);
6815+ cleanup_table:
6816+ ipt_unregister_table(&packet_raw);
6817+
6818+ return ret;
6819+}
6820+
6821+static void __exit fini(void)
6822+{
6823+ unsigned int i;
6824+
6825+ for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
6826+ nf_unregister_hook(&ipt_ops[i]);
6827+
6828+ ipt_unregister_table(&packet_raw);
6829+}
6830+
6831+module_init(init);
6832+module_exit(fini);
6833+MODULE_LICENSE("GPL");
6834+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6835+MODULE_DESCRIPTION("IPv4 raw table");
6836diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/Kconfig linux-2.6.0-test9/net/ipv6/netfilter/Kconfig
6837--- linux-2.6.0-test9.org/net/ipv6/netfilter/Kconfig 2003-10-25 20:44:37.000000000 +0200
6838+++ linux-2.6.0-test9/net/ipv6/netfilter/Kconfig 2003-11-13 11:01:39.000000000 +0100
6839@@ -217,6 +217,31 @@
6840
6841 To compile it as a module, choose M here. If unsure, say N.
6842
6843+config IP6_NF_RAW
6844+ tristate "Raw table"
6845+ depends on IP6_NF_IPTABLES
6846+ help
6847+ This option adds a `raw' table to iptables: see the man page for
6848+ iptables(8). This table is the very first in the netfilter
6849+ framework and hooks in at the PREROUTING and OUTPUT chains.
6850+ The TRACE target can be used in this table only.
6851+
6852+ To compile it as a module, choose M here. If unsure, say N.
6853+
6854+config IP6_NF_TARGET_TRACE
6855+ tristate "TRACE target support"
6856+ depends on IP6_NF_RAW
6857+ help
6858+ The TRACE target allows packets to be traced as those matches
6859+ any subsequent rule in any IPv6 netfilter table/rule. The matched
6860+ rule and the packet is logged with the prefix
6861+
6862+ TRACE: tablename/chainname/rulenum
6863+
6864+ if the ip6t_LOG target is loaded in.
6865+
6866+ To compile it as a module, choose M here. If unsure, say N.
6867+
6868 #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
6869 endmenu
6870
6871diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/Makefile linux-2.6.0-test9/net/ipv6/netfilter/Makefile
6872--- linux-2.6.0-test9.org/net/ipv6/netfilter/Makefile 2003-10-25 20:43:53.000000000 +0200
6873+++ linux-2.6.0-test9/net/ipv6/netfilter/Makefile 2003-11-13 11:01:39.000000000 +0100
6874@@ -18,7 +18,9 @@
6875 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
6876 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
6877 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
6878+obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
6879 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
6880 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
6881 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
6882+obj-$(CONFIG_IP6_NF_TARGET_TRACE) += ip6t_TRACE.o
6883 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
6884diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/ip6_tables.c linux-2.6.0-test9/net/ipv6/netfilter/ip6_tables.c
6885--- linux-2.6.0-test9.org/net/ipv6/netfilter/ip6_tables.c 2003-10-25 20:44:39.000000000 +0200
6886+++ linux-2.6.0-test9/net/ipv6/netfilter/ip6_tables.c 2003-11-13 11:01:39.000000000 +0100
6887@@ -12,6 +12,7 @@
6888 */
6889 #include <linux/config.h>
6890 #include <linux/skbuff.h>
6891+#include <linux/socket.h>
6892 #include <linux/kmod.h>
6893 #include <linux/vmalloc.h>
6894 #include <linux/netdevice.h>
6895@@ -24,8 +25,17 @@
6896 #include <asm/semaphore.h>
6897 #include <linux/proc_fs.h>
6898
6899+#include <linux/netfilter.h>
6900 #include <linux/netfilter_ipv6/ip6_tables.h>
6901
6902+static const char *hook6names[] = {
6903+ [NF_IP6_PRE_ROUTING] "PREROUTING",
6904+ [NF_IP6_LOCAL_IN] "INPUT",
6905+ [NF_IP6_FORWARD] "FORWARD",
6906+ [NF_IP6_LOCAL_OUT] "OUTPUT",
6907+ [NF_IP6_POST_ROUTING] "POSTROUTING",
6908+};
6909+
6910 MODULE_LICENSE("GPL");
6911 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6912 MODULE_DESCRIPTION("IPv6 packet filter");
6913@@ -403,6 +413,12 @@
6914
6915 t = ip6t_get_target(e);
6916 IP_NF_ASSERT(t->u.kernel.target);
6917+
6918+ /* The packet traced and the rule isn't an unconditional return/END. */
6919+ if (((*pskb)->nfcache & NFC_TRACE) && e->rulenum) {
6920+ nf_log_packet(AF_INET6, hook, *pskb, in, out, "TRACE: %s/%s/%u ",
6921+ table->name, e->chainname, e->rulenum);
6922+ }
6923 /* Standard target? */
6924 if (!t->u.kernel.target->target) {
6925 int v;
6926@@ -556,6 +572,29 @@
6927 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
6928 }
6929
6930+static inline int
6931+find_error_target(struct ip6t_entry *s,
6932+ struct ip6t_entry *e,
6933+ char **chainname)
6934+{
6935+ struct ip6t_entry_target *t;
6936+ static struct ip6t_entry *found = NULL;
6937+
6938+ if (s == e) {
6939+ if (!found)
6940+ return 0;
6941+ t = ip6t_get_target(found);
6942+ if (strcmp(t->u.user.name,
6943+ IP6T_ERROR_TARGET) == 0) {
6944+ *chainname = t->data;
6945+ return 1;
6946+ }
6947+ } else
6948+ found = s;
6949+
6950+ return 0;
6951+}
6952+
6953 /* All zeroes == unconditional rule. */
6954 static inline int
6955 unconditional(const struct ip6t_ip6 *ipv6)
6956@@ -575,6 +614,8 @@
6957 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
6958 {
6959 unsigned int hook;
6960+ char *chainname = NULL;
6961+ u_int32_t rulenum;
6962
6963 /* No recursion; use packet counter to save back ptrs (reset
6964 to 0 as we leave), and comefrom to save source hook bitmask */
6965@@ -588,6 +629,8 @@
6966
6967 /* Set initial back pointer. */
6968 e->counters.pcnt = pos;
6969+ rulenum = 1;
6970+ chainname = (char *) hook6names[hook];
6971
6972 for (;;) {
6973 struct ip6t_standard_target *t
6974@@ -600,6 +643,8 @@
6975 }
6976 e->comefrom
6977 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
6978+ e->rulenum = rulenum++;
6979+ e->chainname = chainname;
6980
6981 /* Unconditional return/END. */
6982 if (e->target_offset == sizeof(struct ip6t_entry)
6983@@ -609,6 +654,10 @@
6984 && unconditional(&e->ipv6)) {
6985 unsigned int oldpos, size;
6986
6987+ /* Set unconditional rulenum to zero. */
6988+ e->rulenum = 0;
6989+ e->counters.bcnt = 0;
6990+
6991 /* Return: backtrack through the last
6992 big jump. */
6993 do {
6994@@ -634,6 +683,11 @@
6995 (newinfo->entries + pos);
6996 } while (oldpos == pos + e->next_offset);
6997
6998+ /* Restore chainname, rulenum. */
6999+ chainname = e->chainname;
7000+ rulenum = e->counters.bcnt;
7001+ e->counters.bcnt = 0;
7002+
7003 /* Move along one */
7004 size = e->next_offset;
7005 e = (struct ip6t_entry *)
7006@@ -649,6 +703,17 @@
7007 /* This a jump; chase it. */
7008 duprintf("Jump rule %u -> %u\n",
7009 pos, newpos);
7010+ e->counters.bcnt = rulenum++;
7011+ rulenum = 1;
7012+ e = (struct ip6t_entry *)
7013+ (newinfo->entries + newpos);
7014+ if (IP6T_ENTRY_ITERATE(newinfo->entries,
7015+ newinfo->size,
7016+ find_error_target,
7017+ e, &chainname) == 0) {
7018+ printk("ip6_tables: table screwed up!\n");
7019+ return 0;
7020+ }
7021 } else {
7022 /* ... this is a fallthru */
7023 newpos = pos + e->next_offset;
7024diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/ip6t_LOG.c linux-2.6.0-test9/net/ipv6/netfilter/ip6t_LOG.c
7025--- linux-2.6.0-test9.org/net/ipv6/netfilter/ip6t_LOG.c 2003-10-25 20:43:18.000000000 +0200
7026+++ linux-2.6.0-test9/net/ipv6/netfilter/ip6t_LOG.c 2003-11-13 11:01:18.000000000 +0100
7027@@ -3,18 +3,24 @@
7028 */
7029 #include <linux/module.h>
7030 #include <linux/skbuff.h>
7031+#include <linux/socket.h>
7032 #include <linux/ip.h>
7033 #include <linux/spinlock.h>
7034 #include <linux/icmpv6.h>
7035 #include <net/udp.h>
7036 #include <net/tcp.h>
7037 #include <net/ipv6.h>
7038+#include <linux/netfilter.h>
7039 #include <linux/netfilter_ipv6/ip6_tables.h>
7040
7041 MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
7042 MODULE_DESCRIPTION("IP6 tables LOG target module");
7043 MODULE_LICENSE("GPL");
7044
7045+static unsigned int nflog = 1;
7046+MODULE_PARM(nflog, "i");
7047+MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
7048+
7049 struct in_device;
7050 #include <net/route.h>
7051 #include <linux/netfilter_ipv6/ip6t_LOG.h>
7052@@ -256,40 +262,38 @@
7053 }
7054 }
7055
7056-static unsigned int
7057-ip6t_log_target(struct sk_buff **pskb,
7058- unsigned int hooknum,
7059- const struct net_device *in,
7060- const struct net_device *out,
7061- const void *targinfo,
7062- void *userinfo)
7063+static void
7064+ip6t_log_packet(unsigned int hooknum,
7065+ const struct sk_buff *skb,
7066+ const struct net_device *in,
7067+ const struct net_device *out,
7068+ const struct ip6t_log_info *loginfo,
7069+ const char *level_string,
7070+ const char *prefix)
7071 {
7072- struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
7073- const struct ip6t_log_info *loginfo = targinfo;
7074- char level_string[4] = "< >";
7075+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
7076
7077- level_string[1] = '0' + (loginfo->level % 8);
7078 spin_lock_bh(&log_lock);
7079 printk(level_string);
7080 printk("%sIN=%s OUT=%s ",
7081- loginfo->prefix,
7082+ prefix == NULL ? loginfo->prefix : prefix,
7083 in ? in->name : "",
7084 out ? out->name : "");
7085 if (in && !out) {
7086 /* MAC logging for input chain only. */
7087 printk("MAC=");
7088- if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
7089- if ((*pskb)->dev->type != ARPHRD_SIT){
7090+ if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) {
7091+ if (skb->dev->type != ARPHRD_SIT){
7092 int i;
7093- unsigned char *p = (*pskb)->mac.raw;
7094- for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
7095+ unsigned char *p = skb->mac.raw;
7096+ for (i = 0; i < skb->dev->hard_header_len; i++,p++)
7097 printk("%02x%c", *p,
7098- i==(*pskb)->dev->hard_header_len - 1
7099+ i==skb->dev->hard_header_len - 1
7100 ? ' ':':');
7101 } else {
7102 int i;
7103- unsigned char *p = (*pskb)->mac.raw;
7104- if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
7105+ unsigned char *p = skb->mac.raw;
7106+ if ( p - (ETH_ALEN*2+2) > skb->head ){
7107 p -= (ETH_ALEN+2);
7108 for (i = 0; i < (ETH_ALEN); i++,p++)
7109 printk("%02x%s", *p,
7110@@ -300,10 +304,10 @@
7111 i == ETH_ALEN-1 ? ' ' : ':');
7112 }
7113
7114- if (((*pskb)->dev->addr_len == 4) &&
7115- (*pskb)->dev->hard_header_len > 20){
7116+ if ((skb->dev->addr_len == 4) &&
7117+ skb->dev->hard_header_len > 20){
7118 printk("TUNNEL=");
7119- p = (*pskb)->mac.raw + 12;
7120+ p = skb->mac.raw + 12;
7121 for (i = 0; i < 4; i++,p++)
7122 printk("%3d%s", *p,
7123 i == 3 ? "->" : ".");
7124@@ -319,10 +323,41 @@
7125 dump_packet(loginfo, ipv6h, 1);
7126 printk("\n");
7127 spin_unlock_bh(&log_lock);
7128+}
7129+
7130+static unsigned int
7131+ip6t_log_target(struct sk_buff **pskb,
7132+ unsigned int hooknum,
7133+ const struct net_device *in,
7134+ const struct net_device *out,
7135+ const void *targinfo,
7136+ void *userinfo)
7137+{
7138+ const struct ip6t_log_info *loginfo = targinfo;
7139+ char level_string[4] = "< >";
7140+
7141+ level_string[1] = '0' + (loginfo->level % 8);
7142+ ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
7143
7144 return IP6T_CONTINUE;
7145 }
7146
7147+static void
7148+ip6t_logfn(unsigned int hooknum,
7149+ const struct sk_buff *skb,
7150+ const struct net_device *in,
7151+ const struct net_device *out,
7152+ const char *prefix)
7153+{
7154+ struct ip6t_log_info loginfo = {
7155+ .level = 0,
7156+ .logflags = IP6T_LOG_MASK,
7157+ .prefix = ""
7158+ };
7159+
7160+ ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
7161+}
7162+
7163 static int ip6t_log_checkentry(const char *tablename,
7164 const struct ip6t_entry *e,
7165 void *targinfo,
7166@@ -359,12 +394,17 @@
7167 {
7168 if (ip6t_register_target(&ip6t_log_reg))
7169 return -EINVAL;
7170+ if (nflog)
7171+ nf_log_register(PF_INET6, &ip6t_logfn);
7172
7173 return 0;
7174 }
7175
7176 static void __exit fini(void)
7177 {
7178+ if (nflog)
7179+ nf_log_register(PF_INET6, &ip6t_logfn);
7180+
7181 ip6t_unregister_target(&ip6t_log_reg);
7182 }
7183
7184diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/ip6t_TRACE.c linux-2.6.0-test9/net/ipv6/netfilter/ip6t_TRACE.c
7185--- linux-2.6.0-test9.org/net/ipv6/netfilter/ip6t_TRACE.c 1970-01-01 01:00:00.000000000 +0100
7186+++ linux-2.6.0-test9/net/ipv6/netfilter/ip6t_TRACE.c 2003-11-13 11:01:39.000000000 +0100
7187@@ -0,0 +1,69 @@
7188+/* This is a module which is used for setting
7189+ * the NFC_TRACE flag in the nfcache field of an skb.
7190+ */
7191+#include <linux/module.h>
7192+#include <linux/skbuff.h>
7193+
7194+#include <linux/netfilter_ipv6/ip6_tables.h>
7195+
7196+static unsigned int
7197+target(struct sk_buff **pskb,
7198+ unsigned int hooknum,
7199+ const struct net_device *in,
7200+ const struct net_device *out,
7201+ const void *targinfo,
7202+ void *userinfo)
7203+{
7204+ (*pskb)->nfcache |= NFC_TRACE;
7205+ return IP6T_CONTINUE;
7206+}
7207+
7208+static int
7209+checkentry(const char *tablename,
7210+ const struct ip6t_entry *e,
7211+ void *targinfo,
7212+ unsigned int targinfosize,
7213+ unsigned int hook_mask)
7214+{
7215+ if (targinfosize != 0) {
7216+ printk(KERN_WARNING "TRACE: targinfosize %u != 0\n",
7217+ targinfosize);
7218+ return 0;
7219+ }
7220+
7221+ if (strcmp(tablename, "raw") != 0) {
7222+ printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename);
7223+ return 0;
7224+ }
7225+
7226+ return 1;
7227+}
7228+
7229+static struct ip6t_target ip6t_trace_reg = {
7230+ .name = "TRACE",
7231+ .target = target,
7232+ .checkentry = checkentry,
7233+ .destroy = NULL,
7234+ .me = THIS_MODULE,
7235+};
7236+
7237+static int __init init(void)
7238+{
7239+ if (ip6t_register_target(&ip6t_trace_reg))
7240+ return -EINVAL;
7241+
7242+ return 0;
7243+}
7244+
7245+static void __exit fini(void)
7246+{
7247+ ip6t_unregister_target(&ip6t_trace_reg);
7248+}
7249+
7250+module_init(init);
7251+module_exit(fini);
7252+
7253+MODULE_LICENSE("GPL");
7254+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
7255+MODULE_DESCRIPTION("IPv6 TRACE target");
7256+
7257\ No newline at end of file
7258diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/ip6table_filter.c linux-2.6.0-test9/net/ipv6/netfilter/ip6table_filter.c
7259--- linux-2.6.0-test9.org/net/ipv6/netfilter/ip6table_filter.c 2003-10-25 20:42:53.000000000 +0200
7260+++ linux-2.6.0-test9/net/ipv6/netfilter/ip6table_filter.c 2003-11-13 11:01:39.000000000 +0100
7261@@ -52,7 +52,7 @@
7262 0,
7263 sizeof(struct ip6t_entry),
7264 sizeof(struct ip6t_standard),
7265- 0, { 0, 0 }, { } },
7266+ 0, NULL, 0, { 0, 0 }, { } },
7267 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7268 -NF_ACCEPT - 1 } },
7269 /* FORWARD */
7270@@ -60,7 +60,7 @@
7271 0,
7272 sizeof(struct ip6t_entry),
7273 sizeof(struct ip6t_standard),
7274- 0, { 0, 0 }, { } },
7275+ 0, NULL, 0, { 0, 0 }, { } },
7276 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7277 -NF_ACCEPT - 1 } },
7278 /* LOCAL_OUT */
7279@@ -68,7 +68,7 @@
7280 0,
7281 sizeof(struct ip6t_entry),
7282 sizeof(struct ip6t_standard),
7283- 0, { 0, 0 }, { } },
7284+ 0, NULL, 0, { 0, 0 }, { } },
7285 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7286 -NF_ACCEPT - 1 } }
7287 },
7288@@ -77,7 +77,7 @@
7289 0,
7290 sizeof(struct ip6t_entry),
7291 sizeof(struct ip6t_error),
7292- 0, { 0, 0 }, { } },
7293+ 0, NULL, 0, { 0, 0 }, { } },
7294 { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
7295 { } },
7296 "ERROR"
7297diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/ip6table_mangle.c linux-2.6.0-test9/net/ipv6/netfilter/ip6table_mangle.c
7298--- linux-2.6.0-test9.org/net/ipv6/netfilter/ip6table_mangle.c 2003-10-25 20:43:26.000000000 +0200
7299+++ linux-2.6.0-test9/net/ipv6/netfilter/ip6table_mangle.c 2003-11-13 11:01:39.000000000 +0100
7300@@ -66,7 +66,7 @@
7301 0,
7302 sizeof(struct ip6t_entry),
7303 sizeof(struct ip6t_standard),
7304- 0, { 0, 0 }, { } },
7305+ 0, NULL, 0, { 0, 0 }, { } },
7306 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7307 -NF_ACCEPT - 1 } },
7308 /* LOCAL_IN */
7309@@ -74,7 +74,7 @@
7310 0,
7311 sizeof(struct ip6t_entry),
7312 sizeof(struct ip6t_standard),
7313- 0, { 0, 0 }, { } },
7314+ 0, NULL, 0, { 0, 0 }, { } },
7315 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7316 -NF_ACCEPT - 1 } },
7317 /* FORWARD */
7318@@ -82,7 +82,7 @@
7319 0,
7320 sizeof(struct ip6t_entry),
7321 sizeof(struct ip6t_standard),
7322- 0, { 0, 0 }, { } },
7323+ 0, NULL, 0, { 0, 0 }, { } },
7324 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7325 -NF_ACCEPT - 1 } },
7326 /* LOCAL_OUT */
7327@@ -90,7 +90,7 @@
7328 0,
7329 sizeof(struct ip6t_entry),
7330 sizeof(struct ip6t_standard),
7331- 0, { 0, 0 }, { } },
7332+ 0, NULL, 0, { 0, 0 }, { } },
7333 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7334 -NF_ACCEPT - 1 } },
7335 /* POST_ROUTING */
7336@@ -98,7 +98,7 @@
7337 0,
7338 sizeof(struct ip6t_entry),
7339 sizeof(struct ip6t_standard),
7340- 0, { 0, 0 }, { } },
7341+ 0, NULL, 0, { 0, 0 }, { } },
7342 { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7343 -NF_ACCEPT - 1 } }
7344 },
7345@@ -107,7 +107,7 @@
7346 0,
7347 sizeof(struct ip6t_entry),
7348 sizeof(struct ip6t_error),
7349- 0, { 0, 0 }, { } },
7350+ 0, NULL, 0, { 0, 0 }, { } },
7351 { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
7352 { } },
7353 "ERROR"
7354diff -Nur linux-2.6.0-test9.org/net/ipv6/netfilter/ip6table_raw.c linux-2.6.0-test9/net/ipv6/netfilter/ip6table_raw.c
7355--- linux-2.6.0-test9.org/net/ipv6/netfilter/ip6table_raw.c 1970-01-01 01:00:00.000000000 +0100
7356+++ linux-2.6.0-test9/net/ipv6/netfilter/ip6table_raw.c 2003-11-13 11:01:39.000000000 +0100
7357@@ -0,0 +1,158 @@
7358+/*
7359+ * IPv6 raw table, a port of the IPv4 raw table to IPv6
7360+ *
7361+ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
7362+ */
7363+#include <linux/module.h>
7364+#include <linux/netfilter_ipv6/ip6_tables.h>
7365+
7366+#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
7367+
7368+#if 0
7369+#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
7370+#else
7371+#define DEBUGP(x, args...)
7372+#endif
7373+
7374+/* Standard entry. */
7375+struct ip6t_standard
7376+{
7377+ struct ip6t_entry entry;
7378+ struct ip6t_standard_target target;
7379+};
7380+
7381+struct ip6t_error_target
7382+{
7383+ struct ip6t_entry_target target;
7384+ char errorname[IP6T_FUNCTION_MAXNAMELEN];
7385+};
7386+
7387+struct ip6t_error
7388+{
7389+ struct ip6t_entry entry;
7390+ struct ip6t_error_target target;
7391+};
7392+
7393+static struct
7394+{
7395+ struct ip6t_replace repl;
7396+ struct ip6t_standard entries[2];
7397+ struct ip6t_error term;
7398+} initial_table __initdata
7399+= { { "raw", RAW_VALID_HOOKS, 3,
7400+ sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
7401+ { [NF_IP6_PRE_ROUTING] 0,
7402+ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
7403+ { [NF_IP6_PRE_ROUTING] 0,
7404+ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
7405+ 0, NULL, { } },
7406+ {
7407+ /* PRE_ROUTING */
7408+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
7409+ 0,
7410+ sizeof(struct ip6t_entry),
7411+ sizeof(struct ip6t_standard),
7412+ 0, NULL, 0, { 0, 0 }, { } },
7413+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7414+ -NF_ACCEPT - 1 } },
7415+ /* LOCAL_OUT */
7416+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
7417+ 0,
7418+ sizeof(struct ip6t_entry),
7419+ sizeof(struct ip6t_standard),
7420+ 0, NULL, 0, { 0, 0 }, { } },
7421+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
7422+ -NF_ACCEPT - 1 } },
7423+ },
7424+ /* ERROR */
7425+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
7426+ 0,
7427+ sizeof(struct ip6t_entry),
7428+ sizeof(struct ip6t_error),
7429+ 0, NULL, 0, { 0, 0 }, { } },
7430+ { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
7431+ { } },
7432+ "ERROR"
7433+ }
7434+ }
7435+};
7436+
7437+static struct ip6t_table packet_raw = {
7438+ .name = "raw",
7439+ .table = &initial_table.repl,
7440+ .valid_hooks = RAW_VALID_HOOKS,
7441+ .lock = RW_LOCK_UNLOCKED,
7442+ .me = THIS_MODULE
7443+};
7444+
7445+/* The work comes in here from netfilter.c. */
7446+static unsigned int
7447+ip6t_hook(unsigned int hook,
7448+ struct sk_buff **pskb,
7449+ const struct net_device *in,
7450+ const struct net_device *out,
7451+ int (*okfn)(struct sk_buff *))
7452+{
7453+ return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
7454+}
7455+
7456+static struct nf_hook_ops ip6t_ops[] = {
7457+ { /* PRE_ROUTING */
7458+ .hook = ip6t_hook,
7459+ .owner = THIS_MODULE,
7460+ .pf = PF_INET6,
7461+ .hooknum = NF_IP6_PRE_ROUTING,
7462+ .priority = NF_IP6_PRI_FIRST,
7463+ },
7464+ { /* LOCAL_OUT */
7465+ .hook = ip6t_hook,
7466+ .owner = THIS_MODULE,
7467+ .pf = PF_INET6,
7468+ .hooknum = NF_IP6_LOCAL_OUT,
7469+ .priority = NF_IP6_PRI_FIRST,
7470+ },
7471+};
7472+
7473+static int __init init(void)
7474+{
7475+ int ret;
7476+
7477+ /* Register table */
7478+ ret = ip6t_register_table(&packet_raw);
7479+ if (ret < 0)
7480+ return ret;
7481+
7482+ /* Register hooks */
7483+ ret = nf_register_hook(&ip6t_ops[0]);
7484+ if (ret < 0)
7485+ goto cleanup_table;
7486+
7487+ ret = nf_register_hook(&ip6t_ops[1]);
7488+ if (ret < 0)
7489+ goto cleanup_hook0;
7490+
7491+ return ret;
7492+
7493+ cleanup_hook0:
7494+ nf_unregister_hook(&ip6t_ops[0]);
7495+ cleanup_table:
7496+ ip6t_unregister_table(&packet_raw);
7497+
7498+ return ret;
7499+}
7500+
7501+static void __exit fini(void)
7502+{
7503+ unsigned int i;
7504+
7505+ for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
7506+ nf_unregister_hook(&ip6t_ops[i]);
7507+
7508+ ip6t_unregister_table(&packet_raw);
7509+}
7510+
7511+module_init(init);
7512+module_exit(fini);
7513+MODULE_LICENSE("GPL");
7514+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
7515+MODULE_DESCRIPTION("IPv6 raw table");
7516diff -Nur linux-2.6.0-test9.org/netfilter-patch-o-matic/patches linux-2.6.0-test9/netfilter-patch-o-matic/patches
7517--- linux-2.6.0-test9.org/netfilter-patch-o-matic/patches 1970-01-01 01:00:00.000000000 +0100
7518+++ linux-2.6.0-test9/netfilter-patch-o-matic/patches 2003-11-13 11:02:28.000000000 +0100
7519@@ -0,0 +1,30 @@
7520+./base/01_sctp_match.patch
7521+./pending/23_REJECT-headroom-tcprst.patch
7522+./pending/24_rcu.patch
7523+./pending/25-err-ptr.patch
7524+./pending/26-memsets.patch
7525+./pending/40_nf-log.patch
7526+./pending/70_expect-evict-order.patch
7527+./pending/71_raw.patch
7528+./submitted/02_REJECT-headroom-tcprst.patch
7529+./submitted/03_260t4-mirror-remove.patch
7530+./submitted/03_physdev_bridged.patch
7531+./submitted/04_260t4-unclean-remove.patch
7532+./submitted/05_260t4-unexperimental.patch
7533+./submitted/06_260t4-cosmetic.patch
7534+./submitted/07_260t4-newmodules_iprange_SAME_NETMAP_CLASSIFY.patch
7535+./submitted/07_nonlinear_skb.patch
7536+./submitted/08_260t4_ipt-helper-kconfig.patch
7537+./submitted/09_260t4-cosmetic-physdev-author.patch
7538+./submitted/75_nathelper-udp-csum.patch
7539+./submitted/76_mangle_udp-sizecheck.patch
7540+./submitted/77_destroy-conntrack.patch
7541+./submitted/78_reject-localout.patch
7542+./submitted/80_ip_conntrack-proc.patch
7543+./submitted/82_irc-conntrack-mirc-serverlookup.patch
7544+./submitted/83_nolocalout.patch
7545+./submitted/84_local-nullbinding.patch
7546+./submitted/85_ipv6header.patch
7547+./submitted/86_getorigdst-tuple-zero.patch
7548+./submitted/87_compat-nat_setup_info.patch
7549+./submitted/89_ip_queue-maxlen.patch
This page took 1.007249 seconds and 4 git commands to generate.