~ubuntu-branches/ubuntu/precise/xtables-addons/precise

« back to all changes in this revision

Viewing changes to extensions/xt_TARPIT.c

  • Committer: Bazaar Package Importer
  • Author(s): Pierre Chifflier
  • Date: 2008-10-27 22:31:20 UTC
  • Revision ID: james.westby@ubuntu.com-20081027223120-njqjsraqjpp7s98t
Tags: upstream-1.5.7
Import upstream version 1.5.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      "TARPIT" target extension to Xtables
 
3
 *      Kernel module to capture and hold incoming TCP connections using
 
4
 *      no local per-connection resources.
 
5
 *
 
6
 *      Copyright © Aaron Hopkins <tools [at] die net>, 2002
 
7
 *
 
8
 *      Based on ipt_REJECT.c and offering functionality similar to
 
9
 *      LaBrea <http://www.hackbusters.net/LaBrea/>.
 
10
 *
 
11
 *      <<<
 
12
 *      This program is free software; you can redistribute it and/or modify
 
13
 *      it under the terms of the GNU General Public License as published by
 
14
 *      the Free Software Foundation; either version 2 of the License, or
 
15
 *      (at your option) any later version.
 
16
 *
 
17
 *      This program is distributed in the hope that it will be useful,
 
18
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
 *      GNU General Public License for more details.
 
21
 *
 
22
 *      You should have received a copy of the GNU General Public License
 
23
 *      along with this program; if not, write to the Free Software
 
24
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
25
 *      >>>
 
26
 *
 
27
 * Goal:
 
28
 * - Allow incoming TCP connections to be established.
 
29
 * - Passing data should result in the connection being switched to the
 
30
 *   persist state (0 byte window), in which the remote side stops sending
 
31
 *   data and asks to continue every 60 seconds.
 
32
 * - Attempts to shut down the connection should be ignored completely, so
 
33
 *   the remote side ends up having to time it out.
 
34
 *
 
35
 * This means:
 
36
 * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes
 
37
 * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing
 
38
 * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited
 
39
 */
 
40
 
 
41
#include <linux/ip.h>
 
42
#include <linux/module.h>
 
43
#include <linux/skbuff.h>
 
44
#include <linux/netfilter/x_tables.h>
 
45
#ifdef CONFIG_BRIDGE_NETFILTER
 
46
#       include <linux/netfilter_bridge.h>
 
47
#endif
 
48
#include <net/route.h>
 
49
#include <net/tcp.h>
 
50
#include "compat_xtables.h"
 
51
 
 
52
static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
 
53
{
 
54
        struct tcphdr _otcph, *oth, *tcph;
 
55
        unsigned int addr_type;
 
56
        struct sk_buff *nskb;
 
57
        struct iphdr *niph;
 
58
        u_int16_t tmp;
 
59
 
 
60
        /* A truncated TCP header is not going to be useful */
 
61
        if (oldskb->len < ip_hdrlen(oldskb) + sizeof(struct tcphdr))
 
62
                return;
 
63
 
 
64
        oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
 
65
                                 sizeof(_otcph), &_otcph);
 
66
        if (oth == NULL)
 
67
                return;
 
68
 
 
69
        /* No replies for RST, FIN or !SYN,!ACK */
 
70
        if (oth->rst || oth->fin || (!oth->syn && !oth->ack))
 
71
                return;
 
72
 
 
73
        /* Rate-limit replies to !SYN,ACKs */
 
74
#if 0
 
75
        if (!oth->syn && oth->ack)
 
76
                if (!xrlim_allow(&ort->u.dst, HZ))
 
77
                        return;
 
78
#endif
 
79
 
 
80
        /* Check checksum. */
 
81
        if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
 
82
                return;
 
83
 
 
84
        /*
 
85
         * Copy skb (even if skb is about to be dropped, we cannot just
 
86
         * clone it because there may be other things, such as tcpdump,
 
87
         * interested in it)
 
88
         */
 
89
        nskb = skb_copy_expand(oldskb, LL_MAX_HEADER,
 
90
                               skb_tailroom(oldskb), GFP_ATOMIC);
 
91
        if (nskb == NULL)
 
92
                return;
 
93
 
 
94
        /* This packet will not be the same as the other: clear nf fields */
 
95
        nf_reset(nskb);
 
96
        skb_nfmark(nskb) = 0;
 
97
        skb_init_secmark(nskb);
 
98
 
 
99
        skb_shinfo(nskb)->gso_size = 0;
 
100
        skb_shinfo(nskb)->gso_segs = 0;
 
101
        skb_shinfo(nskb)->gso_type = 0;
 
102
 
 
103
        tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));
 
104
 
 
105
        /* Swap source and dest */
 
106
        niph         = ip_hdr(nskb);
 
107
        niph->daddr  = xchg(&niph->saddr, niph->daddr);
 
108
        tmp          = tcph->source;
 
109
        tcph->source = tcph->dest;
 
110
        tcph->dest   = tmp;
 
111
 
 
112
        /* Truncate to length (no data) */
 
113
        tcph->doff    = sizeof(struct tcphdr) / 4;
 
114
        skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
 
115
        niph->tot_len = htons(nskb->len);
 
116
 
 
117
        /* Use supplied sequence number or make a new one */
 
