[kernel] refresh generic 2.6.22 patches
[openwrt.git] / target / linux / generic-2.6 / patches-2.6.22 / 171-netfilter_tarpit.patch
1 Index: linux-2.6.22.19/net/netfilter/Kconfig
2 ===================================================================
3 --- linux-2.6.22.19.orig/net/netfilter/Kconfig
4 +++ linux-2.6.22.19/net/netfilter/Kconfig
5 @@ -379,6 +379,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.22.19/net/netfilter/Makefile
30 ===================================================================
31 --- linux-2.6.22.19.orig/net/netfilter/Makefile
32 +++ linux-2.6.22.19/net/netfilter/Makefile
33 @@ -45,6 +45,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE
34  obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
35  obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.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  obj-$(CONFIG_NETFILTER_XT_TARGET_CHAOS) += xt_CHAOS.o
41 Index: linux-2.6.22.19/net/netfilter/xt_TARPIT.c
42 ===================================================================
43 --- /dev/null
44 +++ linux-2.6.22.19/net/netfilter/xt_TARPIT.c
45 @@ -0,0 +1,280 @@
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 **pskb,
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 sk_buff *skb = *pskb;
257 +       const struct iphdr *iph   = ip_hdr(skb);
258 +       struct rtable *rt         = (void *)skb->dst;
259 +
260 +       /* Do we have an input route cache entry? */
261 +       if (rt == NULL)
262 +               return NF_DROP;
263 +
264 +       /* No replies to physical multicast/broadcast */
265 +       if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST)
266 +               return NF_DROP;
267 +
268 +       /* Now check at the protocol level */
269 +       if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
270 +               return NF_DROP;
271 +
272 +       /*
273 +        * Our naive response construction does not deal with IP
274 +        * options, and probably should not try.
275 +        */
276 +       if (iph->ihl * 4 != sizeof(struct iphdr))
277 +               return NF_DROP;
278 +
279 +       /* We are not interested in fragments */
280 +       if (iph->frag_off & htons(IP_OFFSET))
281 +               return NF_DROP;
282 +
283 +       tarpit_tcp(skb, rt, hooknum == NF_IP_LOCAL_IN);
284 +       return NF_DROP;
285 +}
286 +
287 +static int xt_tarpit_check(const char *tablename, const void *entry,
288 +                            const struct xt_target *target, void *targinfo,
289 +                            unsigned int hook_mask)
290 +{
291 +       bool invalid;
292 +
293 +       if (strcmp(tablename, "raw") == 0 && hook_mask == NF_IP_PRE_ROUTING)
294 +               return true;
295 +       if (strcmp(tablename, "filter") != 0)
296 +               return false;
297 +       invalid = hook_mask & ~((1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD));
298 +       return !invalid;
299 +}
300 +
301 +static struct xt_target xt_tarpit_reg = {
302 +       .name       = "TARPIT",
303 +       .family     = AF_INET,
304 +       .proto      = IPPROTO_TCP,
305 +       .target     = xt_tarpit_target,
306 +       .checkentry = xt_tarpit_check,
307 +       .me         = THIS_MODULE,
308 +};
309 +
310 +static int __init xt_tarpit_init(void)
311 +{
312 +       return xt_register_target(&xt_tarpit_reg);
313 +}
314 +
315 +static void __exit xt_tarpit_exit(void)
316 +{
317 +       xt_unregister_target(&xt_tarpit_reg);
318 +}
319 +
320 +module_init(xt_tarpit_init);
321 +module_exit(xt_tarpit_exit);
322 +MODULE_DESCRIPTION("netfilter xt_TARPIT target module");
323 +MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
324 +MODULE_LICENSE("GPL");
325 +MODULE_ALIAS("ipt_TARPIT");