]>
Commit | Line | Data |
---|---|---|
c6410bf7 | 1 | Kconfig | 17 +++ |
2 | Makefile | 1 | |
3 | ipt_TARPIT.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
4 | 3 files changed, 314 insertions(+) | |
5 | ||
6 | diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig | |
7 | --- linux.org/net/ipv4/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200 | |
8 | +++ linux/net/ipv4/netfilter/Kconfig 2006-05-04 11:21:59.000000000 +0200 | |
9 | @@ -606,5 +606,22 @@ | |
10 | Allows altering the ARP packet payload: source and destination | |
11 | hardware and network addresses. | |
12 | ||
13 | +config IP_NF_TARGET_TARPIT | |
14 | + tristate 'TARPIT target support' | |
15 | + depends on IP_NF_FILTER | |
16 | + help | |
17 | + Adds a TARPIT target to iptables, which captures and holds | |
18 | + incoming TCP connections using no local per-connection resources. | |
19 | + Connections are accepted, but immediately switched to the persist | |
20 | + state (0 byte window), in which the remote side stops sending data | |
21 | + and asks to continue every 60-240 seconds. Attempts to close the | |
22 | + connection are ignored, forcing the remote side to time out the | |
23 | + connection in 12-24 minutes. | |
24 | + | |
25 | + This offers similar functionality to LaBrea | |
26 | + <http://www.hackbusters.net/LaBrea/> but doesn't require dedicated | |
27 | + hardware or IPs. Any TCP port that you would normally DROP or REJECT | |
28 | + can instead become a tarpit. | |
29 | + | |
30 | endmenu | |
31 | ||
32 | diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile | |
33 | --- linux.org/net/ipv4/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200 | |
34 | +++ linux/net/ipv4/netfilter/Makefile 2006-05-04 11:21:59.000000000 +0200 | |
35 | @@ -0,0 +0,1 @@ | |
36 | +obj-$(CONFIG_IP_NF_TARGET_TARPIT) += ipt_TARPIT.o | |
37 | diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_TARPIT.c linux/net/ipv4/netfilter/ipt_TARPIT.c | |
38 | --- linux.org/net/ipv4/netfilter/ipt_TARPIT.c 1970-01-01 01:00:00.000000000 +0100 | |
39 | +++ linux/net/ipv4/netfilter/ipt_TARPIT.c 2006-05-04 11:21:59.000000000 +0200 | |
40 | @@ -0,0 +1,296 @@ | |
41 | +/* | |
42 | + * Kernel module to capture and hold incoming TCP connections using | |
43 | + * no local per-connection resources. | |
44 | + * | |
45 | + * Based on ipt_REJECT.c and offering functionality similar to | |
46 | + * LaBrea <http://www.hackbusters.net/LaBrea/>. | |
47 | + * | |
48 | + * Copyright (c) 2002 Aaron Hopkins <tools@die.net> | |
49 | + * | |
50 | + * This program is free software; you can redistribute it and/or modify | |
51 | + * it under the terms of the GNU General Public License as published by | |
52 | + * the Free Software Foundation; either version 2 of the License, or | |
53 | + * (at your option) any later version. | |
54 | + * | |
55 | + * This program is distributed in the hope that it will be useful, | |
56 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
57 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
58 | + * GNU General Public License for more details. | |
59 | + * | |
60 | + * You should have received a copy of the GNU General Public License | |
61 | + * along with this program; if not, write to the Free Software | |
62 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
63 | + * | |
64 | + * Goal: | |
65 | + * - Allow incoming TCP connections to be established. | |
66 | + * - Passing data should result in the connection being switched to the | |
67 | + * persist state (0 byte window), in which the remote side stops sending | |
68 | + * data and asks to continue every 60 seconds. | |
69 | + * - Attempts to shut down the connection should be ignored completely, so | |
70 | + * the remote side ends up having to time it out. | |
71 | + * | |
72 | + * This means: | |
73 | + * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes | |
74 | + * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing | |
75 | + * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited | |
76 | + */ | |
77 | + | |
78 | +#include <linux/config.h> | |
79 | +#include <linux/version.h> | |
80 | +#include <linux/module.h> | |
81 | +#include <linux/skbuff.h> | |
82 | +#include <linux/ip.h> | |
83 | +#include <net/ip.h> | |
84 | +#include <net/tcp.h> | |
85 | +#include <net/icmp.h> | |
86 | +struct in_device; | |
87 | +#include <net/route.h> | |
88 | +#include <linux/random.h> | |
89 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
90 | + | |
91 | +#if 0 | |
92 | +#define DEBUGP printk | |
93 | +#else | |
94 | +#define DEBUGP(format, args...) | |
95 | +#endif | |
96 | + | |
97 | +MODULE_LICENSE("GPL"); | |
98 | +MODULE_AUTHOR("Aaron Hopkins <tools@die.net>"); | |
99 | + | |
100 | +/* Stolen from ip_finish_output2 */ | |
101 | +static int ip_direct_send(struct sk_buff *skb) | |
102 | +{ | |
103 | + struct dst_entry *dst = skb->dst; | |
104 | + struct hh_cache *hh = dst->hh; | |
105 | + | |
106 | + if (hh) { | |
107 | + read_lock_bh(&hh->hh_lock); | |
108 | + memcpy(skb->data - 16, hh->hh_data, 16); | |
109 | + read_unlock_bh(&hh->hh_lock); | |
110 | + skb_push(skb, hh->hh_len); | |
111 | + return hh->hh_output(skb); | |
112 | + } else if (dst->neighbour) | |
113 | + return dst->neighbour->output(skb); | |
114 | + | |
115 | + if (net_ratelimit()) | |
116 | + printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n"); | |
117 | + kfree_skb(skb); | |
118 | + return -EINVAL; | |
119 | +} | |
120 | + | |
121 | + | |
122 | +/* Send reply */ | |
123 | +static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local) | |
124 | +{ | |
125 | + struct sk_buff *nskb; | |
126 | + struct rtable *nrt; | |
127 | + struct tcphdr *otcph, *ntcph; | |
128 | + struct flowi fl = {}; | |
129 | + unsigned int otcplen; | |
130 | + u_int16_t tmp; | |
131 | + | |
132 | + /* A truncated TCP header isn't going to be useful */ | |
133 | + if (oskb->len < (oskb->nh.iph->ihl*4) + sizeof(struct tcphdr)) | |
134 | + return; | |
135 | + | |
136 | + otcph = (struct tcphdr *)((u_int32_t*)oskb->nh.iph | |
137 | + + oskb->nh.iph->ihl); | |
138 | + otcplen = oskb->len - oskb->nh.iph->ihl*4; | |
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(otcph, otcplen, oskb->nh.iph->saddr, | |
150 | + oskb->nh.iph->daddr, | |
151 | + csum_partial((char *)otcph, otcplen, 0)) != 0) | |
152 | + return; | |
153 | + | |
154 | + /* Copy skb (even if skb is about to be dropped, we can't just | |
155 | + clone it because there may be other things, such as tcpdump, | |
156 | + interested in it) */ | |
157 | + nskb = skb_copy(oskb, GFP_ATOMIC); | |
158 | + if (!nskb) | |
159 | + return; | |
160 | + | |
161 | + /* This packet will not be the same as the other: clear nf fields */ | |
162 | + nf_conntrack_put(nskb->nfct); | |
163 | + nskb->nfct = NULL; | |
164 | +#ifdef CONFIG_NETFILTER_DEBUG | |
165 | + nskb->nf_debug = 0; | |
166 | +#endif | |
167 | + | |
168 | + ntcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); | |
169 | + | |
170 | + /* Truncate to length (no data) */ | |
171 | + ntcph->doff = sizeof(struct tcphdr)/4; | |
172 | + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); | |
173 | + nskb->nh.iph->tot_len = htons(nskb->len); | |
174 | + | |
175 | + /* Swap source and dest */ | |
176 | + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); | |
177 | + tmp = ntcph->source; | |
178 | + ntcph->source = ntcph->dest; | |
179 | + ntcph->dest = tmp; | |
180 | + | |
181 | + /* Use supplied sequence number or make a new one */ | |
182 | + ntcph->seq = otcph->ack ? otcph->ack_seq | |
183 | + : htonl(secure_tcp_sequence_number(nskb->nh.iph->saddr, | |
184 | + nskb->nh.iph->daddr, | |
185 | + ntcph->source, | |
186 | + ntcph->dest)); | |
187 | + | |
188 | + /* Our SYN-ACKs must have a >0 window */ | |
189 | + ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0; | |
190 | + | |
191 | + ntcph->urg_ptr = 0; | |
192 | + | |
193 | + /* Reset flags */ | |
194 | + ((u_int8_t *)ntcph)[13] = 0; | |
195 | + | |
196 | + if (otcph->syn && otcph->ack) { | |
197 | + ntcph->rst = 1; | |
198 | + ntcph->ack_seq = 0; | |
199 | + } else { | |
200 | + ntcph->syn = otcph->syn; | |
201 | + ntcph->ack = 1; | |
202 | + ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn); | |
203 | + } | |
204 | + | |
205 | + /* Adjust TCP checksum */ | |
206 | + ntcph->check = 0; | |
207 | + ntcph->check = tcp_v4_check(ntcph, sizeof(struct tcphdr), | |
208 | + nskb->nh.iph->saddr, | |
209 | + nskb->nh.iph->daddr, | |
210 | + csum_partial((char *)ntcph, | |
211 | + sizeof(struct tcphdr), 0)); | |
212 | + | |
213 | + fl.nl_u.ip4_u.daddr = nskb->nh.iph->daddr; | |
214 | + fl.nl_u.ip4_u.saddr = local ? nskb->nh.iph->saddr : 0; | |
215 | + fl.nl_u.ip4_u.tos = RT_TOS(nskb->nh.iph->tos) | RTO_CONN; | |
216 | + fl.oif = 0; | |
217 | + | |
218 | + if (ip_route_output_key(&nrt, &fl)) | |
219 | + goto free_nskb; | |
220 | + | |
221 | + dst_release(nskb->dst); | |
222 | + nskb->dst = &nrt->u.dst; | |
223 | + | |
224 | + /* Adjust IP TTL */ | |
225 | + nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); | |
226 | + | |
227 | + /* Set DF, id = 0 */ | |
228 | + nskb->nh.iph->frag_off = htons(IP_DF); | |
229 | + nskb->nh.iph->id = 0; | |
230 | + | |
231 | + /* Adjust IP checksum */ | |
232 | + nskb->nh.iph->check = 0; | |
233 | + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, | |
234 | + nskb->nh.iph->ihl); | |
235 | + | |
236 | + /* "Never happens" */ | |
237 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) | |
238 | + if (nskb->len > dst_mtu(nskb->dst)) | |
239 | +#else | |
240 | + if (nskb->len > dst_pmtu(nskb->dst)) | |
241 | +#endif | |
242 | + goto free_nskb; | |
243 | + | |
244 | + ip_direct_send (nskb); | |
245 | + | |
246 | + return; | |
247 | + | |
248 | + free_nskb: | |
249 | + kfree_skb(nskb); | |
250 | +} | |
251 | + | |
252 | + | |
253 | +static unsigned int tarpit(struct sk_buff **pskb, | |
254 | + const struct net_device *in, | |
255 | + const struct net_device *out, | |
256 | + unsigned int hooknum, | |
257 | + const void *targinfo, | |
258 | + void *userinfo) | |
259 | +{ | |
260 | + struct sk_buff *skb = *pskb; | |
261 | + struct rtable *rt = (struct rtable*)skb->dst; | |
262 | + | |
263 | + /* Do we have an input route cache entry? */ | |
264 | + if (!rt) | |
265 | + return NF_DROP; | |
266 | + | |
267 | + /* No replies to physical multicast/broadcast */ | |
268 | + if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST) | |
269 | + return NF_DROP; | |
270 | + | |
271 | + /* Now check at the protocol level */ | |
272 | + if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) | |
273 | + return NF_DROP; | |
274 | + | |
275 | + /* Our naive response construction doesn't deal with IP | |
276 | + options, and probably shouldn't try. */ | |
277 | + if (skb->nh.iph->ihl*4 != sizeof(struct iphdr)) | |
278 | + return NF_DROP; | |
279 | + | |
280 | + /* We aren't interested in fragments */ | |
281 | + if (skb->nh.iph->frag_off & htons(IP_OFFSET)) | |
282 | + return NF_DROP; | |
283 | + | |
284 | + tarpit_tcp(skb,rt,hooknum == NF_IP_LOCAL_IN); | |
285 | + | |
286 | + return NF_DROP; | |
287 | +} | |
288 | + | |
289 | + | |
290 | +static int check(const char *tablename, | |
291 | + const void *e_void, | |
292 | + void *targinfo, | |
293 | + unsigned int targinfosize, | |
294 | + unsigned int hook_mask) | |
295 | +{ | |
296 | + const struct ipt_entry *e = e_void; | |
297 | + | |
298 | + /* Only allow these for input/forward packet filtering. */ | |
299 | + if (strcmp(tablename, "filter") != 0) { | |
300 | + DEBUGP("TARPIT: bad table %s'.\n", tablename); | |
301 | + return 0; | |
302 | + } | |
303 | + if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) | |
304 | + | (1 << NF_IP_FORWARD))) != 0) { | |
305 | + DEBUGP("TARPIT: bad hook mask %X\n", hook_mask); | |
306 | + return 0; | |
307 | + } | |
308 | + | |
309 | + /* Must specify that it's a TCP packet */ | |
310 | + if (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO)) { | |
311 | + DEBUGP("TARPIT: not valid for non-tcp\n"); | |
312 | + return 0; | |
313 | + } | |
314 | + | |
315 | + return 1; | |
316 | +} | |
317 | + | |
318 | +static struct ipt_target ipt_tarpit_reg = { | |
319 | + .name = "TARPIT", | |
320 | + .target = tarpit, | |
321 | + .checkentry = check, | |
322 | + .me = THIS_MODULE | |
323 | +}; | |
324 | + | |
325 | +static int __init init(void) | |
326 | +{ | |
327 | + return ipt_register_target(&ipt_tarpit_reg); | |
328 | +} | |
329 | + | |
330 | +static void __exit fini(void) | |
331 | +{ | |
332 | + ipt_unregister_target(&ipt_tarpit_reg); | |
333 | +} | |
334 | + | |
335 | +module_init(init); | |
336 | +module_exit(fini); |