118
        tcph->seq = oth->ack ? oth->ack_seq : 0;
 
119
 
 
120
        /* Our SYN-ACKs must have a >0 window */
 
121
        tcph->window  = (oth->syn && !oth->ack) ? htons(5) : 0;
 
122
        tcph->urg_ptr = 0;
 
123
 
 
124
        /* Reset flags */
 
125
        ((u_int8_t *)tcph)[13] = 0;
 
126
 
 
127
        if (oth->syn && oth->ack) {
 
128
                tcph->rst     = true;
 
129
                tcph->ack_seq = false;
 
130
        } else {
 
131
                tcph->syn     = oth->syn;
 
132
                tcph->ack     = 1;
 
133
                tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
 
134
        }
 
135
 
 
136
        /* Adjust TCP checksum */
 
137
        tcph->check = 0;
 
138
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 20)
 
139
        tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), niph->saddr,
 
140
                      niph->daddr, csum_partial((char *)tcph,
 
141
                      sizeof(struct tcphdr), 0));
 
142
#else
 
143
        tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
 
144
                      niph->daddr, csum_partial((char *)tcph,
 
145
                      sizeof(struct tcphdr), 0));
 
146
#endif
 
147
 
 
148
        /* Set DF, id = 0 */
 
149
        niph->frag_off = htons(IP_DF);
 
150
        niph->id       = 0;
 
151
 
 
152
#ifdef CONFIG_BRIDGE_NETFILTER
 
153
        if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
 
154
            nskb->nf_bridge->mask & BRNF_BRIDGED))
 
155
#else
 
156
        if (hook != NF_INET_FORWARD)
 
157
#endif
 
158
                addr_type = RTN_LOCAL;
 
159
 
 
160
        if (ip_route_me_harder(&nskb, addr_type))
 
161
                goto free_nskb;
 
162
        else
 
163
                niph = ip_hdr(nskb);
 
164
 
 
165
        nskb->ip_summed = CHECKSUM_NONE;
 
166
 
 
167
        /* Adjust IP TTL */
 
168
        niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
 
169
 
 
170
        /* Adjust IP checksum */
 
171
        niph->check = 0;
 
172
        niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);
 
173
 
 
174
        /* "Never happens" */
 
175
        if (nskb->len > dst_mtu(nskb->dst))
 
176
                goto free_nskb;
 
177
 
 
178
        nf_ct_attach(nskb, oldskb);
 
179
 
 
180
        NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
 
181
                dst_output);
 
182
        return;
 
183
 
 
184
 free_nskb:
 
185
        kfree_skb(nskb);
 
186
}
 
187
 
 
188
static unsigned int
 
189
tarpit_tg(struct sk_buff **pskb, const struct net_device *in,
 
190
          const struct net_device *out, unsigned int hooknum,
 
191
          const struct xt_target *target, const void *targinfo)
 
192
{
 
193
        const struct sk_buff *skb = *pskb;
 
194
        const struct iphdr *iph = ip_hdr(skb);
 
195
        const struct rtable *rt = (const void *)skb->dst;
 
196
 
 
197
        /* Do we have an input route cache entry? (Not in PREROUTING.) */
 
198
        if (rt == NULL)
 
199
                return NF_DROP;
 
200
 
 
201
        /* No replies to physical multicast/broadcast */
 
202
        /* skb != PACKET_OTHERHOST handled by ip_rcv() */
 
203
        if (skb->pkt_type != PACKET_HOST)
 
204
                return NF_DROP;
 
205
 
 
206
        /* Now check at the protocol level */
 
207
        if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
 
208
                return NF_DROP;
 
209
 
 
210
        /*
 
211
         * Our naive response construction does not deal with IP
 
212
         * options, and probably should not try.
 
213
         */
 
214
        if (ip_hdrlen(skb) != sizeof(struct iphdr))
 
215
                return NF_DROP;
 
216
 
 
217
        /* We are not interested in fragments */
 
218
        if (iph->frag_off & htons(IP_OFFSET))
 
219
                return NF_DROP;
 
220
 
 
221
        tarpit_tcp(*pskb, hooknum);
 
222
        return NF_DROP;
 
223
}
 
224
 
 
225
static struct xt_target tarpit_tg_reg __read_mostly = {
 
226
        .name   = "TARPIT",
 
227
        .family = AF_INET,
 
228
        .table  = "filter",
 
229
        .hooks  = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
 
230
        .proto  = IPPROTO_TCP,
 
231
        .target = tarpit_tg,
 
232
        .me     = THIS_MODULE,
 
233
};
 
234
 
 
235
static int __init tarpit_tg_init(void)
 
236
{
 
237
        return xt_register_target(&tarpit_tg_reg);
 
238
}
 
239
 
 
240
static void __exit tarpit_tg_exit(void)
 
241
{
 
242
        xt_unregister_target(&tarpit_tg_reg);
 
243
}
 
244
 
 
245
module_init(tarpit_tg_init);
 
246
module_exit(tarpit_tg_exit);
 
247
MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
 
248
MODULE_DESCRIPTION("Xtables: \"TARPIT\", capture and hold TCP connections");
 
249
MODULE_LICENSE("GPL");
 
250
MODULE_ALIAS("ipt_TARPIT");