[8.09] kernel: refresh patches
[openwrt/svn-archive/archive.git] / target / linux / generic-2.6 / patches-2.6.23 / 171-netfilter_tarpit.patch
1 --- a/net/netfilter/Kconfig
2 +++ b/net/netfilter/Kconfig
3 @@ -401,6 +401,23 @@ config NETFILTER_XT_TARGET_CONNSECMARK
4
5 To compile it as a module, choose M here. If unsure, say N.
6
7 +config NETFILTER_XT_TARGET_TARPIT
8 + tristate '"TARPIT" target support'
9 + depends on NETFILTER_XTABLES
10 + ---help---
11 + Adds a TARPIT target to iptables, which captures and holds
12 + incoming TCP connections using no local per-connection resources.
13 + Connections are accepted, but immediately switched to the persist
14 + state (0 byte window), in which the remote side stops sending data
15 + and asks to continue every 60-240 seconds. Attempts to close the
16 + connection are ignored, forcing the remote side to time out the
17 + connection in 12-24 minutes.
18 +
19 + This offers similar functionality to LaBrea
20 + <http://www.hackbusters.net/LaBrea/>, but does not require dedicated
21 + hardware or IPs. Any TCP port that you would normally DROP or REJECT
22 + can instead become a tarpit.
23 +
24 config NETFILTER_XT_TARGET_TCPMSS
25 tristate '"TCPMSS" target support'
26 depends on NETFILTER_XTABLES && (IPV6 || IPV6=n)
27 --- a/net/netfilter/Makefile
28 +++ b/net/netfilter/Makefile
29 @@ -47,6 +47,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG)
30 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
31 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
32 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
33 +obj-$(CONFIG_NETFILTER_XT_TARGET_TARPIT) += xt_TARPIT.o
34 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
35 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
36 obj-$(CONFIG_NETFILTER_XT_TARGET_CHAOS) += xt_CHAOS.o
37 --- /dev/null
38 +++ b/net/netfilter/xt_TARPIT.c
39 @@ -0,0 +1,280 @@
40 +/*
41 + * Kernel module to capture and hold incoming TCP connections using
42 + * no local per-connection resources.
43 + *
44 + * Based on ipt_REJECT.c and offering functionality similar to
45 + * LaBrea <http://www.hackbusters.net/LaBrea/>.
46 + *
47 + * Copyright (c) 2002 Aaron Hopkins <tools@die.net>
48 + *
49 + * This program is free software; you can redistribute it and/or modify
50 + * it under the terms of the GNU General Public License as published by
51 + * the Free Software Foundation; either version 2 of the License, or
52 + * (at your option) any later version.
53 + *
54 + * This program is distributed in the hope that it will be useful,
55 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
56 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57 + * GNU General Public License for more details.
58 + *
59 + * You should have received a copy of the GNU General Public License
60 + * along with this program; if not, write to the Free Software
61 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
62 + *
63 + * Goal:
64 + * - Allow incoming TCP connections to be established.
65 + * - Passing data should result in the connection being switched to the
66 + * persist state (0 byte window), in which the remote side stops sending
67 + * data and asks to continue every 60 seconds.
68 + * - Attempts to shut down the connection should be ignored completely, so
69 + * the remote side ends up having to time it out.
70 + *
71 + * This means:
72 + * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes
73 + * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing
74 + * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited
75 + */
76 +
77 +#include <linux/version.h>
78 +#include <linux/module.h>
79 +#include <linux/skbuff.h>
80 +#include <linux/ip.h>
81 +#include <net/ip.h>
82 +#include <net/tcp.h>
83 +#include <net/icmp.h>
84 +struct in_device;
85 +#include <net/route.h>
86 +#include <linux/random.h>
87 +#include <linux/netfilter_ipv4/ip_tables.h>
88 +
89 +#if 0
90 +#define DEBUGP printk
91 +#else
92 +#define DEBUGP(format, args...)
93 +#endif
94 +
95 +/* Stolen from ip_finish_output2 */
96 +static int ip_direct_send(struct sk_buff *skb)
97 +{
98 + struct dst_entry *dst = skb->dst;
99 +
100 + if (dst->hh != NULL)
101 + return neigh_hh_output(dst->hh, skb);
102 + else if (dst->neighbour != NULL)
103 + return dst->neighbour->output(skb);
104 +
105 + if (net_ratelimit())
106 + printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n");
107 +
108 + kfree_skb(skb);
109 + return -EINVAL;
110 +}
111 +
112 +
113 +/* Send reply */
114 +static void tarpit_tcp(const struct sk_buff *oskb, struct rtable *ort,
115 + unsigned int local)
116 +{
117 + struct sk_buff *nskb;
118 + struct rtable *nrt;
119 + struct tcphdr *otcph, *ntcph;
120 + struct flowi fl = {};
121 + unsigned int otcplen;
122 + u_int16_t tmp;
123 +
124 + const struct iphdr *oiph = ip_hdr(oskb);
125 + struct iphdr *niph;
126 +
127 + /* A truncated TCP header is not going to be useful */
128 + if (oskb->len < ip_hdrlen(oskb) + sizeof(struct tcphdr))
129 + return;
130 +
131 + otcph = (void *)oiph + ip_hdrlen(oskb);
132 + otcplen = oskb->len - ip_hdrlen(oskb);
133 +
134 + /* No replies for RST or FIN */
135 + if (otcph->rst || otcph->fin)
136 + return;
137 +
138 + /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */
139 + if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ)))
140 + return;
141 +
142 + /* Check checksum. */
143 + if (tcp_v4_check(otcplen, oiph->saddr, oiph->daddr,
144 + csum_partial((char *)otcph, otcplen, 0)) != 0)
145 + return;
146 +
147 + /*
148 + * Copy skb (even if skb is about to be dropped, we cannot just
149 + * clone it because there may be other things, such as tcpdump,
150 + * interested in it)
151 + */
152 + nskb = skb_copy(oskb, GFP_ATOMIC);
153 + if (nskb == NULL)
154 + return;
155 +
156 + niph = ip_hdr(nskb);
157 +
158 + /* This packet will not be the same as the other: clear nf fields */
159 + nf_conntrack_put(nskb->nfct);
160 + nskb->nfct = NULL;
161 +#ifdef CONFIG_NETFILTER_DEBUG
162 + nskb->nf_debug = 0;
163 +#endif
164 +
165 + ntcph = (void *)niph + ip_hdrlen(nskb);
166 +
167 + /* Truncate to length (no data) */
168 + ntcph->doff = sizeof(struct tcphdr)/4;
169 + skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
170 + niph->tot_len = htons(nskb->len);
171 +
172 + /* Swap source and dest */
173 + niph->daddr = xchg(&niph->saddr, niph->daddr);
174 + tmp = ntcph->source;
175 + ntcph->source = ntcph->dest;
176 + ntcph->dest = tmp;
177 +
178 + /* Use supplied sequence number or make a new one */
179 + ntcph->seq = otcph->ack ? otcph->ack_seq
180 + : htonl(secure_tcp_sequence_number(niph->saddr,
181 + niph->daddr,
182 + ntcph->source,
183 + ntcph->dest));
184 +
185 + /* Our SYN-ACKs must have a >0 window */
186 + ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0;
187 +
188 + ntcph->urg_ptr = 0;
189 +
190 + /* Reset flags */
191 + ((u_int8_t *)ntcph)[13] = 0;
192 +
193 + if (otcph->syn && otcph->ack) {
194 + ntcph->rst = 1;
195 + ntcph->ack_seq = 0;
196 + } else {
197 + ntcph->syn = otcph->syn;
198 + ntcph->ack = 1;
199 + ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn);
200 + }
201 +
202 + /* Adjust TCP checksum */
203 + ntcph->check = 0;
204 + ntcph->check = tcp_v4_check(sizeof(struct tcphdr),
205 + niph->saddr,
206 + niph->daddr,
207 + csum_partial((char *)ntcph,
208 + sizeof(struct tcphdr), 0));
209 +
210 + fl.nl_u.ip4_u.daddr = niph->daddr;
211 + fl.nl_u.ip4_u.saddr = local ? niph->saddr : 0;
212 + fl.nl_u.ip4_u.tos = RT_TOS(niph->tos) | RTO_CONN;
213 + fl.oif = 0;
214 +
215 + if (ip_route_output_key(&nrt, &fl))
216 + goto free_nskb;
217 +
218 + dst_release(nskb->dst);
219 + nskb->dst = &nrt->u.dst;
220 +
221 + /* Adjust IP TTL */
222 + niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
223 +
224 + /* Set DF, id = 0 */
225 + niph->frag_off = htons(IP_DF);
226 + niph->id = 0;
227 +
228 + /* Adjust IP checksum */
229 + niph->check = 0;
230 + niph->check = ip_fast_csum((unsigned char *)niph, niph->ihl);
231 +
232 + /* "Never happens" */
233 + if (nskb->len > dst_mtu(nskb->dst))
234 + goto free_nskb;
235 +
236 + ip_direct_send(nskb);
237 + return;
238 +
239 + free_nskb:
240 + kfree_skb(nskb);
241 +}
242 +
243 +static unsigned int xt_tarpit_target(struct sk_buff **pskb,
244 + const struct net_device *in,
245 + const struct net_device *out,
246 + unsigned int hooknum,
247 + const struct xt_target *target,
248 + const void *targinfo)
249 +{
250 + const struct sk_buff *skb = *pskb;
251 + const struct iphdr *iph = ip_hdr(skb);
252 + struct rtable *rt = (void *)skb->dst;
253 +
254 + /* Do we have an input route cache entry? */
255 + if (rt == NULL)
256 + return NF_DROP;
257 +
258 + /* No replies to physical multicast/broadcast */
259 + if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST)
260 + return NF_DROP;
261 +
262 + /* Now check at the protocol level */
263 + if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
264 + return NF_DROP;
265 +
266 + /*
267 + * Our naive response construction does not deal with IP
268 + * options, and probably should not try.
269 + */
270 + if (iph->ihl * 4 != sizeof(struct iphdr))
271 + return NF_DROP;
272 +
273 + /* We are not interested in fragments */
274 + if (iph->frag_off & htons(IP_OFFSET))
275 + return NF_DROP;
276 +
277 + tarpit_tcp(skb, rt, hooknum == NF_IP_LOCAL_IN);
278 + return NF_DROP;
279 +}
280 +
281 +static bool xt_tarpit_check(const char *tablename, const void *entry,
282 + const struct xt_target *target, void *targinfo,
283 + unsigned int hook_mask)
284 +{
285 + bool invalid;
286 +
287 + if (strcmp(tablename, "raw") == 0 && hook_mask == NF_IP_PRE_ROUTING)
288 + return true;
289 + if (strcmp(tablename, "filter") != 0)
290 + return false;
291 + invalid = hook_mask & ~((1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD));
292 + return !invalid;
293 +}
294 +
295 +static struct xt_target xt_tarpit_reg = {
296 + .name = "TARPIT",
297 + .family = AF_INET,
298 + .proto = IPPROTO_TCP,
299 + .target = xt_tarpit_target,
300 + .checkentry = xt_tarpit_check,
301 + .me = THIS_MODULE,
302 +};
303 +
304 +static int __init xt_tarpit_init(void)
305 +{
306 + return xt_register_target(&xt_tarpit_reg);
307 +}
308 +
309 +static void __exit xt_tarpit_exit(void)
310 +{
311 + xt_unregister_target(&xt_tarpit_reg);
312 +}
313 +
314 +module_init(xt_tarpit_init);
315 +module_exit(xt_tarpit_exit);
316 +MODULE_DESCRIPTION("netfilter xt_TARPIT target module");
317 +MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
318 +MODULE_LICENSE("GPL");
319 +MODULE_ALIAS("ipt_TARPIT");