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