OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv4/] [netfilter/] [ipt_REJECT.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.