NETFILTER: remove unnecessary goto statement for error recovery
[tomato.git] / release / src-rt / linux / linux-2.6 / net / ipv4 / netfilter / ipt_TARPIT.c
blob5b6f71a9dcae38767beea064183927312aa4c2d6
1 /*
2 * Kernel module to capture and hold incoming TCP connections using
3 * no local per-connection resources.
5 * Based on ipt_REJECT.c and offering functionality similar to
6 * LaBrea <http://www.hackbusters.net/LaBrea/>.
8 * Copyright (c) 2002 Aaron Hopkins <tools@die.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Goal:
25 * - Allow incoming TCP connections to be established.
26 * - Passing data should result in the connection being switched to the
27 * persist state (0 byte window), in which the remote side stops sending
28 * data and asks to continue every 60 seconds.
29 * - Attempts to shut down the connection should be ignored completely, so
30 * the remote side ends up having to time it out.
32 * This means:
33 * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes
34 * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing
35 * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited
38 #include <linux/version.h>
39 #include <linux/module.h>
40 #include <linux/skbuff.h>
41 #include <linux/ip.h>
42 #include <net/ip.h>
43 #include <net/tcp.h>
44 #include <net/icmp.h>
45 struct in_device;
46 #include <net/route.h>
47 #include <linux/random.h>
48 #include <linux/netfilter_ipv4/ip_tables.h>
50 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
51 #define ip_hdr(s) (s->nh.iph)
52 #endif
54 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
55 #define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING
56 #define NF_INET_LOCAL_IN NF_IP_LOCAL_IN
57 #define NF_INET_FORWARD NF_IP_FORWARD
58 #define NF_INET_LOCAL_OUT NF_IP_LOCAL_OUT
59 #define NF_INET_POST_ROUTING NF_IP_POST_ROUTING
60 #endif
62 #if 0
63 #define DEBUGP printk
64 #else
65 #define DEBUGP(format, args...)
66 #endif
68 MODULE_LICENSE("GPL");
69 MODULE_AUTHOR("Aaron Hopkins <tools@die.net>");
71 /* Stolen from ip_finish_output2 */
72 static int ip_direct_send(struct sk_buff *skb)
74 struct dst_entry *dst = skb->dst;
76 if (dst->hh)
77 return neigh_hh_output(dst->hh, skb);
78 else if (dst->neighbour)
79 return dst->neighbour->output(skb);
81 if (net_ratelimit())
82 printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n");
83 kfree_skb(skb);
84 return -EINVAL;
88 /* Send reply */
89 static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local)
91 struct sk_buff *nskb;
92 struct rtable *nrt;
93 struct tcphdr *otcph, *ntcph;
94 struct flowi fl = {};
95 unsigned int otcplen;
96 u_int16_t tmp;
98 /* A truncated TCP header isn't going to be useful */
99 if (oskb->len < (ip_hdr(oskb)->ihl*4) + sizeof(struct tcphdr))
100 return;
102 otcph = (struct tcphdr *)((u_int32_t*)ip_hdr(oskb)
103 + ip_hdr(oskb)->ihl);
104 otcplen = oskb->len - ip_hdr(oskb)->ihl*4;
106 /* No replies for RST or FIN */
107 if (otcph->rst || otcph->fin)
108 return;
110 /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */
111 if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ)))
112 return;
114 /* Check checksum. */
115 if (tcp_v4_check(otcplen, ip_hdr(oskb)->saddr,
116 ip_hdr(oskb)->daddr,
117 csum_partial((char *)otcph, otcplen, 0)) != 0)
118 return;
120 /* Copy skb (even if skb is about to be dropped, we can't just
121 clone it because there may be other things, such as tcpdump,
122 interested in it) */
123 nskb = skb_copy(oskb, GFP_ATOMIC);
124 if (!nskb)
125 return;
127 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
128 /* This packet will not be the same as the other: clear nf fields */
129 nf_conntrack_put(nskb->nfct);
130 nskb->nfct = NULL;
131 #endif /* CONFIG_NF_CONNTRACK */
133 ntcph = (struct tcphdr *)((u_int32_t*)ip_hdr(nskb) + ip_hdr(nskb)->ihl);
135 /* Truncate to length (no data) */
136 ntcph->doff = sizeof(struct tcphdr)/4;
137 skb_trim(nskb, ip_hdr(nskb)->ihl*4 + sizeof(struct tcphdr));
138 ip_hdr(nskb)->tot_len = htons(nskb->len);
140 /* Swap source and dest */
141 ip_hdr(nskb)->daddr = xchg(&ip_hdr(nskb)->saddr, ip_hdr(nskb)->daddr);
142 tmp = ntcph->source;
143 ntcph->source = ntcph->dest;
144 ntcph->dest = tmp;
146 /* Use supplied sequence number or make a new one */
147 ntcph->seq = otcph->ack ? otcph->ack_seq
148 : htonl(secure_tcp_sequence_number(ip_hdr(nskb)->saddr,
149 ip_hdr(nskb)->daddr,
150 ntcph->source,
151 ntcph->dest));
153 /* Our SYN-ACKs must have a >0 window */
154 ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0;
156 ntcph->urg_ptr = 0;
158 /* Reset flags */
159 ((u_int8_t *)ntcph)[13] = 0;
161 if (otcph->syn && otcph->ack) {
162 ntcph->rst = 1;
163 ntcph->ack_seq = 0;
164 } else {
165 ntcph->syn = otcph->syn;
166 ntcph->ack = 1;
167 ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn);
170 /* Adjust TCP checksum */
171 ntcph->check = 0;
172 ntcph->check = tcp_v4_check(sizeof(struct tcphdr),
173 ip_hdr(nskb)->saddr,
174 ip_hdr(nskb)->daddr,
175 csum_partial((char *)ntcph,
176 sizeof(struct tcphdr), 0));
178 fl.nl_u.ip4_u.daddr = ip_hdr(nskb)->daddr;
179 fl.nl_u.ip4_u.saddr = local ? ip_hdr(nskb)->saddr : 0;
180 fl.nl_u.ip4_u.tos = RT_TOS(ip_hdr(nskb)->tos) | RTO_CONN;
181 fl.oif = 0;
183 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
184 if (ip_route_output_key(&init_net, &nrt, &fl))
185 #else
186 if (ip_route_output_key(&nrt, &fl))
187 #endif
188 goto free_nskb;
190 dst_release(nskb->dst);
191 nskb->dst = &nrt->u.dst;
193 /* Adjust IP TTL */
194 ip_hdr(nskb)->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
196 /* Set DF, id = 0 */
197 ip_hdr(nskb)->frag_off = htons(IP_DF);
198 ip_hdr(nskb)->id = 0;
200 /* Adjust IP checksum */
201 ip_hdr(nskb)->check = 0;
202 ip_hdr(nskb)->check = ip_fast_csum((unsigned char *)ip_hdr(nskb),
203 ip_hdr(nskb)->ihl);
205 /* "Never happens" */
206 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
207 if (nskb->len > dst_mtu(nskb->dst))
208 #else
209 if (nskb->len > dst_pmtu(nskb->dst))
210 #endif
211 goto free_nskb;
213 ip_direct_send (nskb);
215 return;
217 free_nskb:
218 kfree_skb(nskb);
221 static unsigned int
222 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
223 target(struct sk_buff **pskb,
224 unsigned int hooknum,
225 const struct net_device *in,
226 const struct net_device *out,
227 const void *targinfo,
228 void *userinfo)
229 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
230 target(struct sk_buff **pskb,
231 const struct net_device *in,
232 const struct net_device *out,
233 unsigned int hooknum,
234 const void *targinfo,
235 void *userinfo)
236 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
237 target(struct sk_buff **pskb,
238 const struct net_device *in,
239 const struct net_device *out,
240 unsigned int hooknum,
241 const struct xt_target *target,
242 const void *targinfo,
243 void *userinfo)
244 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
245 target(struct sk_buff **pskb,
246 const struct net_device *in,
247 const struct net_device *out,
248 unsigned int hooknum,
249 const struct xt_target *target,
250 const void *targinfo)
251 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
252 target(struct sk_buff *skb,
253 const struct net_device *in,
254 const struct net_device *out,
255 unsigned int hooknum,
256 const struct xt_target *target,
257 const void *targinfo)
258 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
259 target(struct sk_buff *skb,
260 const struct xt_target_param *par)
261 #endif
263 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
264 unsigned int hooknum = par->hooknum;
265 #endif
266 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
267 struct sk_buff *skb = *pskb;
268 #endif
269 struct rtable *rt = (struct rtable*)skb->dst;
271 /* Do we have an input route cache entry? */
272 if (!rt)
273 return NF_DROP;
275 /* No replies to physical multicast/broadcast */
276 if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST)
277 return NF_DROP;
279 /* Now check at the protocol level */
280 if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
281 return NF_DROP;
283 /* Our naive response construction doesn't deal with IP
284 options, and probably shouldn't try. */
285 if (ip_hdr(skb)->ihl*4 != sizeof(struct iphdr))
286 return NF_DROP;
288 /* We aren't interested in fragments */
289 if (ip_hdr(skb)->frag_off & htons(IP_OFFSET))
290 return NF_DROP;
292 tarpit_tcp(skb,rt,hooknum == NF_INET_LOCAL_IN);
294 return NF_DROP;
297 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
298 static int
299 checkentry(const char *tablename,
300 const struct ipt_entry *e,
301 void *targinfo,
302 unsigned int targinfosize,
303 unsigned int hook_mask)
304 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
305 static int
306 checkentry(const char *tablename,
307 const void *e,
308 void *targinfo,
309 unsigned int targinfosize,
310 unsigned int hook_mask)
311 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
312 static int
313 checkentry(const char *tablename,
314 const void *e,
315 const struct xt_target *target,
316 void *targinfo,
317 unsigned int targinfosize,
318 unsigned int hook_mask)
319 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
320 static int
321 checkentry(const char *tablename,
322 const void *e,
323 const struct xt_target *target,
324 void *targinfo,
325 unsigned int hook_mask)
326 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
327 static bool
328 checkentry(const char *tablename,
329 const void *e,
330 const struct xt_target *target,
331 void *targinfo,
332 unsigned int hook_mask)
333 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
334 static bool
335 checkentry(const struct xt_tgchk_param *par)
336 #endif
338 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
339 const struct ipt_entry *entry = e;
340 #else
341 const char *tablename = par->table;
342 const struct ipt_entry *entry = par->entryinfo;
343 unsigned int hook_mask = par-> hook_mask;
344 #endif
346 /* Only allow these for input/forward packet filtering. */
347 if (strcmp(tablename, "filter") != 0) {
348 DEBUGP("TARPIT: bad table %s'.\n", tablename);
349 return 0;
351 if ((hook_mask & ~((1 << NF_INET_LOCAL_IN)
352 | (1 << NF_INET_FORWARD))) != 0) {
353 DEBUGP("TARPIT: bad hook mask %X\n", hook_mask);
354 return 0;
357 /* Must specify that it's a TCP packet */
358 if (entry->ip.proto != IPPROTO_TCP || (entry->ip.invflags & IPT_INV_PROTO)) {
359 DEBUGP("TARPIT: not valid for non-tcp\n");
360 return 0;
363 return 1;
366 static struct xt_target ipt_tarpit_reg = {
367 .name = "TARPIT",
368 .family = AF_INET,
369 .target = target,
370 .checkentry = checkentry,
371 .me = THIS_MODULE
374 static int __init init(void)
376 return xt_register_target(&ipt_tarpit_reg);
379 static void __exit fini(void)
381 xt_unregister_target(&ipt_tarpit_reg);
384 module_init(init);
385 module_exit(fini);