3 ipt_TARPIT.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 3 files changed, 314 insertions(+)
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
10 Allows altering the ARP packet payload: source and destination
11 hardware and network addresses.
13 +config IP_NF_TARGET_TARPIT
14 + tristate 'TARPIT target support'
15 + depends on IP_NF_FILTER
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.
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.
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
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
42 + * Kernel module to capture and hold incoming TCP connections using
43 + * no local per-connection resources.
45 + * Based on ipt_REJECT.c and offering functionality similar to
46 + * LaBrea <http://www.hackbusters.net/LaBrea/>.
48 + * Copyright (c) 2002 Aaron Hopkins <tools@die.net>
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.
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.
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.
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.
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
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>
85 +#include <net/icmp.h>
87 +#include <net/route.h>
88 +#include <linux/random.h>
89 +#include <linux/netfilter_ipv4/ip_tables.h>
92 +#define DEBUGP printk
94 +#define DEBUGP(format, args...)
97 +MODULE_LICENSE("GPL");
98 +MODULE_AUTHOR("Aaron Hopkins <tools@die.net>");
100 +/* Stolen from ip_finish_output2 */
101 +static int ip_direct_send(struct sk_buff *skb)
103 + struct dst_entry *dst = skb->dst;
104 + struct hh_cache *hh = dst->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);
115 + if (net_ratelimit())
116 + printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n");
123 +static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local)
125 + struct sk_buff *nskb;
126 + struct rtable *nrt;
127 + struct tcphdr *otcph, *ntcph;
128 + struct flowi fl = {};
129 + unsigned int otcplen;
132 + /* A truncated TCP header isn't going to be useful */
133 + if (oskb->len < (oskb->nh.iph->ihl*4) + sizeof(struct tcphdr))
136 + otcph = (struct tcphdr *)((u_int32_t*)oskb->nh.iph
137 + + oskb->nh.iph->ihl);
138 + otcplen = oskb->len - oskb->nh.iph->ihl*4;
140 + /* No replies for RST or FIN */
141 + if (otcph->rst || otcph->fin)
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)))
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)
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);
161 + /* This packet will not be the same as the other: clear nf fields */
162 + nf_conntrack_put(nskb->nfct);
164 +#ifdef CONFIG_NETFILTER_DEBUG
165 + nskb->nf_debug = 0;
168 + ntcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
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);
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;
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,
188 + /* Our SYN-ACKs must have a >0 window */
189 + ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0;
191 + ntcph->urg_ptr = 0;
194 + ((u_int8_t *)ntcph)[13] = 0;
196 + if (otcph->syn && otcph->ack) {
198 + ntcph->ack_seq = 0;
200 + ntcph->syn = otcph->syn;
202 + ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn);
205 + /* Adjust TCP checksum */
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));
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;
218 + if (ip_route_output_key(&nrt, &fl))
221 + dst_release(nskb->dst);
222 + nskb->dst = &nrt->u.dst;
224 + /* Adjust IP TTL */
225 + nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
227 + /* Set DF, id = 0 */
228 + nskb->nh.iph->frag_off = htons(IP_DF);
229 + nskb->nh.iph->id = 0;
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);
236 + /* "Never happens" */
237 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
238 + if (nskb->len > dst_mtu(nskb->dst))
240 + if (nskb->len > dst_pmtu(nskb->dst))
244 + ip_direct_send (nskb);
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,
260 + struct sk_buff *skb = *pskb;
261 + struct rtable *rt = (struct rtable*)skb->dst;
263 + /* Do we have an input route cache entry? */
267 + /* No replies to physical multicast/broadcast */
268 + if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST)
271 + /* Now check at the protocol level */
272 + if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
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))
280 + /* We aren't interested in fragments */
281 + if (skb->nh.iph->frag_off & htons(IP_OFFSET))
284 + tarpit_tcp(skb,rt,hooknum == NF_IP_LOCAL_IN);
290 +static int check(const char *tablename,
291 + const void *e_void,
293 + unsigned int targinfosize,
294 + unsigned int hook_mask)
296 + const struct ipt_entry *e = e_void;
298 + /* Only allow these for input/forward packet filtering. */
299 + if (strcmp(tablename, "filter") != 0) {
300 + DEBUGP("TARPIT: bad table %s'.\n", tablename);
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);
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");
318 +static struct ipt_target ipt_tarpit_reg = {
321 + .checkentry = check,
325 +static int __init init(void)
327 + return ipt_register_target(&ipt_tarpit_reg);
330 +static void __exit fini(void)
332 + ipt_unregister_target(&ipt_tarpit_reg);