1 diff -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
5 <= 0x2000 is used for protocol-flags. */
6 #define NFC_UNKNOWN 0x4000
7 #define NFC_ALTERED 0x8000
8 +#define NFC_TRACE 0x10000
11 #include <linux/config.h>
14 extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
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);
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);
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, ...);
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
37 diff -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
42 extern unsigned int ip_conntrack_htable_size;
44 +/* A fake conntrack entry which never vanishes. */
45 +extern struct ip_conntrack ip_conntrack_untracked;
47 /* eg. PROVIDES_CONNTRACK(ftp); */
48 #define PROVIDES_CONNTRACK(name) \
49 int needs_ip_conntrack_##name; \
50 diff -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
55 unsigned int comefrom;
57 + /* Name of the chain */
60 + /* Rule number in the chain. */
63 /* Packet and byte counters. */
64 struct ipt_counters counters;
66 diff -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
70 #define NETLINK_NFLOG 5
73 +#define NFLOG_DEFAULT_NLGROUP 1
74 +#define NFLOG_DEFAULT_QTHRESHOLD 1
76 #define ULOG_MAC_LEN 80
77 #define ULOG_PREFIX_LEN 32
79 diff -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
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))
88 /* flags, invflags: */
89 #define IPT_CONNTRACK_STATE 0x01
90 diff -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
94 +/* iptables module for matching the SCTP header
96 + * (C) 2003 Harald Welte <laforge@gnumonks.org>
98 + * This software is distributed under GNU GPL v2, 1991
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 */
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 */
118 +#endif /* _IPT_SCTP_H */
119 diff -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
123 #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
124 #define IPT_STATE_INVALID (1 << 0)
126 +#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
128 struct ipt_state_info
130 unsigned int statemask;
131 diff -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
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,
143 diff -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
148 unsigned int comefrom;
150 + /* Name of the chain */
153 + /* Rule number in the chain. */
156 /* Packet and byte counters. */
157 struct ip6t_counters counters;
159 diff -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
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;
170 nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
171 diff -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
176 + * Handle firewalling
177 + * Linux ethernet bridge
180 + * Lennert Buytenhek <buytenh@gnu.org>
181 + * Bart De Schuymer (maintainer) <bdschuym@pandora.be>
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
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.
194 + * Lennert dedicates this file to Kerstin Wurdinger.
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>
209 +#include <asm/uaccess.h>
210 +#include <asm/checksum.h>
211 +#include "br_private.h"
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)))
221 +#define has_bridge_parent(device) ((device)->br_port != NULL)
222 +#define bridge_parent(device) ((device)->br_port->br->dev)
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))
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.
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.
238 +static struct net_device __fake_net_device = {
239 + .hard_header_len = ETH_HLEN
242 +static struct rtable __fake_rtable = {
245 + .__refcnt = ATOMIC_INIT(1),
246 + .dev = &__fake_net_device,
247 + .path = &__fake_rtable.u.dst,
248 + .metrics = {[RTAX_MTU - 1] = 1500},
256 +/* PF_BRIDGE/PRE_ROUTING *********************************************/
257 +static void __br_dnat_complain(void)
259 + static unsigned long last_complaint;
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;
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.
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
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.
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.
285 + * Let us first consider the case that ip_route_input() succeeds:
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.
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.
297 + * Let us now consider the case that ip_route_input() fails:
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.
306 + * ip_route_input() will also fail if there is no route available.
307 + * In that case we just drop the packet.
309 + * --Lennert, 20020411
310 + * --Bart, 20020416 (updated)
311 + * --Bart, 20021007 (updated)
314 +static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
316 +#ifdef CONFIG_NETFILTER_DEBUG
317 + skb->nf_debug |= (1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_FORWARD);
320 + if (skb->pkt_type == PACKET_OTHERHOST) {
321 + skb->pkt_type = PACKET_HOST;
322 + skb->nf_bridge->mask |= BRNF_PKT_TYPE;
324 + skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
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;
331 + skb->dst->output(skb);
335 +static int br_nf_pre_routing_finish(struct sk_buff *skb)
337 + struct net_device *dev = skb->dev;
338 + struct iphdr *iph = skb->nh.iph;
339 + struct nf_bridge_info *nf_bridge = skb->nf_bridge;
341 +#ifdef CONFIG_NETFILTER_DEBUG
342 + skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING);
345 + if (nf_bridge->mask & BRNF_PKT_TYPE) {
346 + skb->pkt_type = PACKET_OTHERHOST;
347 + nf_bridge->mask ^= BRNF_PKT_TYPE;
349 + nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
351 + if (dnat_took_place(skb)) {
352 + if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
355 + struct flowi fl = { .nl_u =
356 + { .ip4_u = { .daddr = iph->daddr, .saddr = 0 ,
357 + .tos = iph->tos} }, .proto = 0};
359 + if (!ip_route_output_key(&rt, &fl)) {
360 + /* Bridged-and-DNAT'ed traffic doesn't
361 + * require ip_forwarding.
363 + if (((struct dst_entry *)rt)->dev == dev) {
364 + skb->dst = (struct dst_entry *)rt;
367 + __br_dnat_complain();
368 + dst_release((struct dst_entry *)rt);
373 + if (skb->dst->dev == dev) {
375 + /* Tell br_nf_local_out this is a
378 + nf_bridge->mask |= BRNF_BRIDGED_DNAT;
379 + skb->dev = nf_bridge->physindev;
381 + if (skb->protocol ==
382 + __constant_htons(ETH_P_8021Q)) {
383 + skb_push(skb, VLAN_HLEN);
384 + skb->nh.raw -= VLAN_HLEN;
386 + NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
387 + skb, skb->dev, NULL,
388 + br_nf_pre_routing_finish_bridge,
392 + memcpy(skb->mac.ethernet->h_dest, dev->dev_addr,
394 + skb->pkt_type = PACKET_HOST;
397 + skb->dst = (struct dst_entry *)&__fake_rtable;
398 + dst_hold(skb->dst);
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;
407 + NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
408 + br_handle_frame_finish, 1);
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.
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 *))
425 + struct sk_buff *skb = *pskb;
426 + struct nf_bridge_info *nf_bridge;
428 + if (skb->protocol != __constant_htons(ETH_P_IP)) {
429 + struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)
430 + ((*pskb)->mac.ethernet);
434 + if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
436 + skb_pull(*pskb, VLAN_HLEN);
437 + (*pskb)->nh.raw += VLAN_HLEN;
438 + } else if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
441 + if (!pskb_may_pull(skb, sizeof(struct iphdr)))
445 + if (iph->ihl < 5 || iph->version != 4)
448 + if (!pskb_may_pull(skb, 4*iph->ihl))
452 + if (ip_fast_csum((__u8 *)iph, iph->ihl) != 0)
455 + len = ntohs(iph->tot_len);
456 + if (skb->len < len || len < 4*iph->ihl)
459 + if (skb->len > len) {
460 + __pskb_trim(skb, len);
461 + if (skb->ip_summed == CHECKSUM_HW)
462 + skb->ip_summed = CHECKSUM_NONE;
465 +#ifdef CONFIG_NETFILTER_DEBUG
466 + skb->nf_debug ^= (1 << NF_IP_PRE_ROUTING);
468 + if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
471 + if (skb->pkt_type == PACKET_OTHERHOST) {
472 + skb->pkt_type = PACKET_HOST;
473 + nf_bridge->mask |= BRNF_PKT_TYPE;
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);
481 + NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
482 + br_nf_pre_routing_finish);
487 +// IP_INC_STATS_BH(IpInHdrErrors);
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.
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 *))
505 + struct sk_buff *skb = *pskb;
507 + if (skb->dst == (struct dst_entry *)&__fake_rtable) {
508 + dst_release(skb->dst);
515 +/* PF_BRIDGE/FORWARD *************************************************/
516 +static int br_nf_forward_finish(struct sk_buff *skb)
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);
522 +#ifdef CONFIG_NETFILTER_DEBUG
523 + skb->nf_debug ^= (1 << NF_BR_FORWARD);
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;
533 + in = *((struct net_device **)(skb->cb));
535 + if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
536 + skb_push(skb, VLAN_HLEN);
537 + skb->nh.raw -= VLAN_HLEN;
539 + NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
540 + skb->dev, br_forward_finish, 1);
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
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 *))
554 + struct sk_buff *skb = *pskb;
555 + struct nf_bridge_info *nf_bridge;
556 + struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
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)
562 + skb_pull(*pskb, VLAN_HLEN);
563 + (*pskb)->nh.raw += VLAN_HLEN;
566 +#ifdef CONFIG_NETFILTER_DEBUG
567 + skb->nf_debug ^= (1 << NF_BR_FORWARD);
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;
576 + /* The physdev module checks on this */
577 + nf_bridge->mask |= BRNF_BRIDGED;
578 + nf_bridge->physoutdev = skb->dev;
580 + NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(in),
581 + bridge_parent(out), br_nf_forward_finish);
583 + struct net_device **d = (struct net_device **)(skb->cb);
584 + struct arphdr *arp = skb->nh.arph;
586 + if (arp->ar_pln != 4) {
588 + skb_push(*pskb, VLAN_HLEN);
589 + (*pskb)->nh.raw -= VLAN_HLEN;
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);
602 +/* PF_BRIDGE/LOCAL_OUT ***********************************************/
603 +static int br_nf_local_out_finish(struct sk_buff *skb)
605 +#ifdef CONFIG_NETFILTER_DEBUG
606 + skb->nf_debug &= ~(1 << NF_BR_LOCAL_OUT);
608 + if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
609 + skb_push(skb, VLAN_HLEN);
610 + skb->nh.raw -= VLAN_HLEN;
613 + NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
614 + br_forward_finish, NF_BR_PRI_FIRST + 1);
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.
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.
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 *))
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);
652 + if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
655 + /* Sometimes we get packets with NULL ->dst here (for example,
656 + * running a dhcp client daemon triggers this).
658 + if (skb->dst == NULL)
661 + nf_bridge = skb->nf_bridge;
662 + nf_bridge->physoutdev = skb->dev;
664 + realindev = nf_bridge->physindev;
666 + /* Bridged, take PF_BRIDGE/FORWARD.
667 + * (see big note in front of br_nf_pre_routing_finish)
669 + if (nf_bridge->mask & BRNF_BRIDGED_DNAT) {
670 + okfn = br_forward_finish;
672 + if (nf_bridge->mask & BRNF_PKT_TYPE) {
673 + skb->pkt_type = PACKET_OTHERHOST;
674 + nf_bridge->mask ^= BRNF_PKT_TYPE;
676 + if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
677 + skb_push(skb, VLAN_HLEN);
678 + skb->nh.raw -= VLAN_HLEN;
681 + NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev,
684 + struct net_device *realoutdev = bridge_parent(skb->dev);
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;
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;
696 + /* IP forwarded traffic has a physindev, locally
697 + * generated traffic hasn't.
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,
705 + NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD + 1);
707 +#ifdef CONFIG_NETFILTER_DEBUG
708 + skb->nf_debug ^= (1 << NF_IP_LOCAL_OUT);
711 + NF_HOOK_THRESH(PF_INET, NF_IP_LOCAL_OUT, skb, realindev,
713 + NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT + 1);
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 *))
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);
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);
740 + printk(" head:%p, raw:%p\n", skb->head, skb->mac.raw);
744 + if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
747 + /* Sometimes we get packets with NULL ->dst here (for example,
748 + * running a dhcp client daemon triggers this).
750 + if (skb->dst == NULL)
753 +#ifdef CONFIG_NETFILTER_DEBUG
754 + skb->nf_debug ^= (1 << NF_IP_POST_ROUTING);
757 + /* We assume any code from br_dev_queue_push_xmit onwards doesn't care
758 + * about the value of skb->pkt_type.
760 + if (skb->pkt_type == PACKET_OTHERHOST) {
761 + skb->pkt_type = PACKET_HOST;
762 + nf_bridge->mask |= BRNF_PKT_TYPE;
765 + if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
766 + skb_pull(skb, VLAN_HLEN);
767 + skb->nh.raw += VLAN_HLEN;
770 + nf_bridge_save_header(skb);
772 +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
773 + if (nf_bridge->netoutdev)
774 + realoutdev = nf_bridge->netoutdev;
776 + NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
777 + realoutdev, br_dev_queue_push_xmit);
783 +/* IPv4/SABOTAGE *****************************************************/
785 +/* Don't hand locally destined packets to PF_INET/PRE_ROUTING
786 + * for the second time.
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 *))
792 + if ((*pskb)->nf_bridge &&
793 + !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
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.
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 *))
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)
818 + struct sk_buff *skb = *pskb;
819 + struct nf_bridge_info *nf_bridge;
821 + if (!skb->nf_bridge && !nf_bridge_alloc(skb))
824 + nf_bridge = skb->nf_bridge;
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.
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;
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;
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.
853 +static struct nf_hook_ops br_nf_ops[] = {
854 + { .hook = br_nf_pre_routing,
855 + .owner = THIS_MODULE,
857 + .hooknum = NF_BR_PRE_ROUTING,
858 + .priority = NF_BR_PRI_BRNF, },
859 + { .hook = br_nf_local_in,
860 + .owner = THIS_MODULE,
862 + .hooknum = NF_BR_LOCAL_IN,
863 + .priority = NF_BR_PRI_BRNF, },
864 + { .hook = br_nf_forward,
865 + .owner = THIS_MODULE,
867 + .hooknum = NF_BR_FORWARD,
868 + .priority = NF_BR_PRI_BRNF, },
869 + { .hook = br_nf_local_out,
870 + .owner = THIS_MODULE,
872 + .hooknum = NF_BR_LOCAL_OUT,
873 + .priority = NF_BR_PRI_FIRST, },
874 + { .hook = br_nf_post_routing,
875 + .owner = THIS_MODULE,
877 + .hooknum = NF_BR_POST_ROUTING,
878 + .priority = NF_BR_PRI_LAST, },
879 + { .hook = ipv4_sabotage_in,
880 + .owner = THIS_MODULE,
882 + .hooknum = NF_IP_PRE_ROUTING,
883 + .priority = NF_IP_PRI_FIRST, },
884 + { .hook = ipv4_sabotage_out,
885 + .owner = THIS_MODULE,
887 + .hooknum = NF_IP_FORWARD,
888 + .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD, },
889 + { .hook = ipv4_sabotage_out,
890 + .owner = THIS_MODULE,
892 + .hooknum = NF_IP_LOCAL_OUT,
893 + .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
894 + { .hook = ipv4_sabotage_out,
895 + .owner = THIS_MODULE,
897 + .hooknum = NF_IP_POST_ROUTING,
898 + .priority = NF_IP_PRI_FIRST, },
901 +int br_netfilter_init(void)
905 + for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) {
908 + if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0)
912 + nf_unregister_hook(&br_nf_ops[i]);
917 + printk(KERN_NOTICE "Bridge firewalling registered\n");
922 +void br_netfilter_fini(void)
926 + for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--)
927 + nf_unregister_hook(&br_nf_ops[i]);
929 diff -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
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.
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>
944 EXPORT_SYMBOL(skb_ip_make_writable);
945 #endif /*CONFIG_INET*/
947 +/* Internal logging interface, which relies on the real
948 + LOG target modules */
950 +#define NF_LOG_PREFIXLEN 128
952 +static nf_logfn *nf_logging[NPROTO]; /* = NULL */
953 +static int reported = 0;
954 +static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
956 +int nf_log_register(int pf, nf_logfn *logfn)
960 + /* Any setup of logging members must be done before
961 + * substituting pointer. */
963 + spin_lock(&nf_log_lock);
964 + if (!nf_logging[pf]) {
965 + nf_logging[pf] = logfn;
968 + spin_unlock(&nf_log_lock);
972 +void nf_log_unregister(int pf, nf_logfn *logfn)
974 + spin_lock(&nf_log_lock);
975 + if (nf_logging[pf] == logfn)
976 + nf_logging[pf] = NULL;
977 + spin_unlock(&nf_log_lock);
979 + /* Give time to concurrent readers. */
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, ...)
991 + char prefix[NF_LOG_PREFIXLEN];
995 + logfn = nf_logging[pf];
997 + va_start(args, fmt);
998 + vsnprintf(prefix, sizeof(prefix), fmt, 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");
1008 + rcu_read_unlock();
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
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);
1024 diff -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
1028 +/* netfilter.c: look after the filters for various protocols.
1029 + * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
1031 + * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
1034 + * Rusty Russell (C)2000 -- This code is GPL.
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.
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>
1059 +#define __KERNEL_SYSCALLS__
1060 +#include <linux/unistd.h>
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)
1070 +#define NFDEBUG(format, args...)
1073 +/* Sockopts only registered and called from user context, so
1074 + net locking would be overkill. Also, [gs]etsockopt calls may
1076 +static DECLARE_MUTEX(nf_sockopt_mutex);
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;
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.
1087 +static struct nf_queue_handler_t {
1088 + nf_queue_outfn_t outfn;
1090 +} queue_handler[NPROTO];
1091 +static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
1093 +int nf_register_hook(struct nf_hook_ops *reg)
1095 + struct list_head *i;
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)
1102 + list_add_rcu(®->list, i->prev);
1103 + spin_unlock_bh(&nf_hook_lock);
1105 + synchronize_net();
1109 +void nf_unregister_hook(struct nf_hook_ops *reg)
1111 + spin_lock_bh(&nf_hook_lock);
1112 + list_del_rcu(®->list);
1113 + spin_unlock_bh(&nf_hook_lock);
1115 + synchronize_net();
1118 +/* Do exclusive ranges overlap? */
1119 +static inline int overlap(int min1, int max1, int min2, int max2)
1121 + return max1 > min2 && min1 < max2;
1124 +/* Functions to register sockopt ranges (exclusive). */
1125 +int nf_register_sockopt(struct nf_sockopt_ops *reg)
1127 + struct list_head *i;
1130 + if (down_interruptible(&nf_sockopt_mutex) != 0)
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);
1150 + list_add(®->list, &nf_sockopts);
1152 + up(&nf_sockopt_mutex);
1156 +void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
1158 + /* No point being interruptible: we're probably in cleanup_module() */
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);
1170 + list_del(®->list);
1171 + up(&nf_sockopt_mutex);
1174 +#ifdef CONFIG_NETFILTER_DEBUG
1175 +#include <net/ip.h>
1176 +#include <net/tcp.h>
1177 +#include <linux/netfilter_ipv4.h>
1179 +static void debug_print_hooks_ip(unsigned int nf_debug)
1181 + if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
1182 + printk("PRE_ROUTING ");
1183 + nf_debug ^= (1 << NF_IP_PRE_ROUTING);
1185 + if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
1186 + printk("LOCAL_IN ");
1187 + nf_debug ^= (1 << NF_IP_LOCAL_IN);
1189 + if (nf_debug & (1 << NF_IP_FORWARD)) {
1190 + printk("FORWARD ");
1191 + nf_debug ^= (1 << NF_IP_FORWARD);
1193 + if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
1194 + printk("LOCAL_OUT ");
1195 + nf_debug ^= (1 << NF_IP_LOCAL_OUT);
1197 + if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
1198 + printk("POST_ROUTING ");
1199 + nf_debug ^= (1 << NF_IP_POST_ROUTING);
1202 + printk("Crap bits: 0x%04X", nf_debug);
1206 +void nf_dump_skb(int pf, struct sk_buff *skb)
1208 + printk("skb: pf=%i %s dev=%s len=%u\n",
1210 + skb->sk ? "(owned)" : "(unowned)",
1211 + skb->dev ? skb->dev->name : "(no dev)",
1215 + const struct iphdr *ip = skb->nh.iph;
1216 + __u32 *opt = (__u32 *) (ip + 1);
1218 + __u16 src_port = 0, dst_port = 0;
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);
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),
1232 + ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
1233 + ntohs(ip->frag_off), ip->ttl);
1235 + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
1236 + printk(" O=0x%8.8X", *opt++);
1242 +void nf_debug_ip_local_deliver(struct sk_buff *skb)
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. */
1249 + printk("ip_local_deliver: skb->dev is NULL.\n");
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);
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);
1271 +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb)
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: ",
1277 + debug_print_hooks_ip(newskb->nf_debug);
1278 + nf_dump_skb(PF_INET, newskb);
1280 + /* Clear to avoid confusing input check */
1281 + newskb->nf_debug = 0;
1284 +void nf_debug_ip_finish_output2(struct sk_buff *skb)
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.
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);
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);
1315 +#endif /*CONFIG_NETFILTER_DEBUG*/
1317 +/* Call get/setsockopt() */
1318 +static int nf_sockopt(struct sock *sk, int pf, int val,
1319 + char *opt, int *len, int get)
1321 + struct list_head *i;
1322 + struct nf_sockopt_ops *ops;
1325 + if (down_interruptible(&nf_sockopt_mutex) != 0)
1328 + list_for_each(i, &nf_sockopts) {
1329 + ops = (struct nf_sockopt_ops *)i;
1330 + if (ops->pf == pf) {
1332 + if (val >= ops->get_optmin
1333 + && val < ops->get_optmax) {
1335 + up(&nf_sockopt_mutex);
1336 + ret = ops->get(sk, val, opt, len);
1340 + if (val >= ops->set_optmin
1341 + && val < ops->set_optmax) {
1343 + up(&nf_sockopt_mutex);
1344 + ret = ops->set(sk, val, opt, *len);
1350 + up(&nf_sockopt_mutex);
1351 + return -ENOPROTOOPT;
1354 + down(&nf_sockopt_mutex);
1356 + if (ops->cleanup_task)
1357 + wake_up_process(ops->cleanup_task);
1358 + up(&nf_sockopt_mutex);
1362 +int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
1365 + return nf_sockopt(sk, pf, val, opt, &len, 0);
1368 +int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
1370 + return nf_sockopt(sk, pf, val, opt, len, 1);
1373 +static unsigned int nf_iterate(struct list_head *head,
1374 + struct sk_buff **skb,
1376 + const struct net_device *indev,
1377 + const struct net_device *outdev,
1378 + struct list_head **i,
1379 + int (*okfn)(struct sk_buff *),
1383 + * The caller must not block between calls to this
1384 + * function because of risk of continuing from deleted element.
1386 + list_for_each_continue_rcu(*i, head) {
1387 + struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
1389 + if (hook_thresh > elem->priority)
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)) {
1408 +#ifdef CONFIG_NETFILTER_DEBUG
1413 + NFDEBUG("Evil return from %p(%u).\n",
1414 + elem->hook, hook);
1421 +int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
1425 + write_lock_bh(&queue_handler_lock);
1426 + if (queue_handler[pf].outfn)
1429 + queue_handler[pf].outfn = outfn;
1430 + queue_handler[pf].data = data;
1433 + write_unlock_bh(&queue_handler_lock);
1438 +/* The caller must flush their queue before this */
1439 +int nf_unregister_queue_handler(int pf)
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);
1450 + * Any packet that leaves via this function must come back
1451 + * through nf_reinject().
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 *))
1461 + struct nf_info *info;
1462 +#ifdef CONFIG_BRIDGE_NETFILTER
1463 + struct net_device *physindev = NULL;
1464 + struct net_device *physoutdev = NULL;
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);
1475 + info = kmalloc(sizeof(*info), GFP_ATOMIC);
1477 + if (net_ratelimit())
1478 + printk(KERN_ERR "OOM queueing packet %p\n",
1480 + read_unlock(&queue_handler_lock);
1485 + *info = (struct nf_info) {
1486 + (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
1488 + /* If it's going away, ignore hook. */
1489 + if (!try_module_get(info->elem->owner)) {
1490 + read_unlock(&queue_handler_lock);
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);
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);
1508 + status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
1509 + read_unlock(&queue_handler_lock);
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);
1519 + module_put(info->elem->owner);
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 *),
1533 + struct list_head *elem;
1534 + unsigned int verdict;
1537 + if (skb->ip_summed == CHECKSUM_HW) {
1538 + if (outdev == NULL) {
1539 + skb->ip_summed = CHECKSUM_NONE;
1541 + skb_checksum_help(skb);
1545 + /* We may already have this, but read-locks nest anyway */
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);
1553 + skb->nf_debug |= (1 << hook);
1556 + elem = &nf_hooks[pf][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))
1566 + switch (verdict) {
1577 + rcu_read_unlock();
1581 +void nf_reinject(struct sk_buff *skb, struct nf_info *info,
1582 + unsigned int verdict)
1584 + struct list_head *elem = &info->elem->list;
1585 + struct list_head *i;
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);
1601 + /* Drop reference to owner of hook which queued us. */
1602 + module_put(info->elem->owner);
1604 + list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
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",
1613 + verdict = NF_DROP;
1616 + /* Continue traversal iff userspace said ok... */
1617 + if (verdict == NF_REPEAT) {
1618 + elem = elem->prev;
1619 + verdict = NF_ACCEPT;
1622 + if (verdict == NF_ACCEPT) {
1624 + verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
1626 + info->indev, info->outdev, &elem,
1627 + info->okfn, INT_MIN);
1630 + switch (verdict) {
1636 + if (!nf_queue(skb, elem, info->pf, info->hook,
1637 + info->indev, info->outdev, info->okfn))
1641 + rcu_read_unlock();
1643 + if (verdict == NF_DROP)
1651 +/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
1652 +int ip_route_me_harder(struct sk_buff **pskb)
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;
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.
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;
1671 + if (ip_route_output_key(&rt, &fl) != 0)
1674 + /* Drop old route. */
1675 + dst_release((*pskb)->dst);
1676 + (*pskb)->dst = &rt->u.dst;
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)
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);
1690 + dst_release(&rt->u.dst);
1691 + dst_release(odst);
1694 + if ((*pskb)->dst->error)
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;
1702 + nskb = skb_realloc_headroom(*pskb, hh_len);
1706 + skb_set_owner_w(nskb, (*pskb)->sk);
1714 +int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
1716 + struct sk_buff *nskb;
1717 + unsigned int iplen;
1719 + if (writable_len > (*pskb)->len)
1722 + /* Not exclusive use of packet? Must copy. */
1723 + if (skb_shared(*pskb) || skb_cloned(*pskb))
1726 + /* Alexey says IP hdr is always modifiable and linear, so ok. */
1727 + if (writable_len <= (*pskb)->nh.iph->ihl*4)
1730 + iplen = writable_len - (*pskb)->nh.iph->ihl*4;
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)
1739 + if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
1744 + if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
1747 + case IPPROTO_ICMP:
1749 + <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
1752 + /* Insert other cases here as desired */
1756 + nskb = skb_copy(*pskb, GFP_ATOMIC);
1759 + BUG_ON(skb_is_nonlinear(nskb));
1761 + /* Rest of kernel will get very unhappy if we pass it a
1762 + suddenly-orphaned skbuff */
1764 + skb_set_owner_w(nskb, (*pskb)->sk);
1770 + return pskb_may_pull(*pskb, writable_len);
1772 +EXPORT_SYMBOL(skb_ip_make_writable);
1773 +#endif /*CONFIG_INET*/
1775 +/* Internal logging interface, which relies on the real
1776 + LOG target modules */
1778 +#define NF_LOG_PREFIXLEN 128
1780 +static nf_logfn *nf_logging[NPROTO]; /* = NULL */
1781 +static int reported = 0;
1782 +static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
1784 +int nf_log_register(int pf, nf_logfn *logfn)
1788 + /* Any setup of logging members must be done before
1789 + * substituting pointer. */
1791 + spin_lock(&nf_log_lock);
1792 + if (!nf_logging[pf]) {
1793 + nf_logging[pf] = logfn;
1796 + spin_unlock(&nf_log_lock);
1800 +void nf_log_unregister(int pf, nf_logfn *logfn)
1802 + spin_lock(&nf_log_lock);
1803 + if (nf_logging[pf] == logfn)
1804 + nf_logging[pf] = NULL;
1805 + spin_unlock(&nf_log_lock);
1807 + /* Give time to concurrent readers. */
1808 + synchronize_net();
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, ...)
1819 + char prefix[NF_LOG_PREFIXLEN];
1823 + logfn = nf_logging[pf];
1825 + va_start(args, fmt);
1826 + vsnprintf(prefix, sizeof(prefix), fmt, 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");
1836 + rcu_read_unlock();
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
1843 +void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
1845 +void __init netfilter_init(void)
1849 + for (i = 0; i < NPROTO; i++) {
1850 + for (h = 0; h < NF_MAX_HOOKS; h++)
1851 + INIT_LIST_HEAD(&nf_hooks[i][h]);
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);
1868 diff -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 @@
1873 To compile it as a module, choose M here. If unsure, say N.
1875 +config IP_NF_MATCH_SCTP
1876 + tristate "SCTP match support"
1877 + depends on IP_NF_IPTABLES
1879 + This match allows iptables to match on the SCTP header.
1881 + If you want to compile it as a module, say M here and read
1882 + <file:Documentation/modules.txt>. If unsure, say `N'.
1884 config IP_NF_MATCH_LENGTH
1885 tristate "LENGTH match support"
1886 depends on IP_NF_IPTABLES
1887 @@ -527,6 +536,42 @@
1889 To compile it as a module, choose M here. If unsure, say N.
1892 + tristate "Raw table"
1893 + depends on IP_NF_IPTABLES
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.
1900 + To compile it as a module, choose M here. If unsure, say N.
1902 +config IP_NF_TARGET_TRACE
1903 + tristate "TRACE target support"
1904 + depends on IP_NF_RAW
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
1910 + TRACE: tablename/chainname/rulenum
1912 + if the ipt_LOG or ipt_ULOG targets are loaded in.
1914 + To compile it as a module, choose M here. If unsure, say N.
1916 +config IP_NF_TARGET_NOTRACK
1917 + tristate "NOTRACK target support"
1918 + depends on IP_NF_RAW
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).
1925 + To compile it as a module, choose M here. If unsure, say N.
1927 config IP_NF_ARPTABLES
1928 tristate "ARP tables support"
1930 diff -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
1935 +# IP netfilter configuration
1938 +menu "IP: Netfilter Configuration"
1939 + depends on INET && NETFILTER
1941 +config IP_NF_CONNTRACK
1942 + tristate "Connection tracking (required for masq/NAT)"
1944 + Connection tracking keeps a record of what packets have passed
1945 + through your machine, in order to figure out how they are related
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'
1953 + To compile it as a module, choose M here. If unsure, say N.
1956 + tristate "FTP protocol support"
1957 + depends on IP_NF_CONNTRACK
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.
1963 + To compile it as a module, choose M here. If unsure, say Y.
1966 + tristate "IRC protocol support"
1967 + depends on IP_NF_CONNTRACK
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.
1978 + To compile it as a module, choose M here. If unsure, say Y.
1981 + tristate "TFTP protocol support"
1982 + depends on IP_NF_CONNTRACK
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.
1989 + To compile it as a module, choose M here. If unsure, say Y.
1991 +config IP_NF_AMANDA
1992 + tristate "Amanda backup protocol support"
1993 + depends on IP_NF_CONNTRACK
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
2002 + To compile it as a module, choose M here. If unsure, say Y.
2005 + tristate "Userspace queueing via NETLINK"
2007 + Netfilter has the ability to queue packets to user space: the
2008 + netlink device can be used to access them using this driver.
2010 + To compile it as a module, choose M here. If unsure, say N.
2012 +config IP_NF_IPTABLES
2013 + tristate "IP tables support (required for filtering/masq/NAT)"
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
2020 + To compile it as a module, choose M here. If unsure, say N.
2022 +# The simple matches.
2023 +config IP_NF_MATCH_LIMIT
2024 + tristate "limit match support"
2025 + depends on IP_NF_IPTABLES
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.
2031 + To compile it as a module, choose M here. If unsure, say N.
2033 +config IP_NF_MATCH_IPRANGE
2034 + tristate "IP range match support"
2035 + depends on IP_NF_IPTABLES
2037 + This option makes possible to match IP addresses against IP address
2040 + To compile it as a module, choose M here. If unsure, say N.
2042 +config IP_NF_MATCH_MAC
2043 + tristate "MAC address match support"
2044 + depends on IP_NF_IPTABLES
2046 + MAC matching allows you to match packets based on the source
2047 + Ethernet address of the packet.
2049 + To compile it as a module, choose M here. If unsure, say N.
2051 +config IP_NF_MATCH_PKTTYPE
2052 + tristate "Packet type match support"
2053 + depends on IP_NF_IPTABLES
2055 + Packet type matching allows you to match a packet by
2056 + its "class", eg. BROADCAST, MULTICAST, ...
2059 + iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
2061 + To compile it as a module, choose M here. If unsure, say N.
2063 +config IP_NF_MATCH_MARK
2064 + tristate "netfilter MARK match support"
2065 + depends on IP_NF_IPTABLES
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
2071 + To compile it as a module, choose M here. If unsure, say N.
2073 +config IP_NF_MATCH_MULTIPORT
2074 + tristate "Multiple port match support"
2075 + depends on IP_NF_IPTABLES
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.
2081 + To compile it as a module, choose M here. If unsure, say N.
2083 +config IP_NF_MATCH_TOS
2084 + tristate "TOS match support"
2085 + depends on IP_NF_IPTABLES
2087 + TOS matching allows you to match packets based on the Type Of
2088 + Service fields of the IP packet.
2090 + To compile it as a module, choose M here. If unsure, say N.
2092 +config IP_NF_MATCH_RECENT
2093 + tristate "recent match support"
2094 + depends on IP_NF_IPTABLES
2096 + This match is used for creating one or many lists of recently
2097 + used addresses and then matching against that/those list(s).
2099 + Short options are available by using 'iptables -m recent -h'
2100 + Official Website: <http://snowman.net/projects/ipt_recent/>
2102 + To compile it as a module, choose M here. If unsure, say N.
2104 +config IP_NF_MATCH_ECN
2105 + tristate "ECN match support"
2106 + depends on IP_NF_IPTABLES
2108 + This option adds a `ECN' match, which allows you to match against
2109 + the IPv4 and TCP header ECN fields.
2111 + To compile it as a module, choose M here. If unsure, say N.
2113 +config IP_NF_MATCH_DSCP
2114 + tristate "DSCP match support"
2115 + depends on IP_NF_IPTABLES
2117 + This option adds a `DSCP' match, which allows you to match against
2118 + the IPv4 header DSCP field (DSCP codepoint).
2120 + The DSCP codepoint can have any value between 0x0 and 0x4f.
2122 + To compile it as a module, choose M here. If unsure, say N.
2124 +config IP_NF_MATCH_AH_ESP
2125 + tristate "AH/ESP match support"
2126 + depends on IP_NF_IPTABLES
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.
2131 + To compile it as a module, choose M here. If unsure, say N.
2133 +config IP_NF_MATCH_LENGTH
2134 + tristate "LENGTH match support"
2135 + depends on IP_NF_IPTABLES
2137 + This option allows you to match the length of a packet against a
2138 + specific value or range of values.
2140 + To compile it as a module, choose M here. If unsure, say N.
2142 +config IP_NF_MATCH_TTL
2143 + tristate "TTL match support"
2144 + depends on IP_NF_IPTABLES
2146 + This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
2147 + to match packets by their TTL value.
2149 + To compile it as a module, choose M here. If unsure, say N.
2151 +config IP_NF_MATCH_TCPMSS
2152 + tristate "tcpmss match support"
2153 + depends on IP_NF_IPTABLES
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.
2159 + To compile it as a module, choose M here. If unsure, say N.
2161 +config IP_NF_MATCH_HELPER
2162 + tristate "Helper match support"
2163 + depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
2165 + Helper matching allows you to match packets in dynamic connections
2166 + tracked by a conntrack-helper, ie. ip_conntrack_ftp
2168 + To compile it as a module, choose M here. If unsure, say Y.
2170 +config IP_NF_MATCH_STATE
2171 + tristate "Connection state match support"
2172 + depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
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.
2178 + To compile it as a module, choose M here. If unsure, say N.
2180 +config IP_NF_MATCH_CONNTRACK
2181 + tristate "Connection tracking match support"
2182 + depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
2184 + This is a general conntrack match module, a superset of the state match.
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.
2190 + To compile it as a module, choose M here. If unsure, say N.
2192 +config IP_NF_MATCH_OWNER
2193 + tristate "Owner match support"
2194 + depends on IP_NF_IPTABLES
2196 + Packet owner matching allows you to match locally-generated packets
2197 + based on who created them: the user, group, process or session.
2199 + To compile it as a module, choose M here. If unsure, say N.
2201 +config IP_NF_MATCH_PHYSDEV
2202 + tristate "Physdev match support"
2203 + depends on IP_NF_IPTABLES && BRIDGE_NETFILTER
2205 + Physdev packet matching matches against the physical bridge ports
2206 + the IP packet arrived on or will leave by.
2208 + To compile it as a module, choose M here. If unsure, say N.
2211 +config IP_NF_FILTER
2212 + tristate "Packet filtering"
2213 + depends on IP_NF_IPTABLES
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).
2219 + To compile it as a module, choose M here. If unsure, say N.
2221 +config IP_NF_TARGET_REJECT
2222 + tristate "REJECT target support"
2223 + depends on IP_NF_FILTER
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.
2229 + To compile it as a module, choose M here. If unsure, say N.
2232 + tristate "Full NAT"
2233 + depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
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).
2239 + To compile it as a module, choose M here. If unsure, say N.
2241 +config IP_NF_NAT_NEEDED
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
2246 +config IP_NF_TARGET_MASQUERADE
2247 + tristate "MASQUERADE target support"
2248 + depends on IP_NF_NAT
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).
2256 + To compile it as a module, choose M here. If unsure, say N.
2258 +config IP_NF_TARGET_REDIRECT
2259 + tristate "REDIRECT target support"
2260 + depends on IP_NF_NAT
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.
2267 + To compile it as a module, choose M here. If unsure, say N.
2269 +config IP_NF_TARGET_NETMAP
2270 + tristate "NETMAP target support"
2271 + depends on IP_NF_NAT
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.
2278 + To compile it as a module, choose M here. If unsure, say N.
2280 +config IP_NF_TARGET_SAME
2281 + tristate "SAME target support"
2282 + depends on IP_NF_NAT
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.
2287 + To compile it as a module, choose M here. If unsure, say N.
2289 +config IP_NF_NAT_LOCAL
2290 + bool "NAT of local connections (READ HELP)"
2291 + depends on IP_NF_NAT
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.
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.
2301 + If unsure, say 'N'.
2303 +config IP_NF_NAT_SNMP_BASIC
2304 + tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
2305 + depends on EXPERIMENTAL && IP_NF_NAT
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.
2314 + This is the "basic" form of SNMP-ALG, as described in RFC 2962
2316 + To compile it as a module, choose M here. If unsure, say N.
2318 +config IP_NF_NAT_IRC
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
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
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
2332 +config IP_NF_NAT_TFTP
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
2338 +config IP_NF_NAT_AMANDA
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
2344 +config IP_NF_MANGLE
2345 + tristate "Packet mangling"
2346 + depends on IP_NF_IPTABLES
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.
2352 + To compile it as a module, choose M here. If unsure, say N.
2354 +config IP_NF_TARGET_TOS
2355 + tristate "TOS target support"
2356 + depends on IP_NF_MANGLE
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.
2362 + To compile it as a module, choose M here. If unsure, say N.
2364 +config IP_NF_TARGET_ECN
2365 + tristate "ECN target support"
2366 + depends on IP_NF_MANGLE
2368 + This option adds a `ECN' target, which can be used in the iptables mangle
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.
2376 + To compile it as a module, choose M here. If unsure, say N.
2378 +config IP_NF_TARGET_DSCP
2379 + tristate "DSCP target support"
2380 + depends on IP_NF_MANGLE
2382 + This option adds a `DSCP' match, which allows you to match against
2383 + the IPv4 header DSCP field (DSCP codepoint).
2385 + The DSCP codepoint can have any value between 0x0 and 0x4f.
2387 + To compile it as a module, choose M here. If unsure, say N.
2389 +config IP_NF_TARGET_MARK
2390 + tristate "MARK target support"
2391 + depends on IP_NF_MANGLE
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
2400 + To compile it as a module, choose M here. If unsure, say N.
2402 +config IP_NF_TARGET_CLASSIFY
2403 + tristate "CLASSIFY target support"
2404 + depends on IP_NF_MANGLE
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:
2410 + atm, cbq, dsmark, pfifo_fast, htb, prio
2412 + To compile it as a module, choose M here. If unsure, say N.
2414 +config IP_NF_TARGET_LOG
2415 + tristate "LOG target support"
2416 + depends on IP_NF_IPTABLES
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.
2421 + To compile it as a module, choose M here. If unsure, say N.
2423 +config IP_NF_TARGET_ULOG
2424 + tristate "ULOG target support"
2425 + depends on IP_NF_IPTABLES
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.
2432 + The apropriate userspace logging daemon (ulogd) may be obtained from
2433 + http://www.gnumonks.org/projects/ulogd
2435 + To compile it as a module, choose M here. If unsure, say N.
2437 +config IP_NF_TARGET_TCPMSS
2438 + tristate "TCPMSS target support"
2439 + depends on IP_NF_IPTABLES
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
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
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.
2455 + Workaround: activate this option and add a rule to your firewall
2456 + configuration like:
2458 + iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
2459 + -j TCPMSS --clamp-mss-to-pmtu
2461 + To compile it as a module, choose M here. If unsure, say N.
2464 + tristate "Raw table"
2465 + depends on IP_NF_IPTABLES
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.
2472 + To compile it as a module, choose M here. If unsure, say N.
2474 +config IP_NF_TARGET_TRACE
2475 + tristate "TRACE target support"
2476 + depends on IP_NF_RAW
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
2482 + TRACE: tablename/chainname/rulenum
2484 + if the ipt_LOG or ipt_ULOG targets are loaded in.
2486 + To compile it as a module, choose M here. If unsure, say N.
2488 +config IP_NF_TARGET_NOTRACK
2489 + tristate "NOTRACK target support"
2490 + depends on IP_NF_RAW
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).
2497 + To compile it as a module, choose M here. If unsure, say N.
2499 +config IP_NF_ARPTABLES
2500 + tristate "ARP tables support"
2502 +config IP_NF_ARPFILTER
2503 + tristate "ARP packet filtering"
2504 + depends on IP_NF_ARPTABLES
2506 +config IP_NF_ARP_MANGLE
2507 + tristate "ARP payload mangling"
2508 + depends on IP_NF_ARPTABLES
2510 + Allows altering the ARP packet payload: source and destination
2511 + hardware and network addresses.
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
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.
2524 + To compile it as a module, choose M here. If unsure, say N.
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
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.
2536 + To compile it as a module, choose M here. If unsure, say N.
2540 diff -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
2545 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
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
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
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
2566 # generic ARP tables
2567 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
2568 diff -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
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>
2579 /* This rwlock protects the main hash table, protocol/helper/expected
2580 registrations, conntrack timers*/
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;
2587 extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
2589 @@ -808,18 +808,10 @@
2593 - /* Previously seen (loopback)? Ignore. Do this before
2594 - fragment check. */
2595 + /* Previously seen (loopback or untracked)? Ignore. */
2599 - /* Gather fragments. */
2600 - if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
2601 - *pskb = ip_ct_gather_frags(*pskb);
2606 proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2608 /* It may be an icmp error... */
2611 } else if (related_to->helper->max_expected &&
2612 related_to->expecting >= related_to->helper->max_expected) {
2613 - struct list_head *cur_item;
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));
2620 /* choose the the oldest expectation to evict */
2621 - list_for_each(cur_item, &related_to->sibling_list) {
2622 - struct ip_conntrack_expect *cur;
2624 - cur = list_entry(cur_item,
2625 - struct ip_conntrack_expect,
2627 - if (cur->sibling == NULL) {
2629 + list_for_each_entry(old, &related_to->sibling_list,
2631 + if (old->sibling == NULL)
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);
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);
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 @@
2656 /* For use by ipt_REJECT */
2657 ip_ct_attach = ip_conntrack_attach;
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;
2670 diff -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
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
2678 +/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
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
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>
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)
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>
2718 +#define IP_CONNTRACK_VERSION "2.1"
2721 +#define DEBUGP printk
2723 +#define DEBUGP(format, args...)
2726 +DECLARE_RWLOCK(ip_conntrack_lock);
2727 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
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;
2739 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
2741 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
2742 + u_int8_t protocol)
2744 + return protocol == curr->proto;
2747 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
2749 + struct ip_conntrack_protocol *p;
2751 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2752 + p = LIST_FIND(&protocol_list, proto_cmpfn,
2753 + struct ip_conntrack_protocol *, protocol);
2755 + p = &ip_conntrack_generic_protocol;
2760 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
2762 + struct ip_conntrack_protocol *p;
2764 + READ_LOCK(&ip_conntrack_lock);
2765 + p = __ip_ct_find_proto(protocol);
2766 + READ_UNLOCK(&ip_conntrack_lock);
2771 +ip_conntrack_put(struct ip_conntrack *ct)
2774 + IP_NF_ASSERT(ct->infos[0].master);
2775 + /* nf_conntrack_put wants to go via an info struct, so feed it
2777 + nf_conntrack_put(&ct->infos[0]);
2780 +static int ip_conntrack_hash_rnd_initted;
2781 +static unsigned int ip_conntrack_hash_rnd;
2784 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
2787 + dump_tuple(tuple);
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);
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)
2802 + /* Never happen */
2803 + if (iph->frag_off & htons(IP_OFFSET)) {
2804 + printk("ip_conntrack_core: Frag of proto %u.\n",
2809 + tuple->src.ip = iph->saddr;
2810 + tuple->dst.ip = iph->daddr;
2811 + tuple->dst.protonum = iph->protocol;
2813 + return protocol->pkt_to_tuple(skb, dataoff, tuple);
2817 +invert_tuple(struct ip_conntrack_tuple *inverse,
2818 + const struct ip_conntrack_tuple *orig,
2819 + const struct ip_conntrack_protocol *protocol)
2821 + inverse->src.ip = orig->dst.ip;
2822 + inverse->dst.ip = orig->src.ip;
2823 + inverse->dst.protonum = orig->dst.protonum;
2825 + return protocol->invert_tuple(inverse, orig);
2829 +/* ip_conntrack_expect helper functions */
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)
2835 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2836 + return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
2840 +destroy_expect(struct ip_conntrack_expect *exp)
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));
2850 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
2852 + IP_NF_ASSERT(exp);
2854 + if (atomic_dec_and_test(&exp->use)) {
2855 + /* usage count dropped to zero */
2856 + destroy_expect(exp);
2860 +static inline struct ip_conntrack_expect *
2861 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
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);
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)
2873 + struct ip_conntrack_expect *exp;
2875 + READ_LOCK(&ip_conntrack_lock);
2876 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
2877 + exp = __ip_ct_expect_find(tuple);
2879 + atomic_inc(&exp->use);
2880 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2881 + READ_UNLOCK(&ip_conntrack_lock);
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)
2890 + DEBUGP("unexpect_related(%p)\n", expect);
2891 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2893 + /* we're not allowed to unexpect a confirmed expectation! */
2894 + IP_NF_ASSERT(!expect->sibling);
2896 + /* delete from global and local lists */
2897 + list_del(&expect->list);
2898 + list_del(&expect->expected_list);
2900 + /* decrement expect-count of master conntrack */
2901 + if (expect->expectant)
2902 + expect->expectant->expecting--;
2904 + ip_conntrack_expect_put(expect);
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)
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))
2921 + __unexpect_related(expect);
2924 +/* delete all unconfirmed expectations for this conntrack */
2925 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
2927 + struct list_head *exp_entry, *next;
2928 + struct ip_conntrack_expect *exp;
2930 + DEBUGP("remove_expectations(%p)\n", ct);
2932 + list_for_each_safe(exp_entry, next, &ct->sibling_list) {
2933 + exp = list_entry(exp_entry, struct ip_conntrack_expect,
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;
2948 + IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
2949 + IP_NF_ASSERT(exp->expectant == ct);
2951 + /* delete expectation from global and private lists */
2952 + unexpect_related(exp);
2957 +clean_from_lists(struct ip_conntrack *ct)
2959 + unsigned int ho, hr;
2961 + DEBUGP("clean_from_lists(%p)\n", ct);
2962 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
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]);
2969 + /* Destroy all un-established, pending expectations */
2970 + remove_expectations(ct, 1);
2974 +destroy_conntrack(struct nf_conntrack *nfct)
2976 + struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
2977 + struct ip_conntrack_protocol *proto;
2979 + DEBUGP("destroy_conntrack(%p)\n", ct);
2980 + IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
2981 + IP_NF_ASSERT(!timer_pending(&ct->timeout));
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);
2990 + if (ip_conntrack_destroyed)
2991 + ip_conntrack_destroyed(ct);
2993 + WRITE_LOCK(&ip_conntrack_lock);
2994 + /* Delete us from our own list to prevent corruption later */
2995 + list_del(&ct->sibling_list);
2997 + /* Delete our master expectation */
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;
3005 + kfree(ct->master);
3007 + WRITE_UNLOCK(&ip_conntrack_lock);
3010 + ip_conntrack_put(master);
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);
3017 +static void death_by_timeout(unsigned long ul_conntrack)
3019 + struct ip_conntrack *ct = (void *)ul_conntrack;
3021 + WRITE_LOCK(&ip_conntrack_lock);
3022 + clean_from_lists(ct);
3023 + WRITE_UNLOCK(&ip_conntrack_lock);
3024 + ip_conntrack_put(ct);
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)
3032 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3033 + return i->ctrack != ignored_conntrack
3034 + && ip_ct_tuple_equal(tuple, &i->tuple);
3037 +static struct ip_conntrack_tuple_hash *
3038 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
3039 + const struct ip_conntrack *ignored_conntrack)
3041 + struct ip_conntrack_tuple_hash *h;
3042 + unsigned int hash = hash_conntrack(tuple);
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);
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)
3057 + struct ip_conntrack_tuple_hash *h;
3059 + READ_LOCK(&ip_conntrack_lock);
3060 + h = __ip_conntrack_find(tuple, ignored_conntrack);
3062 + atomic_inc(&h->ctrack->ct_general.use);
3063 + READ_UNLOCK(&ip_conntrack_lock);
3068 +static inline struct ip_conntrack *
3069 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
3071 + struct ip_conntrack *ct
3072 + = (struct ip_conntrack *)nfct->master;
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);
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)
3085 + return __ip_conntrack_get(skb->nfct, ctinfo);
3089 +/* Confirm a connection given skb->nfct; places it in hash table */
3091 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
3093 + unsigned int hash, repl_hash;
3094 + struct ip_conntrack *ct;
3095 + enum ip_conntrack_info ctinfo;
3097 + ct = __ip_conntrack_get(nfct, &ctinfo);
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)
3106 + hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
3107 + repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
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); */
3114 + /* No external references means noone else could have
3116 + IP_NF_ASSERT(!is_confirmed(ct));
3117 + DEBUGP("Confirming conntrack %p\n", ct);
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);
3146 + WRITE_UNLOCK(&ip_conntrack_lock);
3150 +/* Returns true if a connection correspondings to the tuple (required
3153 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
3154 + const struct ip_conntrack *ignored_conntrack)
3156 + struct ip_conntrack_tuple_hash *h;
3158 + READ_LOCK(&ip_conntrack_lock);
3159 + h = __ip_conntrack_find(tuple, ignored_conntrack);
3160 + READ_UNLOCK(&ip_conntrack_lock);
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)
3171 + struct ip_conntrack_tuple innertuple, origtuple;
3173 + struct icmphdr icmp;
3176 + struct ip_conntrack_protocol *innerproto;
3177 + struct ip_conntrack_tuple_hash *h;
3180 + IP_NF_ASSERT(skb->nfct == NULL);
3182 + /* Not enough header? */
3183 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
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)
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);
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);
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");
3215 + *ctinfo = IP_CT_RELATED;
3217 + h = ip_conntrack_find_get(&innertuple, NULL);
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);
3226 + DEBUGP("icmp_error_track: no match\n");
3229 + /* Reverse direction from that found */
3230 + if (DIRECTION(h) != IP_CT_DIR_REPLY)
3231 + *ctinfo += IP_CT_IS_REPLY;
3233 + if (DIRECTION(h) == IP_CT_DIR_REPLY)
3234 + *ctinfo += IP_CT_IS_REPLY;
3237 + /* Update skb to refer to this connection */
3238 + skb->nfct = &h->ctrack->infos[*ctinfo];
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)
3246 + return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
3249 +static int early_drop(struct list_head *chain)
3251 + /* Traverse backwards: gives us oldest, which is roughly LRU */
3252 + struct ip_conntrack_tuple_hash *h;
3255 + READ_LOCK(&ip_conntrack_lock);
3256 + h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
3258 + atomic_inc(&h->ctrack->ct_general.use);
3259 + READ_UNLOCK(&ip_conntrack_lock);
3264 + if (del_timer(&h->ctrack->timeout)) {
3265 + death_by_timeout((unsigned long)h->ctrack);
3268 + ip_conntrack_put(h->ctrack);
3272 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
3273 + const struct ip_conntrack_tuple *rtuple)
3275 + return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
3278 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
3280 + return LIST_FIND(&helpers, helper_cmp,
3281 + struct ip_conntrack_helper *,
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)
3292 + struct ip_conntrack *conntrack;
3293 + struct ip_conntrack_tuple repl_tuple;
3295 + struct ip_conntrack_expect *expected;
3297 + static unsigned int drop_next;
3299 + if (!ip_conntrack_hash_rnd_initted) {
3300 + get_random_bytes(&ip_conntrack_hash_rnd, 4);
3301 + ip_conntrack_hash_rnd_initted = 1;
3304 + hash = hash_conntrack(tuple);
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;
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"
3319 + return ERR_PTR(-ENOMEM);
3323 + if (!invert_tuple(&repl_tuple, tuple, protocol)) {
3324 + DEBUGP("Can't invert tuple.\n");
3328 + conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
3330 + DEBUGP("Can't allocate conntrack.\n");
3331 + return ERR_PTR(-ENOMEM);
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;
3344 + if (!protocol->new(conntrack, skb)) {
3345 + kmem_cache_free(ip_conntrack_cachep, conntrack);
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;
3353 + INIT_LIST_HEAD(&conntrack->sibling_list);
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);
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))
3370 + /* Look up the conntrack helper for master connections only */
3372 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
3374 + /* If the expectation is dying, then this is a loser. */
3376 + && expected->expectant->helper->timeout
3377 + && ! del_timer(&expected->timeout))
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]);
3392 + atomic_inc(&ip_conntrack_count);
3393 + WRITE_UNLOCK(&ip_conntrack_lock);
3395 + if (expected && expected->expectfn)
3396 + expected->expectfn(conntrack);
3397 + return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
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,
3405 + unsigned int hooknum,
3406 + enum ip_conntrack_info *ctinfo)
3408 + struct ip_conntrack_tuple tuple;
3409 + struct ip_conntrack_tuple_hash *h;
3411 + IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
3413 + if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
3416 + /* look for tuple match */
3417 + h = ip_conntrack_find_get(&tuple, NULL);
3419 + h = init_conntrack(&tuple, proto, skb);
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 */
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",
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",
3440 + *ctinfo = IP_CT_RELATED;
3442 + DEBUGP("ip_conntrack_in: new packet for %p\n",
3444 + *ctinfo = IP_CT_NEW;
3448 + skb->nfct = &h->ctrack->infos[*ctinfo];
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 *))
3459 + struct ip_conntrack *ct;
3460 + enum ip_conntrack_info ctinfo;
3461 + struct ip_conntrack_protocol *proto;
3465 + /* FIXME: Do this right please. --RR */
3466 + (*pskb)->nfcache |= NFC_UNKNOWN;
3468 +/* Doesn't cover locally-generated broadcast, so not worth it. */
3470 + /* Ignore broadcast: no `connection'. */
3471 + if ((*pskb)->pkt_type == PACKET_BROADCAST) {
3472 + printk("Broadcast packet!\n");
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);
3483 + /* Previously seen (loopback)? Ignore. Do this before
3484 + fragment check. */
3485 + if ((*pskb)->nfct)
3488 + /* Gather fragments. */
3489 + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
3490 + *pskb = ip_ct_gather_frags(*pskb);
3495 + proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
3497 + /* It may be an icmp error... */
3498 + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
3499 + && icmp_error_track(*pskb, &ctinfo, hooknum))
3502 + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
3503 + /* Not valid part of a connection */
3507 + /* Too stressed to deal. */
3510 + IP_NF_ASSERT((*pskb)->nfct);
3512 + ret = proto->packet(ct, *pskb, ctinfo);
3515 + nf_conntrack_put((*pskb)->nfct);
3516 + (*pskb)->nfct = NULL;
3520 + if (ret != NF_DROP && ct->helper) {
3521 + ret = ct->helper->help(*pskb, ct, ctinfo);
3524 + nf_conntrack_put((*pskb)->nfct);
3525 + (*pskb)->nfct = NULL;
3530 + set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
3535 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
3536 + const struct ip_conntrack_tuple *orig)
3538 + return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
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)
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));
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)
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 } };
3568 + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
3571 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
3573 + WRITE_LOCK(&ip_conntrack_lock);
3574 + unexpect_related(expect);
3575 + WRITE_UNLOCK(&ip_conntrack_lock);
3578 +static void expectation_timed_out(unsigned long ul_expect)
3580 + struct ip_conntrack_expect *expect = (void *) ul_expect;
3582 + DEBUGP("expectation %p timed out\n", expect);
3583 + WRITE_LOCK(&ip_conntrack_lock);
3584 + __unexpect_related(expect);
3585 + WRITE_UNLOCK(&ip_conntrack_lock);
3588 +/* Add a related connection. */
3589 +int ip_conntrack_expect_related(struct ip_conntrack *related_to,
3590 + struct ip_conntrack_expect *expect)
3592 + struct ip_conntrack_expect *old, *new;
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 */
3599 + DEBUGP("ip_conntrack_expect_related %p\n", related_to);
3600 + DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
3601 + DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
3603 + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
3604 + struct ip_conntrack_expect *, &expect->tuple,
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 */
3616 + old->timeout.expires = jiffies +
3617 + related_to->helper->timeout * HZ;
3618 + add_timer(&old->timeout);
3623 + WRITE_UNLOCK(&ip_conntrack_lock);
3626 + } else if (related_to->helper->max_expected &&
3627 + related_to->expecting >= related_to->helper->max_expected) {
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));
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));
3651 + /* choose the the oldest expectation to evict */
3652 + list_for_each_entry(old, &related_to->sibling_list,
3654 + if (old->sibling == NULL)
3657 + /* We cannot fail since related_to->expecting is the number
3658 + * of unconfirmed expectations */
3659 + IP_NF_ASSERT(old && old->sibling == NULL);
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.
3666 + unexpect_related(old);
3668 + } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
3669 + struct ip_conntrack_expect *, &expect->tuple,
3671 + WRITE_UNLOCK(&ip_conntrack_lock);
3672 + DEBUGP("expect_related: busy!\n");
3676 + new = (struct ip_conntrack_expect *)
3677 + kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
3679 + WRITE_UNLOCK(&ip_conntrack_lock);
3680 + DEBUGP("expect_relaed: OOM allocating expect\n");
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);
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);
3703 + related_to->expecting++;
3705 + WRITE_UNLOCK(&ip_conntrack_lock);
3710 +/* Change tuple in an existing expectation */
3711 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
3712 + struct ip_conntrack_tuple *newtuple)
3716 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3717 + WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
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 */
3732 + memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
3733 + memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
3737 + /* Resent packet */
3738 + DEBUGP("change expect: resent packet\n");
3739 + if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
3742 + /* Force NAT to choose again the same port */
3746 + WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
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)
3756 + WRITE_LOCK(&ip_conntrack_lock);
3757 + if (__ip_conntrack_find(newreply, conntrack)) {
3758 + WRITE_UNLOCK(&ip_conntrack_lock);
3761 + /* Should be unconfirmed, so not in hash table yet */
3762 + IP_NF_ASSERT(!is_confirmed(conntrack));
3764 + DEBUGP("Altering reply tuple of %p to ", conntrack);
3765 + DUMP_TUPLE(newreply);
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 *,
3772 + WRITE_UNLOCK(&ip_conntrack_lock);
3777 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
3779 + WRITE_LOCK(&ip_conntrack_lock);
3780 + list_prepend(&helpers, me);
3781 + WRITE_UNLOCK(&ip_conntrack_lock);
3786 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
3787 + const struct ip_conntrack_helper *me)
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;
3798 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
3802 + /* Need write lock here, to delete helper. */
3803 + WRITE_LOCK(&ip_conntrack_lock);
3804 + LIST_DELETE(&helpers, me);
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);
3812 + /* Someone could be still looking at the helper in a bh. */
3813 + synchronize_net();
3816 +/* Refresh conntrack for this many jiffies. */
3817 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
3819 + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
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;
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);
3832 + WRITE_UNLOCK(&ip_conntrack_lock);
3835 +/* Returns new sk_buff, or NULL */
3837 +ip_ct_gather_frags(struct sk_buff *skb)
3839 + struct sock *sk = skb->sk;
3840 +#ifdef CONFIG_NETFILTER_DEBUG
3841 + unsigned int olddebug = skb->nf_debug;
3848 + local_bh_disable();
3849 + skb = ip_defrag(skb);
3850 + local_bh_enable();
3859 + skb_set_owner_w(skb, sk);
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;
3872 +/* Used by ipt_REJECT. */
3873 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
3875 + struct ip_conntrack *ct;
3876 + enum ip_conntrack_info ctinfo;
3878 + ct = __ip_conntrack_get(nfct, &ctinfo);
3880 + /* This ICMP is in reverse direction to the packet which
3882 + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
3883 + ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
3885 + ctinfo = IP_CT_RELATED;
3887 + /* Attach new skbuff, and increment count */
3888 + nskb->nfct = &ct->infos[ctinfo];
3889 + atomic_inc(&ct->ct_general.use);
3893 +do_kill(const struct ip_conntrack_tuple_hash *i,
3894 + int (*kill)(const struct ip_conntrack *i, void *data),
3897 + return kill(i->ctrack, data);
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),
3905 + struct ip_conntrack_tuple_hash *h = NULL;
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);
3914 + atomic_inc(&h->ctrack->ct_general.use);
3915 + READ_UNLOCK(&ip_conntrack_lock);
3921 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
3924 + struct ip_conntrack_tuple_hash *h;
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. */
3933 + ip_conntrack_put(h->ctrack);
3937 +/* Fast function for those who don't want to parse /proc (and I don't
3939 +/* Reversing the socket's dst/src point of view gives us the reply
3942 +getorigdst(struct sock *sk, int optval, void *user, int *len)
3944 + struct inet_opt *inet = inet_sk(sk);
3945 + struct ip_conntrack_tuple_hash *h;
3946 + struct ip_conntrack_tuple tuple;
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;
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;
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));
3967 + h = ip_conntrack_find_get(&tuple, NULL);
3969 + struct sockaddr_in sin;
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]
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)
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));
3991 +static struct nf_sockopt_ops so_getorigdst = {
3993 + .get_optmin = SO_ORIGINAL_DST,
3994 + .get_optmax = SO_ORIGINAL_DST+1,
3995 + .get = &getorigdst,
3998 +static int kill_all(const struct ip_conntrack *i, void *data)
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)
4007 + ip_ct_attach = NULL;
4008 + /* This makes sure all current packets have passed through
4009 + netfilter framework. Roll on, two-stage module
4011 + synchronize_net();
4013 + i_see_dead_people:
4014 + ip_ct_selective_cleanup(kill_all, NULL);
4015 + if (atomic_read(&ip_conntrack_count) != 0) {
4017 + goto i_see_dead_people;
4020 + kmem_cache_destroy(ip_conntrack_cachep);
4021 + vfree(ip_conntrack_hash);
4022 + nf_unregister_sockopt(&so_getorigdst);
4025 +static int hashsize;
4026 +MODULE_PARM(hashsize, "i");
4028 +int __init ip_conntrack_init(void)
4033 + /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
4034 + * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
4036 + ip_conntrack_htable_size = hashsize;
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;
4046 + ip_conntrack_max = 8 * ip_conntrack_htable_size;
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));
4053 + ret = nf_register_sockopt(&so_getorigdst);
4055 + printk(KERN_ERR "Unable to register netfilter socket option\n");
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;
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;
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);
4081 + for (i = 0; i < ip_conntrack_htable_size; i++)
4082 + INIT_LIST_HEAD(&ip_conntrack_hash[i]);
4084 + /* For use by ipt_REJECT */
4085 + ip_ct_attach = ip_conntrack_attach;
4089 + vfree(ip_conntrack_hash);
4091 + nf_unregister_sockopt(&so_getorigdst);
4095 diff -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);
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 *))
4108 + /* Previously seen (loopback)? Ignore. Do this before
4109 + fragment check. */
4110 + if ((*pskb)->nfct)
4113 + /* Gather fragments. */
4114 + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
4115 + *pskb = ip_ct_gather_frags(*pskb);
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);
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,
4134 + .hooknum = NF_IP_PRE_ROUTING,
4135 + .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
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;
4145 + ret = nf_register_hook(&ip_conntrack_defrag_ops);
4147 + printk("ip_conntrack: can't register pre-routing hook to defrag.\n");
4148 + goto cleanup_proc;
4150 ret = nf_register_hook(&ip_conntrack_in_ops);
4152 printk("ip_conntrack: can't register pre-routing hook.\n");
4153 - goto cleanup_proc;
4154 + goto cleanup_defragops;
4156 ret = nf_register_hook(&ip_conntrack_local_out_ops);
4159 nf_unregister_hook(&ip_conntrack_local_out_ops);
4161 nf_unregister_hook(&ip_conntrack_in_ops);
4162 + cleanup_defragops:
4163 + nf_unregister_hook(&ip_conntrack_defrag_ops);
4165 proc_net_remove("ip_conntrack");
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);
4174 diff -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
4178 +/* This file contains all the functions required for the standalone
4179 + ip_conntrack module.
4181 + These are not required by the compatibility layer.
4184 +/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
4185 + Public Licence. */
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>
4198 +#include <net/checksum.h>
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)
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>
4210 +#define DEBUGP printk
4212 +#define DEBUGP(format, args...)
4215 +MODULE_LICENSE("GPL");
4217 +static int kill_proto(const struct ip_conntrack *i, void *data)
4219 + return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
4220 + *((u_int8_t *) data));
4223 +static unsigned int
4224 +print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple,
4225 + struct ip_conntrack_protocol *proto)
4229 + len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
4230 + NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
4232 + len += proto->print_tuple(buffer + len, tuple);
4237 +/* FIXME: Don't print source proto part. --RR */
4238 +static unsigned int
4239 +print_expect(char *buffer, const struct ip_conntrack_expect *expect)
4243 + if (expect->expectant->helper->timeout)
4244 + len = sprintf(buffer, "EXPECTING: %lu ",
4245 + timer_pending(&expect->timeout)
4246 + ? (expect->timeout.expires - jiffies)/HZ : 0);
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");
4257 +static unsigned int
4258 +print_conntrack(char *buffer, struct ip_conntrack *conntrack)
4261 + struct ip_conntrack_protocol *proto
4262 + = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4263 + .tuple.dst.protonum);
4265 + len = sprintf(buffer, "%-8s %u %lu ",
4267 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4268 + .tuple.dst.protonum,
4269 + timer_pending(&conntrack->timeout)
4270 + ? (conntrack->timeout.expires - jiffies)/HZ : 0);
4272 + len += proto->print_conntrack(buffer + len, conntrack);
4273 + len += print_tuple(buffer + len,
4274 + &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
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,
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");
4290 +/* Returns true when finished. */
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)
4296 + unsigned int newlen;
4297 + IP_NF_ASSERT(hash->ctrack);
4299 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
4301 + /* Only count originals */
4302 + if (DIRECTION(hash))
4305 + if ((*upto)++ < offset)
4308 + newlen = print_conntrack(buffer + *len, hash->ctrack);
4309 + if (*len + newlen > maxlen)
4311 + else *len += newlen;
4317 +list_conntracks(char *buffer, char **start, off_t offset, int length)
4320 + unsigned int len = 0;
4322 + struct list_head *e;
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))
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;
4341 + len += print_expect(buffer + len, expect);
4342 + if (len > length) {
4349 + READ_UNLOCK(&ip_conntrack_lock);
4351 + /* `start' hack - see fs/proc/generic.c line ~165 */
4352 + *start = (char *)((unsigned int)upto - offset);
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 *))
4362 + /* We've seen it coming out the other side: confirm it */
4363 + return ip_conntrack_confirm(*pskb);
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 *))
4372 + struct rtable *rt = (struct rtable *)(*pskb)->dst;
4374 + /* We've seen it coming out the other side: confirm */
4375 + if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
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);
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 *))
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");
4402 + return ip_conntrack_in(hooknum, pskb, in, out, okfn);
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,
4411 + .hooknum = NF_IP_PRE_ROUTING,
4412 + .priority = NF_IP_PRI_CONNTRACK,
4415 +static struct nf_hook_ops ip_conntrack_local_out_ops = {
4416 + .hook = ip_conntrack_local,
4417 + .owner = THIS_MODULE,
4419 + .hooknum = NF_IP_LOCAL_OUT,
4420 + .priority = NF_IP_PRI_CONNTRACK,
4423 +/* Refragmenter; last chance. */
4424 +static struct nf_hook_ops ip_conntrack_out_ops = {
4425 + .hook = ip_refrag,
4426 + .owner = THIS_MODULE,
4428 + .hooknum = NF_IP_POST_ROUTING,
4429 + .priority = NF_IP_PRI_LAST,
4432 +static struct nf_hook_ops ip_conntrack_local_in_ops = {
4433 + .hook = ip_confirm,
4434 + .owner = THIS_MODULE,
4436 + .hooknum = NF_IP_LOCAL_IN,
4437 + .priority = NF_IP_PRI_LAST-1,
4440 +/* Sysctl support */
4442 +#ifdef CONFIG_SYSCTL
4444 +/* From ip_conntrack_core.c */
4445 +extern int ip_conntrack_max;
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;
4457 +/* From ip_conntrack_proto_udp.c */
4458 +extern unsigned long ip_ct_udp_timeout;
4459 +extern unsigned long ip_ct_udp_timeout_stream;
4461 +/* From ip_conntrack_proto_icmp.c */
4462 +extern unsigned long ip_ct_icmp_timeout;
4464 +/* From ip_conntrack_proto_icmp.c */
4465 +extern unsigned long ip_ct_generic_timeout;
4467 +static struct ctl_table_header *ip_ct_sysctl_header;
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,
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},
4512 +#define NET_IP_CONNTRACK_MAX 2089
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,
4522 +static ctl_table ip_ct_ipv4_table[] = {
4523 + {NET_IPV4, "ipv4", NULL, 0, 0555, ip_ct_netfilter_table, 0, 0, 0, 0, 0},
4527 +static ctl_table ip_ct_net_table[] = {
4528 + {CTL_NET, "net", NULL, 0, 0555, ip_ct_ipv4_table, 0, 0, 0, 0, 0},
4532 +static int init_or_cleanup(int init)
4534 + struct proc_dir_entry *proc;
4537 + if (!init) goto cleanup;
4539 + ret = ip_conntrack_init();
4541 + goto cleanup_nothing;
4543 + proc = proc_net_create("ip_conntrack",0,list_conntracks);
4544 + if (!proc) goto cleanup_init;
4545 + proc->owner = THIS_MODULE;
4547 + ret = nf_register_hook(&ip_conntrack_in_ops);
4549 + printk("ip_conntrack: can't register pre-routing hook.\n");
4550 + goto cleanup_proc;
4552 + ret = nf_register_hook(&ip_conntrack_local_out_ops);
4554 + printk("ip_conntrack: can't register local out hook.\n");
4555 + goto cleanup_inops;
4557 + ret = nf_register_hook(&ip_conntrack_out_ops);
4559 + printk("ip_conntrack: can't register post-routing hook.\n");
4560 + goto cleanup_inandlocalops;
4562 + ret = nf_register_hook(&ip_conntrack_local_in_ops);
4564 + printk("ip_conntrack: can't register local in hook.\n");
4565 + goto cleanup_inoutandlocalops;
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");
4578 +#ifdef CONFIG_SYSCTL
4579 + unregister_sysctl_table(ip_ct_sysctl_header);
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);
4587 + nf_unregister_hook(&ip_conntrack_in_ops);
4589 + proc_net_remove("ip_conntrack");
4591 + ip_conntrack_cleanup();
4596 +/* FIXME: Allow NULL functions and sub in pointers to generic for
4598 +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
4601 + struct list_head *i;
4603 + WRITE_LOCK(&ip_conntrack_lock);
4604 + list_for_each(i, &protocol_list) {
4605 + if (((struct ip_conntrack_protocol *)i)->proto
4606 + == proto->proto) {
4612 + list_prepend(&protocol_list, proto);
4615 + WRITE_UNLOCK(&ip_conntrack_lock);
4619 +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
4621 + WRITE_LOCK(&ip_conntrack_lock);
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);
4628 + /* Somebody could be still looking at the proto in bh. */
4629 + synchronize_net();
4631 + /* Remove all contrack entries for this protocol */
4632 + ip_ct_selective_cleanup(kill_proto, &proto->proto);
4635 +static int __init init(void)
4637 + return init_or_cleanup(1);
4640 +static void __exit fini(void)
4642 + init_or_cleanup(0);
4648 +/* Some modules need us, but don't depend directly on any symbol.
4649 + They should call this. */
4650 +void need_ip_conntrack(void)
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);
4681 diff -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
4686 for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
4687 /* Create helper structure */
4688 - memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
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;
4693 diff -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
4697 struct ip_nat_helper *hlpr;
4699 hlpr = &ip_nat_amanda_helper;
4700 - memset(hlpr, 0, sizeof(struct ip_nat_helper));
4702 hlpr->tuple.dst.protonum = IPPROTO_UDP;
4703 hlpr->tuple.src.u.udp.port = htons(10080);
4704 hlpr->mask.src.u.udp.port = 0xFFFF;
4705 diff -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
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,
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;
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);
4730 diff -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
4734 +/* NAT for netfilter; shared with compatibility layer. */
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>
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)
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>
4765 +#define DEBUGP printk
4767 +#define DEBUGP(format, args...)
4770 +DECLARE_RWLOCK(ip_nat_lock);
4771 +DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
4773 +/* Calculated at init based on memory size */
4774 +static unsigned int ip_nat_htable_size;
4776 +static struct list_head *bysource;
4777 +static struct list_head *byipsproto;
4779 +LIST_HEAD(helpers);
4781 +extern struct ip_nat_protocol unknown_nat_protocol;
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)
4787 + /* Modified src and dst, to ensure we don't create two
4788 + identical streams. */
4789 + return (src + dst + proto) % ip_nat_htable_size;
4792 +static inline size_t
4793 +hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
4795 + /* Original src, to ensure we map it consistently if poss. */
4796 + return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
4799 +/* Noone using conntrack by the time this called. */
4800 +static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
4802 + struct ip_nat_info *info = &conn->nat.info;
4803 + unsigned int hs, hp;
4805 + if (!info->initialized)
4808 + IP_NF_ASSERT(info->bysource.conntrack);
4809 + IP_NF_ASSERT(info->byipsproto.conntrack);
4811 + hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
4812 + conn->tuplehash[IP_CT_DIR_ORIGINAL]
4813 + .tuple.dst.protonum);
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);
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);
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.) */
4830 +ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
4832 + u_int32_t diffs[] = { oldvalinv, newval };
4833 + return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
4834 + oldcheck^0xFFFF));
4837 +static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
4839 + return i->protonum == proto;
4842 +struct ip_nat_protocol *
4843 +find_nat_proto(u_int16_t protonum)
4845 + struct ip_nat_protocol *i;
4847 + MUST_BE_READ_LOCKED(&ip_nat_lock);
4848 + i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
4850 + i = &unknown_nat_protocol;
4854 +/* Is this tuple already taken? (not by us) */
4856 +ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
4857 + const struct ip_conntrack *ignored_conntrack)
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.
4863 + We could keep a separate hash if this proves too slow. */
4864 + struct ip_conntrack_tuple reply;
4866 + invert_tuplepr(&reply, tuple);
4867 + return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
4870 +/* Does tuple + the source manip come within the range mr */
4872 +in_range(const struct ip_conntrack_tuple *tuple,
4873 + const struct ip_conntrack_manip *manip,
4874 + const struct ip_nat_multi_range *mr)
4876 + struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
4878 + struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
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)))
4889 + if (newtuple.src.ip != tuple->src.ip)
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))
4902 +src_cmp(const struct ip_nat_hash *i,
4903 + const struct ip_conntrack_tuple *tuple,
4904 + const struct ip_nat_multi_range *mr)
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
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]
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)
4923 + unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
4924 + struct ip_nat_hash *i;
4926 + MUST_BE_READ_LOCKED(&ip_nat_lock);
4927 + i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
4929 + return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
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. */
4938 +do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
4940 + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = var_ip } } };
4941 + struct rtable *rt;
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",
4950 + *other_ipp = rt->rt_src;
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)
4962 + /* Compare backwards: we're dealing with OUTGOING tuples, and
4963 + inside the conntrack is the REPLY tuple. Don't count this
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
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)
4978 + unsigned int score = 0;
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);
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.
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)
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;
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;
5019 + var_ipp = &tuple->dst.ip;
5020 + saved_ip = tuple->src.ip;
5021 + other_ipp = &tuple->src.ip;
5023 + /* Don't do do_extra_mangle unless necessary (overrides
5024 + explicit socket bindings, for example) */
5025 + orig_dstip = tuple->dst.ip;
5027 + IP_NF_ASSERT(mr->rangesize >= 1);
5028 + for (i = 0; i < mr->rangesize; i++) {
5030 + u_int32_t minip, maxip, j;
5032 + /* Don't do ranges which are already eliminated. */
5033 + if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
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);
5041 + minip = maxip = ntohl(*var_ipp);
5044 + for (j = 0; j < maxip - minip + 1; j++) {
5045 + unsigned int score;
5047 + *var_ipp = htonl(minip + (randomness + j)
5048 + % (maxip - minip + 1));
5050 + /* Reset the other ip in case it was mangled by
5051 + * do_extra_mangle last time. */
5052 + *other_ipp = saved_ip;
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
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
5074 + return (struct ip_nat_range *)
5077 + best.score = score;
5078 + best.tuple = *tuple;
5079 + best.range = &mr->range[i];
5083 + *tuple = best.tuple;
5085 + /* Discard const. */
5086 + return (struct ip_nat_range *)best.range;
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)
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);
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;
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,
5116 + tuple->dst.ip = mr->range[0].min_ip;
5120 + /* Discard const. */
5121 + return (struct ip_nat_range *)&mr->range[0];
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)
5131 + struct ip_nat_protocol *proto
5132 + = find_nat_proto(orig_tuple->dst.protonum);
5133 + struct ip_nat_range *rptr;
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;
5141 + /* 1) If this srcip/proto/src-proto-part is currently mapped,
5142 + and that same mapping gives a unique tuple within the given
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;
5151 + manip = find_appropriate_src(orig_tuple, mr);
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))
5162 + /* 2) Select the least-used IP/proto combination in the given
5165 + *tuple = *orig_tuple;
5166 + while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
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. */
5172 + /* Only bother mapping if it's not already in range
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)) {
5181 + if (proto->unique_tuple(tuple, rptr,
5182 + HOOK2MANIP(hooknum),
5184 + /* Must be unique. */
5185 + IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
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,
5197 + DEBUGP("Trying implicit mapping\n");
5198 + if (proto->unique_tuple(tuple, &r,
5201 + /* Must be unique. */
5202 + IP_NF_ASSERT(!ip_nat_used_tuple
5203 + (tuple, conntrack));
5208 + DEBUGP("Protocol can't get unique tuple %u.\n",
5212 + /* Eliminate that from range, and try again. */
5213 + rptr->flags |= IP_NAT_RANGE_FULL;
5214 + *tuple = *orig_tuple;
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;
5229 +helper_cmp(const struct ip_nat_helper *helper,
5230 + const struct ip_conntrack_tuple *tuple)
5232 + return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
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,
5246 +ip_nat_setup_info(struct ip_conntrack *conntrack,
5247 + const struct ip_nat_multi_range *mr,
5248 + unsigned int hooknum)
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;
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))));
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,
5266 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
5267 + invert_tuplepr(&orig_tp,
5268 + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
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",
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)
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);
5297 + if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
5299 + DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
5305 + DEBUGP("Hook %u (%s) %p\n", hooknum,
5306 + HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
5308 + DEBUGP("Original: ");
5309 + DUMP_TUPLE(&orig_tp);
5311 + DUMP_TUPLE(&new_tuple);
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').
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. */
5321 + /* Reply connection: simply invert the new tuple
5323 + invert_tuplepr(&reply, &new_tuple);
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));
5329 + /* FIXME: We can simply used existing conntrack reply tuple
5331 + /* Create inverse of original: C/D/A/B' */
5332 + invert_tuplepr(&inv_tuple, &orig_tp);
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 });
5342 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
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);
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 });
5360 + IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
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);
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 *,
5376 + info->initialized |= (1 << HOOK2MANIP(hooknum));
5379 + IP_NF_ASSERT(info->bysource.conntrack);
5380 + replace_in_hashes(conntrack, info);
5382 + place_in_hashes(conntrack, info);
5388 +void replace_in_hashes(struct ip_conntrack *conntrack,
5389 + struct ip_nat_info *info)
5391 + /* Source has changed, so replace in hashes. */
5392 + unsigned int srchash
5393 + = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
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]
5402 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5404 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5405 + .tuple.dst.protonum);
5407 + IP_NF_ASSERT(info->bysource.conntrack == conntrack);
5408 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5410 + list_del(&info->bysource.list);
5411 + list_del(&info->byipsproto.list);
5413 + list_prepend(&bysource[srchash], &info->bysource);
5414 + list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5417 +void place_in_hashes(struct ip_conntrack *conntrack,
5418 + struct ip_nat_info *info)
5420 + unsigned int srchash
5421 + = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
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]
5430 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5432 + conntrack->tuplehash[IP_CT_DIR_REPLY]
5433 + .tuple.dst.protonum);
5435 + IP_NF_ASSERT(!info->bysource.conntrack);
5437 + MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5438 + info->byipsproto.conntrack = conntrack;
5439 + info->bysource.conntrack = conntrack;
5441 + list_prepend(&bysource[srchash], &info->bysource);
5442 + list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5445 +/* Returns true if succeeded. */
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)
5453 + struct iphdr *iph;
5455 + (*pskb)->nfcache |= NFC_ALTERED;
5456 + if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph)))
5459 + iph = (void *)(*pskb)->data + iphdroff;
5461 + /* Manipulate protcol part. */
5462 + if (!find_nat_proto(proto)->manip_pkt(pskb,
5463 + iphdroff + iph->ihl*4,
5464 + manip, maniptype))
5467 + iph = (void *)(*pskb)->data + iphdroff;
5469 + if (maniptype == IP_NAT_MANIP_SRC) {
5470 + iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
5472 + iph->saddr = manip->ip;
5474 + iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
5476 + iph->daddr = manip->ip;
5481 +static inline int exp_for_packet(struct ip_conntrack_expect *exp,
5482 + struct sk_buff *skb)
5484 + struct ip_conntrack_protocol *proto;
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);
5495 +/* Do packet manipulations according to binding. */
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)
5504 + struct ip_nat_helper *helper;
5505 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
5506 + int proto = (*pskb)->nh.iph->protocol;
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",
5517 + info->manips[i].maniptype == IP_NAT_MANIP_SRC
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);
5529 + helper = info->helper;
5530 + READ_UNLOCK(&ip_nat_lock);
5533 + struct ip_conntrack_expect *exp = NULL;
5534 + struct list_head *cur_item;
5535 + int ret = NF_ACCEPT;
5536 + int helper_called = 0;
5538 + DEBUGP("do_bindings: helper existing for (%p)\n", ct);
5540 + /* Always defragged for helpers */
5541 + IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
5542 + & htons(IP_MF|IP_OFFSET)));
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,
5550 + /* if this expectation is already established, skip */
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,
5560 + if (ret != NF_ACCEPT) {
5561 + READ_UNLOCK(&ip_conntrack_lock);
5564 + helper_called = 1;
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,
5573 + if (ret != NF_ACCEPT) {
5574 + READ_UNLOCK(&ip_conntrack_lock);
5578 + READ_UNLOCK(&ip_conntrack_lock);
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))
5601 +icmp_reply_translation(struct sk_buff **pskb,
5602 + struct ip_conntrack *conntrack,
5603 + unsigned int hooknum,
5607 + struct icmphdr icmp;
5611 + struct ip_nat_info *info = &conntrack->nat.info;
5614 + if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside)))
5616 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
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)))
5627 + /* Must be RELATED */
5628 + IP_NF_ASSERT((*pskb)->nfct
5629 + - (struct ip_conntrack *)(*pskb)->nfct->master
5632 + - (struct ip_conntrack *)(*pskb)->nfct->master
5633 + == IP_CT_RELATED+IP_CT_IS_REPLY);
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)
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).
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
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);
5665 + if (info->manips[i].direction != dir)
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
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))
5685 + /* Outer packet needs to have IP header NATed like
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
5693 + NIPQUAD(info->manips[i].manip.ip));
5694 + if (!manip_pkt(0, pskb, 0,
5695 + &info->manips[i].manip,
5696 + info->manips[i].maniptype))
5700 + READ_UNLOCK(&ip_nat_lock);
5702 + hdrlen = (*pskb)->nh.iph->ihl * 4;
5704 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
5706 + inside->icmp.checksum = 0;
5707 + inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
5708 + (*pskb)->len - hdrlen,
5713 + READ_UNLOCK(&ip_nat_lock);
5717 +int __init ip_nat_init(void)
5721 + /* Leave them the same for the moment. */
5722 + ip_nat_htable_size = ip_conntrack_htable_size;
5724 + /* One vmalloc for both hash tables */
5725 + bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
5729 + byipsproto = bysource + ip_nat_htable_size;
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);
5738 + for (i = 0; i < ip_nat_htable_size; i++) {
5739 + INIT_LIST_HEAD(&bysource[i]);
5740 + INIT_LIST_HEAD(&byipsproto[i]);
5743 + /* FIXME: Man, this is a hack. <SIGH> */
5744 + IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
5745 + ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
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)
5753 + memset((void *)&i->nat, 0, sizeof(i->nat));
5757 +/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
5758 +void ip_nat_cleanup(void)
5760 + ip_ct_selective_cleanup(&clean_nat, NULL);
5761 + ip_conntrack_destroyed = NULL;
5764 diff -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
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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 } },
5803 diff -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
5807 ports[0] = TFTP_PORT;
5809 for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
5810 - memset(&tftp[i], 0, sizeof(struct ip_nat_helper));
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;
5815 diff -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
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>
5827 #include <asm/semaphore.h>
5828 #include <linux/proc_fs.h>
5830 +#include <linux/netfilter.h>
5831 #include <linux/netfilter_ipv4/ip_tables.h>
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",
5841 MODULE_LICENSE("GPL");
5842 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
5843 MODULE_DESCRIPTION("IPv4 packet filter");
5844 @@ -322,6 +332,12 @@
5846 t = ipt_get_target(e);
5847 IP_NF_ASSERT(t->u.kernel.target);
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);
5854 /* Standard target? */
5855 if (!t->u.kernel.target->target) {
5857 @@ -474,6 +490,29 @@
5858 return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex);
5862 +find_error_target(struct ipt_entry *s,
5863 + struct ipt_entry *e,
5866 + struct ipt_entry_target *t;
5867 + static struct ipt_entry *found = NULL;
5872 + t = ipt_get_target(found);
5873 + if (strcmp(t->u.user.name,
5874 + IPT_ERROR_TARGET) == 0) {
5875 + *chainname = t->data;
5884 /* All zeroes == unconditional rule. */
5886 unconditional(const struct ipt_ip *ip)
5888 mark_source_chains(struct ipt_table_info *newinfo, unsigned int valid_hooks)
5891 + char *chainname = NULL;
5892 + u_int32_t rulenum;
5894 /* No recursion; use packet counter to save back ptrs (reset
5895 to 0 as we leave), and comefrom to save source hook bitmask */
5898 /* Set initial back pointer. */
5899 e->counters.pcnt = pos;
5901 + chainname = (char *) hooknames[hook];
5904 struct ipt_standard_target *t
5908 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
5909 + e->rulenum = rulenum++;
5910 + e->chainname = chainname;
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;
5918 + /* Set unconditional rulenum to zero. */
5920 + e->counters.bcnt = 0;
5922 /* Return: backtrack through the last
5925 @@ -552,6 +601,11 @@
5926 (newinfo->entries + pos);
5927 } while (oldpos == pos + e->next_offset);
5929 + /* Restore chainname, rulenum. */
5930 + chainname = e->chainname;
5931 + rulenum = e->counters.bcnt;
5932 + e->counters.bcnt = 0;
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",
5941 + e->counters.bcnt = rulenum++;
5943 + e = (struct ipt_entry *)
5944 + (newinfo->entries + newpos);
5945 + if (IPT_ENTRY_ITERATE(newinfo->entries,
5947 + find_error_target,
5948 + e, &chainname) == 0) {
5949 + printk("ip_tables: table screwed up!\n");
5953 /* ... this is a fallthru */
5954 newpos = pos + e->next_offset;
5955 diff -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
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>
5969 +#include <linux/netfilter.h>
5970 #include <linux/netfilter_ipv4/ip_tables.h>
5971 #include <linux/netfilter_ipv4/ipt_LOG.h>
5974 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
5975 MODULE_DESCRIPTION("iptables syslog logging module");
5977 +static unsigned int nflog = 1;
5978 +MODULE_PARM(nflog, "i");
5979 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
5982 #define DEBUGP printk
5984 @@ -315,28 +321,25 @@
5985 /* maxlen = 230+ 91 + 230 + 252 = 803 */
5988 -static unsigned int
5989 -ipt_log_target(struct sk_buff **pskb,
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,
5998 + const struct ipt_log_info *loginfo,
5999 + const char *level_string,
6000 + const char *prefix)
6002 - const struct ipt_log_info *loginfo = targinfo;
6003 - char level_string[4] = "< >";
6005 - level_string[1] = '0' + (loginfo->level % 8);
6006 spin_lock_bh(&log_lock);
6007 printk(level_string);
6008 printk("%sIN=%s OUT=%s ",
6010 + prefix == NULL ? loginfo->prefix : prefix,
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;
6021 if (physindev && in != physindev)
6022 printk("PHYSIN=%s ", physindev->name);
6023 @@ -348,25 +351,56 @@
6025 /* MAC logging for input chain only. */
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) {
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
6044 - dump_packet(loginfo, *pskb, 0);
6045 + dump_packet(loginfo, skb, 0);
6047 spin_unlock_bh(&log_lock);
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,
6058 + const struct ipt_log_info *loginfo = targinfo;
6059 + char level_string[4] = "< >";
6061 + level_string[1] = '0' + (loginfo->level % 8);
6062 + ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
6064 return IPT_CONTINUE;
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)
6074 + struct ipt_log_info loginfo = {
6076 + .logflags = IPT_LOG_MASK,
6080 + ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
6083 static int ipt_log_checkentry(const char *tablename,
6084 const struct ipt_entry *e,
6086 @@ -406,12 +440,17 @@
6088 if (ipt_register_target(&ipt_log_reg))
6091 + nf_log_register(PF_INET, &ipt_logfn);
6096 static void __exit fini(void)
6099 + nf_log_unregister(PF_INET, &ipt_logfn);
6101 ipt_unregister_target(&ipt_log_reg);
6104 diff -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
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.
6111 +#include <linux/module.h>
6112 +#include <linux/skbuff.h>
6114 +#include <linux/netfilter_ipv4/ip_tables.h>
6115 +#include <linux/netfilter_ipv4/ip_conntrack.h>
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,
6125 + /* Previously seen (loopback)? Ignore. */
6126 + if ((*pskb)->nfct != NULL)
6127 + return IPT_CONTINUE;
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);
6136 + return IPT_CONTINUE;
6140 +checkentry(const char *tablename,
6141 + const struct ipt_entry *e,
6143 + unsigned int targinfosize,
6144 + unsigned int hook_mask)
6146 + if (targinfosize != 0) {
6147 + printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
6152 + if (strcmp(tablename, "raw") != 0) {
6153 + printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
6160 +static struct ipt_target ipt_notrack_reg = {
6161 + .name = "NOTRACK",
6163 + .checkentry = checkentry,
6165 + .me = THIS_MODULE,
6168 +static int __init init(void)
6170 + if (ipt_register_target(&ipt_notrack_reg))
6176 +static void __exit fini(void)
6178 + ipt_unregister_target(&ipt_notrack_reg);
6184 +MODULE_LICENSE("GPL");
6185 +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6186 +MODULE_DESCRIPTION("IPv4 NOTRACK target");
6187 diff -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
6191 +/* This is a module which is used for setting
6192 + * the NFC_TRACE flag in the nfcache field of an skb.
6194 +#include <linux/module.h>
6195 +#include <linux/skbuff.h>
6197 +#include <linux/netfilter_ipv4/ip_tables.h>
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,
6207 + (*pskb)->nfcache |= NFC_TRACE;
6208 + return IPT_CONTINUE;
6212 +checkentry(const char *tablename,
6213 + const struct ipt_entry *e,
6215 + unsigned int targinfosize,
6216 + unsigned int hook_mask)
6218 + if (targinfosize != 0) {
6219 + printk(KERN_WARNING "TRACE: targinfosize %u != 0\n",
6224 + if (strcmp(tablename, "raw") != 0) {
6225 + printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename);
6232 +static struct ipt_target ipt_trace_reg = {
6235 + .checkentry = checkentry,
6237 + .me = THIS_MODULE,
6240 +static int __init init(void)
6242 + if (ipt_register_target(&ipt_trace_reg))
6248 +static void __exit fini(void)
6250 + ipt_unregister_target(&ipt_trace_reg);
6255 +MODULE_LICENSE("GPL");
6256 +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6257 +MODULE_DESCRIPTION("IPv4 TRACE target");
6258 diff -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
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>
6270 MODULE_PARM(flushtimeout, "i");
6271 MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
6273 +static unsigned int nflog = 1;
6274 +MODULE_PARM(nflog, "i");
6275 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
6277 /* global data structures */
6280 @@ -152,17 +157,17 @@
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)
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;
6302 /* ffs == find first bit set, necessary because userspace
6303 * is already shifting groupnumber, but we need unshifted.
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;
6313 copy_len = loginfo->copy_range;
6315 @@ -209,19 +214,21 @@
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;
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));
6332 *(pm->prefix) = '\0';
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;
6345 pm->outdev_name[0] = '\0';
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)
6353 /* check if we are building multi-part messages */
6356 UNLOCK_BH(&ulog_lock);
6358 - return IPT_CONTINUE;
6363 PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
6364 @@ -271,8 +277,35 @@
6365 PRINTR("ipt_ULOG: Error building netlink message\n");
6367 UNLOCK_BH(&ulog_lock);
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)
6376 + struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
6378 - return IPT_CONTINUE;
6379 + ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
6381 + return IPT_CONTINUE;
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)
6390 + struct ipt_ulog_info loginfo = {
6391 + .nl_group = NFLOG_DEFAULT_NLGROUP,
6393 + .qthreshold = NFLOG_DEFAULT_QTHRESHOLD,
6397 + ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
6400 static int ipt_ulog_checkentry(const char *tablename,
6406 + nf_log_register(PF_INET, &ipt_logfn);
6413 DEBUGP("ipt_ULOG: cleanup_module\n");
6416 + nf_log_unregister(PF_INET, &ipt_logfn);
6418 ipt_unregister_target(&ipt_ulog_reg);
6419 sock_release(nflognl->sk_socket);
6421 diff -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
6426 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
6429 + if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
6430 + statebit = IPT_CONNTRACK_STATE_UNTRACKED;
6432 statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6434 statebit = IPT_CONNTRACK_STATE_INVALID;
6435 diff -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
6439 +/* IP tables module for matching the SCTP header
6441 + * $ipt_sctp.c,v 1.3 2002/05/29 15:09:00 laforge Exp$
6443 + * (C) 2003 by Harald Welte <laforge@gnumonks.org>
6445 + * This software is distributed under the terms GNU GPL v2
6448 +#include <linux/module.h>
6449 +#include <linux/skbuff.h>
6450 +#include <linux/sctp.h>
6452 +#include <linux/netfilter_ipv4/ip_tables.h>
6453 +#include <linux/netfilter_ipv4/ipt_sctp.h>
6455 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
6456 +MODULE_DESCRIPTION("IP tables SCTP matching module");
6457 +MODULE_LICENSE("GPL");
6459 +/* Returns 1 if the port is matched by the range, 0 otherwise */
6461 +port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
6465 + ret = (port >= min && port <= max) ^ invert;
6469 +static int chunk_match(const struct sk_buff *skb, u_int32_t chunks, u_int32_t chunk_mask)
6471 + sctp_chunkhdr_t *ch = (sctp_chunkhdr_t *) skb->data;
6473 + u_int32_t chunks_present = 0;
6477 + ch_end = ((u_int8_t *) ch) + WORD_ROUND(ntohs(ch->length));
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);
6486 + ch = (sctp_chunkhdr_t *) ch_end;
6487 + } while (ch_end < skb->tail);
6489 + return ((chunks_present& chunk_mask) == chunks);
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,
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;
6501 + if (iph->protocol != IPPROTO_SCTP)
6504 + if (offset == 1) {
6505 + duprintf("Dropping evil SCTP offset=1 frag.\n");
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");
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],
6522 + !!(info->invflags & IPT_SCTP_INV_DSTPT))
6523 + && chunk_match(skb, info->chunks, info->chunk_mask)
6527 +static int checkentry(const char *tablename, const struct ipt_ip *ip,
6528 + void *matchinfo, unsigned int matchsize,
6529 + unsigned int hook_mask)
6531 + const struct ipt_sctp_info *info = matchinfo;
6533 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_sctp_info)))
6536 + if (ip->proto != IPPROTO_SCTP && !(ip->invflags & IPT_INV_PROTO))
6539 + if !(info->invflags & ~IPT_SCTP_INV_MASK)
6545 +static struct ipt_match sctp_match = {
6548 + .checkentry = &checkentry,
6549 + .me = THIS_MODULE,
6552 +static int __init init(void)
6554 + return ipt_register_match(&sctp_match);
6557 +static void __exit fini(void)
6559 + ipt_unregister_match(&sctp_match);
6564 diff -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
6568 enum ip_conntrack_info ctinfo;
6569 unsigned int statebit;
6571 - if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
6572 - statebit = IPT_STATE_INVALID;
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);
6579 + statebit = IPT_STATE_INVALID;
6581 return (sinfo->statemask & statebit);
6583 diff -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
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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 } },
6622 diff -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
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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 } },
6679 diff -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
6684 + * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
6686 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
6688 +#include <linux/module.h>
6689 +#include <linux/netfilter_ipv4/ip_tables.h>
6691 +#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
6693 +/* Standard entry. */
6694 +struct ipt_standard
6696 + struct ipt_entry entry;
6697 + struct ipt_standard_target target;
6700 +struct ipt_error_target
6702 + struct ipt_entry_target target;
6703 + char errorname[IPT_FUNCTION_MAXNAMELEN];
6708 + struct ipt_entry entry;
6709 + struct ipt_error_target target;
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) },
6727 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 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 } },
6735 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 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 } }
6744 + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 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 } },
6756 +static struct ipt_table packet_raw = {
6758 + .table = &initial_table.repl,
6759 + .valid_hooks = RAW_VALID_HOOKS,
6760 + .lock = RW_LOCK_UNLOCKED,
6761 + .me = THIS_MODULE,
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 *))
6772 + return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
6775 +/* 'raw' is the very first table. */
6776 +static struct nf_hook_ops ipt_ops[] = {
6777 + { /* PRE_ROUTING hook */
6779 + .owner = THIS_MODULE,
6781 + .hooknum = NF_IP_PRE_ROUTING,
6782 + .priority = NF_IP_PRI_RAW,
6784 + { /* LOCAL_OUT hook */
6786 + .owner = THIS_MODULE,
6788 + .hooknum = NF_IP_LOCAL_OUT,
6789 + .priority = NF_IP_PRI_RAW,
6793 +static int __init init(void)
6797 + /* Register table */
6798 + ret = ipt_register_table(&packet_raw);
6802 + /* Register hooks */
6803 + ret = nf_register_hook(&ipt_ops[0]);
6805 + goto cleanup_table;
6807 + ret = nf_register_hook(&ipt_ops[1]);
6809 + goto cleanup_hook0;
6814 + nf_unregister_hook(&ipt_ops[0]);
6816 + ipt_unregister_table(&packet_raw);
6821 +static void __exit fini(void)
6825 + for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
6826 + nf_unregister_hook(&ipt_ops[i]);
6828 + ipt_unregister_table(&packet_raw);
6833 +MODULE_LICENSE("GPL");
6834 +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6835 +MODULE_DESCRIPTION("IPv4 raw table");
6836 diff -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 @@
6841 To compile it as a module, choose M here. If unsure, say N.
6844 + tristate "Raw table"
6845 + depends on IP6_NF_IPTABLES
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.
6852 + To compile it as a module, choose M here. If unsure, say N.
6854 +config IP6_NF_TARGET_TRACE
6855 + tristate "TRACE target support"
6856 + depends on IP6_NF_RAW
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
6862 + TRACE: tablename/chainname/rulenum
6864 + if the ip6t_LOG target is loaded in.
6866 + To compile it as a module, choose M here. If unsure, say N.
6868 #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
6871 diff -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
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
6884 diff -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
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>
6896 #include <asm/semaphore.h>
6897 #include <linux/proc_fs.h>
6899 +#include <linux/netfilter.h>
6900 #include <linux/netfilter_ipv6/ip6_tables.h>
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",
6910 MODULE_LICENSE("GPL");
6911 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
6912 MODULE_DESCRIPTION("IPv6 packet filter");
6913 @@ -403,6 +413,12 @@
6915 t = ip6t_get_target(e);
6916 IP_NF_ASSERT(t->u.kernel.target);
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);
6923 /* Standard target? */
6924 if (!t->u.kernel.target->target) {
6926 @@ -556,6 +572,29 @@
6927 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
6931 +find_error_target(struct ip6t_entry *s,
6932 + struct ip6t_entry *e,
6935 + struct ip6t_entry_target *t;
6936 + static struct ip6t_entry *found = NULL;
6941 + t = ip6t_get_target(found);
6942 + if (strcmp(t->u.user.name,
6943 + IP6T_ERROR_TARGET) == 0) {
6944 + *chainname = t->data;
6953 /* All zeroes == unconditional rule. */
6955 unconditional(const struct ip6t_ip6 *ipv6)
6957 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
6960 + char *chainname = NULL;
6961 + u_int32_t rulenum;
6963 /* No recursion; use packet counter to save back ptrs (reset
6964 to 0 as we leave), and comefrom to save source hook bitmask */
6967 /* Set initial back pointer. */
6968 e->counters.pcnt = pos;
6970 + chainname = (char *) hook6names[hook];
6973 struct ip6t_standard_target *t
6977 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
6978 + e->rulenum = rulenum++;
6979 + e->chainname = chainname;
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;
6987 + /* Set unconditional rulenum to zero. */
6989 + e->counters.bcnt = 0;
6991 /* Return: backtrack through the last
6994 @@ -634,6 +683,11 @@
6995 (newinfo->entries + pos);
6996 } while (oldpos == pos + e->next_offset);
6998 + /* Restore chainname, rulenum. */
6999 + chainname = e->chainname;
7000 + rulenum = e->counters.bcnt;
7001 + e->counters.bcnt = 0;
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",
7010 + e->counters.bcnt = rulenum++;
7012 + e = (struct ip6t_entry *)
7013 + (newinfo->entries + newpos);
7014 + if (IP6T_ENTRY_ITERATE(newinfo->entries,
7016 + find_error_target,
7017 + e, &chainname) == 0) {
7018 + printk("ip6_tables: table screwed up!\n");
7022 /* ... this is a fallthru */
7023 newpos = pos + e->next_offset;
7024 diff -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
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>
7041 MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
7042 MODULE_DESCRIPTION("IP6 tables LOG target module");
7043 MODULE_LICENSE("GPL");
7045 +static unsigned int nflog = 1;
7046 +MODULE_PARM(nflog, "i");
7047 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
7050 #include <net/route.h>
7051 #include <linux/netfilter_ipv6/ip6t_LOG.h>
7052 @@ -256,40 +262,38 @@
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,
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)
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;
7077 - level_string[1] = '0' + (loginfo->level % 8);
7078 spin_lock_bh(&log_lock);
7079 printk(level_string);
7080 printk("%sIN=%s OUT=%s ",
7082 + prefix == NULL ? loginfo->prefix : prefix,
7084 out ? out->name : "");
7086 /* MAC logging for input chain only. */
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){
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
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 ){
7108 for (i = 0; i < (ETH_ALEN); i++,p++)
7109 printk("%02x%s", *p,
7110 @@ -300,10 +304,10 @@
7111 i == ETH_ALEN-1 ? ' ' : ':');
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){
7119 - p = (*pskb)->mac.raw + 12;
7120 + p = skb->mac.raw + 12;
7121 for (i = 0; i < 4; i++,p++)
7123 i == 3 ? "->" : ".");
7124 @@ -319,10 +323,41 @@
7125 dump_packet(loginfo, ipv6h, 1);
7127 spin_unlock_bh(&log_lock);
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,
7138 + const struct ip6t_log_info *loginfo = targinfo;
7139 + char level_string[4] = "< >";
7141 + level_string[1] = '0' + (loginfo->level % 8);
7142 + ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
7144 return IP6T_CONTINUE;
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)
7154 + struct ip6t_log_info loginfo = {
7156 + .logflags = IP6T_LOG_MASK,
7160 + ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
7163 static int ip6t_log_checkentry(const char *tablename,
7164 const struct ip6t_entry *e,
7166 @@ -359,12 +394,17 @@
7168 if (ip6t_register_target(&ip6t_log_reg))
7171 + nf_log_register(PF_INET6, &ip6t_logfn);
7176 static void __exit fini(void)
7179 + nf_log_register(PF_INET6, &ip6t_logfn);
7181 ip6t_unregister_target(&ip6t_log_reg);
7184 diff -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
7188 +/* This is a module which is used for setting
7189 + * the NFC_TRACE flag in the nfcache field of an skb.
7191 +#include <linux/module.h>
7192 +#include <linux/skbuff.h>
7194 +#include <linux/netfilter_ipv6/ip6_tables.h>
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,
7204 + (*pskb)->nfcache |= NFC_TRACE;
7205 + return IP6T_CONTINUE;
7209 +checkentry(const char *tablename,
7210 + const struct ip6t_entry *e,
7212 + unsigned int targinfosize,
7213 + unsigned int hook_mask)
7215 + if (targinfosize != 0) {
7216 + printk(KERN_WARNING "TRACE: targinfosize %u != 0\n",
7221 + if (strcmp(tablename, "raw") != 0) {
7222 + printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename);
7229 +static struct ip6t_target ip6t_trace_reg = {
7232 + .checkentry = checkentry,
7234 + .me = THIS_MODULE,
7237 +static int __init init(void)
7239 + if (ip6t_register_target(&ip6t_trace_reg))
7245 +static void __exit fini(void)
7247 + ip6t_unregister_target(&ip6t_trace_reg);
7253 +MODULE_LICENSE("GPL");
7254 +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
7255 +MODULE_DESCRIPTION("IPv6 TRACE target");
7257 \ No newline at end of file
7258 diff -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
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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 } },
7297 diff -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
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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)), "" } }, { } },
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 } },
7354 diff -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
7359 + * IPv6 raw table, a port of the IPv4 raw table to IPv6
7361 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
7363 +#include <linux/module.h>
7364 +#include <linux/netfilter_ipv6/ip6_tables.h>
7366 +#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
7369 +#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
7371 +#define DEBUGP(x, args...)
7374 +/* Standard entry. */
7375 +struct ip6t_standard
7377 + struct ip6t_entry entry;
7378 + struct ip6t_standard_target target;
7381 +struct ip6t_error_target
7383 + struct ip6t_entry_target target;
7384 + char errorname[IP6T_FUNCTION_MAXNAMELEN];
7389 + struct ip6t_entry entry;
7390 + struct ip6t_error_target target;
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) },
7408 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 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 } },
7416 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 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 } },
7425 + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 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 } },
7437 +static struct ip6t_table packet_raw = {
7439 + .table = &initial_table.repl,
7440 + .valid_hooks = RAW_VALID_HOOKS,
7441 + .lock = RW_LOCK_UNLOCKED,
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 *))
7453 + return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
7456 +static struct nf_hook_ops ip6t_ops[] = {
7457 + { /* PRE_ROUTING */
7458 + .hook = ip6t_hook,
7459 + .owner = THIS_MODULE,
7461 + .hooknum = NF_IP6_PRE_ROUTING,
7462 + .priority = NF_IP6_PRI_FIRST,
7465 + .hook = ip6t_hook,
7466 + .owner = THIS_MODULE,
7468 + .hooknum = NF_IP6_LOCAL_OUT,
7469 + .priority = NF_IP6_PRI_FIRST,
7473 +static int __init init(void)
7477 + /* Register table */
7478 + ret = ip6t_register_table(&packet_raw);
7482 + /* Register hooks */
7483 + ret = nf_register_hook(&ip6t_ops[0]);
7485 + goto cleanup_table;
7487 + ret = nf_register_hook(&ip6t_ops[1]);
7489 + goto cleanup_hook0;
7494 + nf_unregister_hook(&ip6t_ops[0]);
7496 + ip6t_unregister_table(&packet_raw);
7501 +static void __exit fini(void)
7505 + for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
7506 + nf_unregister_hook(&ip6t_ops[i]);
7508 + ip6t_unregister_table(&packet_raw);
7513 +MODULE_LICENSE("GPL");
7514 +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
7515 +MODULE_DESCRIPTION("IPv6 raw table");
7516 diff -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
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