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