more changes on original files
[linux-2.4.git] / netfilter / ipt_REJECT.c
1 /*
2  * This is a module which is used for rejecting packets.
3  * Added support for customized reject packets (Jozsef Kadlecsik).
4  * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812]
5  */
6 #include <linux/config.h>
7 #include <linux/module.h>
8 #include <linux/skbuff.h>
9 #include <linux/ip.h>
10 #include <linux/udp.h>
11 #include <linux/icmp.h>
12 #include <net/icmp.h>
13 #include <net/ip.h>
14 #include <net/tcp.h>
15 #include <net/route.h>
16 #include <linux/netfilter_ipv4/ip_tables.h>
17 #include <linux/netfilter_ipv4/ipt_REJECT.h>
18
19 #if 0
20 #define DEBUGP printk
21 #else
22 #define DEBUGP(format, args...)
23 #endif
24
25 static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
26 {
27         struct iphdr *iph = skb->nh.iph;
28         struct dst_entry *odst;
29         struct rt_key key = {};
30         struct rtable *rt;
31
32         if (hook != NF_IP_FORWARD) {
33                 key.dst = iph->saddr;
34                 if (hook == NF_IP_LOCAL_IN)
35                         key.src = iph->daddr;
36                 key.tos = RT_TOS(iph->tos);
37
38                 if (ip_route_output_key(&rt, &key) != 0)
39                         return NULL;
40         } else {
41                 /* non-local src, find valid iif to satisfy
42                  * rp-filter when calling ip_route_input. */
43                 key.dst = iph->daddr;
44                 if (ip_route_output_key(&rt, &key) != 0)
45                         return NULL;
46
47                 odst = skb->dst;
48                 if (ip_route_input(skb, iph->saddr, iph->daddr,
49                                    RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
50                         dst_release(&rt->u.dst);
51                         return NULL;
52                 }
53                 dst_release(&rt->u.dst);
54                 rt = (struct rtable *)skb->dst;
55                 skb->dst = odst;
56         }
57
58         if (rt->u.dst.error) {
59                 dst_release(&rt->u.dst);
60                 rt = NULL;
61         }
62
63         return rt;
64 }
65
66 /* Send RST reply */
67 static void send_reset(struct sk_buff *oldskb, int hook)
68 {
69         struct sk_buff *nskb;
70         struct tcphdr *otcph, *tcph;
71         struct rtable *rt;
72         unsigned int otcplen;
73         u_int16_t tmp_port;
74         u_int32_t tmp_addr;
75         int needs_ack;
76         int hh_len;
77
78         /* IP header checks: fragment, too short. */
79         if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
80             || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
81                 return;
82
83         otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
84         otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
85
86         /* No RST for RST. */
87         if (otcph->rst)
88                 return;
89
90         /* Check checksum. */
91         if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
92                          oldskb->nh.iph->daddr,
93                          csum_partial((char *)otcph, otcplen, 0)) != 0)
94                 return;
95
96         if ((rt = route_reverse(oldskb, hook)) == NULL)
97                 return;
98
99         hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
100
101
102         /* Copy skb (even if skb is about to be dropped, we can't just
103            clone it because there may be other things, such as tcpdump,
104            interested in it). We also need to expand headroom in case
105            hh_len of incoming interface < hh_len of outgoing interface */
106         nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
107                                GFP_ATOMIC);
108         if (!nskb) {
109                 dst_release(&rt->u.dst);
110                 return;
111         }
112
113         dst_release(nskb->dst);
114         nskb->dst = &rt->u.dst;
115
116         /* This packet will not be the same as the other: clear nf fields */
117         nf_reset(nskb);
118         nskb->nfcache = 0;
119         nskb->nfmark = 0;
120
121         tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
122
123         /* Swap source and dest */
124         tmp_addr = nskb->nh.iph->saddr;
125         nskb->nh.iph->saddr = nskb->nh.iph->daddr;
126         nskb->nh.iph->daddr = tmp_addr;
127         tmp_port = tcph->source;
128         tcph->source = tcph->dest;
129         tcph->dest = tmp_port;
130
131         /* Truncate to length (no data) */
132         tcph->doff = sizeof(struct tcphdr)/4;
133         skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
134         nskb->nh.iph->tot_len = htons(nskb->len);
135
136         if (tcph->ack) {
137                 needs_ack = 0;
138                 tcph->seq = otcph->ack_seq;
139                 tcph->ack_seq = 0;
140         } else {
141                 needs_ack = 1;
142                 tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
143                                       + otcplen - (otcph->doff<<2));
144                 tcph->seq = 0;
145         }
146
147         /* Reset flags */
148         ((u_int8_t *)tcph)[13] = 0;
149         tcph->rst = 1;
150         tcph->ack = needs_ack;
151
152         tcph->window = 0;
153         tcph->urg_ptr = 0;
154
155         /* Adjust TCP checksum */
156         tcph->check = 0;
157         tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
158                                    nskb->nh.iph->saddr,
159                                    nskb->nh.iph->daddr,
160                                    csum_partial((char *)tcph,
161                                                 sizeof(struct tcphdr), 0));
162
163         /* Adjust IP TTL, DF */
164         nskb->nh.iph->ttl = MAXTTL;
165         /* Set DF, id = 0 */
166         nskb->nh.iph->frag_off = htons(IP_DF);
167         nskb->nh.iph->id = 0;
168
169         /* Adjust IP checksum */
170         nskb->nh.iph->check = 0;
171         nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
172                                            nskb->nh.iph->ihl);
173
174         /* "Never happens" */
175         if (nskb->len > nskb->dst->pmtu)
176                 goto free_nskb;
177
178         nf_ct_attach(nskb, oldskb);
179
180         NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
181                 ip_finish_output);
182         return;
183
184  free_nskb:
185         kfree_skb(nskb);
186 }
187
188 static void send_unreach(struct sk_buff *skb_in, int code)
189 {
190         struct iphdr *iph;
191         struct udphdr *udph;
192         struct icmphdr *icmph;
193         struct sk_buff *nskb;
194         u32 saddr;
195         u8 tos;
196         int hh_len, length;
197         struct rtable *rt = (struct rtable*)skb_in->dst;
198         unsigned char *data;
199
200         if (!rt)
201                 return;
202
203         /* FIXME: Use sysctl number. --RR */
204         if (!xrlim_allow(&rt->u.dst, 1*HZ))
205                 return;
206
207         iph = skb_in->nh.iph;
208
209         /* No replies to physical multicast/broadcast */
210         if (skb_in->pkt_type!=PACKET_HOST)
211                 return;
212
213         /* Now check at the protocol level */
214         if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
215                 return;
216
217         /* Only reply to fragment 0. */
218         if (iph->frag_off&htons(IP_OFFSET))
219                 return;
220
221         /* if UDP checksum is set, verify it's correct */
222         if (iph->protocol == IPPROTO_UDP
223             && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
224                 int datalen = skb_in->len - (iph->ihl<<2);
225                 udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
226                 if (udph->check
227                     && csum_tcpudp_magic(iph->saddr, iph->daddr,
228                                          datalen, IPPROTO_UDP,
229                                          csum_partial((char *)udph, datalen,
230                                                       0)) != 0)
231                         return;
232         }
233                     
234         /* If we send an ICMP error to an ICMP error a mess would result.. */
235         if (iph->protocol == IPPROTO_ICMP
236             && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
237                 icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
238                 /* Between echo-reply (0) and timestamp (13),
239                    everything except echo-request (8) is an error.
240                    Also, anything greater than NR_ICMP_TYPES is
241                    unknown, and hence should be treated as an error... */
242                 if ((icmph->type < ICMP_TIMESTAMP
243                      && icmph->type != ICMP_ECHOREPLY
244                      && icmph->type != ICMP_ECHO)
245                     || icmph->type > NR_ICMP_TYPES)
246                         return;
247         }
248
249         saddr = iph->daddr;
250         if (!(rt->rt_flags & RTCF_LOCAL))
251                 saddr = 0;
252
253         tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
254
255         if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
256                 return;
257
258         /* RFC says return as much as we can without exceeding 576 bytes. */
259         length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
260
261         if (length > rt->u.dst.pmtu)
262                 length = rt->u.dst.pmtu;
263         if (length > 576)
264                 length = 576;
265
266         hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
267
268         nskb = alloc_skb(hh_len+15+length, GFP_ATOMIC);
269         if (!nskb) {
270                 ip_rt_put(rt);
271                 return;
272         }
273
274         nskb->priority = 0;
275         nskb->dst = &rt->u.dst;
276         skb_reserve(nskb, hh_len);
277
278         /* Set up IP header */
279         iph = nskb->nh.iph
280                 = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
281         iph->version=4;
282         iph->ihl=5;
283         iph->tos=tos;
284         iph->tot_len = htons(length);
285
286         /* PMTU discovery never applies to ICMP packets. */
287         iph->frag_off = 0;
288
289         iph->ttl = MAXTTL;
290         ip_select_ident(iph, &rt->u.dst, NULL);
291         iph->protocol=IPPROTO_ICMP;
292         iph->saddr=rt->rt_src;
293         iph->daddr=rt->rt_dst;
294         iph->check=0;
295         iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
296
297         /* Set up ICMP header. */
298         icmph = nskb->h.icmph
299                 = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
300         icmph->type = ICMP_DEST_UNREACH;
301         icmph->code = code;     
302         icmph->un.gateway = 0;
303         icmph->checksum = 0;
304         
305         /* Copy as much of original packet as will fit */
306         data = skb_put(nskb,
307                        length - sizeof(struct iphdr) - sizeof(struct icmphdr));
308         /* FIXME: won't work with nonlinear skbs --RR */
309         memcpy(data, skb_in->nh.iph,
310                length - sizeof(struct iphdr) - sizeof(struct icmphdr));
311         icmph->checksum = ip_compute_csum((unsigned char *)icmph,
312                                           length - sizeof(struct iphdr));
313
314         nf_ct_attach(nskb, skb_in);
315
316         NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
317                 ip_finish_output);
318 }       
319
320 static unsigned int reject(struct sk_buff **pskb,
321                            unsigned int hooknum,
322                            const struct net_device *in,
323                            const struct net_device *out,
324                            const void *targinfo,
325                            void *userinfo)
326 {
327         const struct ipt_reject_info *reject = targinfo;
328
329         /* Our naive response construction doesn't deal with IP
330            options, and probably shouldn't try. */
331         if ((*pskb)->nh.iph->ihl<<2 != sizeof(struct iphdr))
332                 return NF_DROP;
333
334         /* WARNING: This code causes reentry within iptables.
335            This means that the iptables jump stack is now crap.  We
336            must return an absolute verdict. --RR */
337         switch (reject->with) {
338         case IPT_ICMP_NET_UNREACHABLE:
339                 send_unreach(*pskb, ICMP_NET_UNREACH);
340                 break;
341         case IPT_ICMP_HOST_UNREACHABLE:
342                 send_unreach(*pskb, ICMP_HOST_UNREACH);
343                 break;
344         case IPT_ICMP_PROT_UNREACHABLE:
345                 send_unreach(*pskb, ICMP_PROT_UNREACH);
346                 break;
347         case IPT_ICMP_PORT_UNREACHABLE:
348                 send_unreach(*pskb, ICMP_PORT_UNREACH);
349                 break;
350         case IPT_ICMP_NET_PROHIBITED:
351                 send_unreach(*pskb, ICMP_NET_ANO);
352                 break;
353         case IPT_ICMP_HOST_PROHIBITED:
354                 send_unreach(*pskb, ICMP_HOST_ANO);
355                 break;
356         case IPT_ICMP_ADMIN_PROHIBITED:
357                 send_unreach(*pskb, ICMP_PKT_FILTERED);
358                 break;
359         case IPT_TCP_RESET:
360                 send_reset(*pskb, hooknum);
361         case IPT_ICMP_ECHOREPLY:
362                 /* Doesn't happen. */
363                 break;
364         }
365
366         return NF_DROP;
367 }
368
369 static int check(const char *tablename,
370                  const struct ipt_entry *e,
371                  void *targinfo,
372                  unsigned int targinfosize,
373                  unsigned int hook_mask)
374 {
375         const struct ipt_reject_info *rejinfo = targinfo;
376
377         if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
378                 DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
379                 return 0;
380         }
381
382         /* Only allow these for packet filtering. */
383         if (strcmp(tablename, "filter") != 0) {
384                 DEBUGP("REJECT: bad table `%s'.\n", tablename);
385                 return 0;
386         }
387         if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
388                            | (1 << NF_IP_FORWARD)
389                            | (1 << NF_IP_LOCAL_OUT))) != 0) {
390                 DEBUGP("REJECT: bad hook mask %X\n", hook_mask);
391                 return 0;
392         }
393
394         if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
395                 printk("REJECT: ECHOREPLY no longer supported.\n");
396                 return 0;
397         } else if (rejinfo->with == IPT_TCP_RESET) {
398                 /* Must specify that it's a TCP packet */
399                 if (e->ip.proto != IPPROTO_TCP
400                     || (e->ip.invflags & IPT_INV_PROTO)) {
401                         DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
402                         return 0;
403                 }
404         }
405
406         return 1;
407 }
408
409 static struct ipt_target ipt_reject_reg
410 = { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE };
411
412 static int __init init(void)
413 {
414         if (ipt_register_target(&ipt_reject_reg))
415                 return -EINVAL;
416         return 0;
417 }
418
419 static void __exit fini(void)
420 {
421         ipt_unregister_target(&ipt_reject_reg);
422 }
423
424 module_init(init);
425 module_exit(fini);
426 MODULE_LICENSE("GPL");