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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [netinet/] [ip_fw.c] - Blame information for rev 389

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

Line No. Rev Author Line
1 30 unneback
/*
2
 * Copyright (c) 1996 Alex Nash
3
 * Copyright (c) 1993 Daniel Boulet
4
 * Copyright (c) 1994 Ugen J.S.Antsilevich
5
 *
6
 * Redistribution and use in source forms, with and without modification,
7
 * are permitted provided that this entire comment appears intact.
8
 *
9
 * Redistribution in binary form may occur without any restrictions.
10
 * Obviously, it would be nice if you gave credit where credit is due
11
 * but requiring it would be too onerous.
12
 *
13
 * This software is provided ``AS IS'' without any warranties of any kind.
14
 *
15
 *      $Id: ip_fw.c,v 1.2 2001-09-27 12:01:55 chris Exp $
16
 */
17
 
18
/*
19
 * Implement IP packet firewall
20
 */
21
 
22
#ifndef IPFIREWALL_MODULE
23
#include "opt_ipfw.h"
24
#endif
25
 
26
#include <sys/param.h>
27
#include <sys/systm.h>
28
#include <sys/malloc.h>
29
#include <sys/mbuf.h>
30
#include <sys/queue.h>
31
#include <sys/kernel.h>
32
#include <sys/socket.h>
33
#include <sys/time.h>
34
#include <sys/sysctl.h>
35
#include <net/if.h>
36
#include <net/route.h>
37
#include <netinet/in.h>
38
#include <netinet/in_systm.h>
39
#include <netinet/ip.h>
40
#include <netinet/ip_var.h>
41
#include <netinet/ip_icmp.h>
42
#include <netinet/ip_fw.h>
43
#include <netinet/tcp.h>
44
#include <netinet/tcp_timer.h>
45
#include <netinet/tcp_var.h>
46
#include <netinet/tcpip.h>
47
#include <netinet/udp.h>
48
 
49
static int fw_debug = 1;
50
#ifdef IPFIREWALL_VERBOSE
51
static int fw_verbose = 1;
52
#else
53
static int fw_verbose = 0;
54
#endif
55
#ifdef IPFIREWALL_VERBOSE_LIMIT
56
static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
57
#else
58
static int fw_verbose_limit = 0;
59
#endif
60
 
61
LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;
62
 
63
#ifdef SYSCTL_NODE
64
SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
65
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "");
66
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "");
67
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "");
68
#endif
69
 
70
#define dprintf(a)      if (!fw_debug); else printf a
71
 
72
#define print_ip(a)      printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
73
                                                  (ntohl(a.s_addr)>>16)&0xFF,\
74
                                                  (ntohl(a.s_addr)>>8)&0xFF,\
75
                                                  (ntohl(a.s_addr))&0xFF);
76
 
77
#define dprint_ip(a)    if (!fw_debug); else print_ip(a)
78
 
79
static int      add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));
80
static int      del_entry __P((struct ip_fw_head *chainptr, u_short number));
81
static int      zero_entry __P((struct mbuf *m));
82
static struct ip_fw *check_ipfw_struct __P((struct ip_fw *m));
83
static struct ip_fw *check_ipfw_mbuf __P((struct mbuf *fw));
84
static int      ipopts_match __P((struct ip *ip, struct ip_fw *f));
85
static int      port_match __P((u_short *portptr, int nports, u_short port,
86
                                int range_flag));
87
static int      tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));
88
static int      icmptype_match __P((struct icmp *  icmp, struct ip_fw * f));
89
static void     ipfw_report __P((struct ip_fw *f, struct ip *ip,
90
                                struct ifnet *rif, struct ifnet *oif));
91
 
92
#ifdef IPFIREWALL_MODULE
93
static ip_fw_chk_t *old_chk_ptr;
94
static ip_fw_ctl_t *old_ctl_ptr;
95
#endif
96
 
97
static int      ip_fw_chk __P((struct ip **pip, int hlen,
98
                        struct ifnet *oif, int ignport, struct mbuf **m));
99
static int      ip_fw_ctl __P((int stage, struct mbuf **mm));
100
 
101
static char err_prefix[] = "ip_fw_ctl:";
102
 
103
/*
104
 * Returns 1 if the port is matched by the vector, 0 otherwise
105
 */
106
static inline int
107
port_match(u_short *portptr, int nports, u_short port, int range_flag)
108
{
109
        if (!nports)
110
                return 1;
111
        if (range_flag) {
112
                if (portptr[0] <= port && port <= portptr[1]) {
113
                        return 1;
114
                }
115
                nports -= 2;
116
                portptr += 2;
117
        }
118
        while (nports-- > 0) {
119
                if (*portptr++ == port) {
120
                        return 1;
121
                }
122
        }
123
        return 0;
124
}
125
 
126
static int
127
tcpflg_match(struct tcphdr *tcp, struct ip_fw *f)
128
{
129
        u_char          flg_set, flg_clr;
130
 
131
        if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) &&
132
            (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK)))
133
                return 1;
134
 
135
        flg_set = tcp->th_flags & f->fw_tcpf;
136
        flg_clr = tcp->th_flags & f->fw_tcpnf;
137
 
138
        if (flg_set != f->fw_tcpf)
139
                return 0;
140
        if (flg_clr)
141
                return 0;
142
 
143
        return 1;
144
}
145
 
146
static int
147
icmptype_match(struct icmp *icmp, struct ip_fw *f)
148
{
149
        int type;
150
 
151
        if (!(f->fw_flg & IP_FW_F_ICMPBIT))
152
                return(1);
153
 
154
        type = icmp->icmp_type;
155
 
156
        /* check for matching type in the bitmap */
157
        if (type < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8 &&
158
                (f->fw_icmptypes[type / (sizeof(unsigned) * 8)] &
159
                (1U << (type % (8 * sizeof(unsigned))))))
160
                return(1);
161
 
162
        return(0); /* no match */
163
}
164
 
165
static int
166
ipopts_match(struct ip *ip, struct ip_fw *f)
167
{
168
        register u_char *cp;
169
        int opt, optlen, cnt;
170
        u_char  opts, nopts, nopts_sve;
171
 
172
        cp = (u_char *)(ip + 1);
173
        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
174
        opts = f->fw_ipopt;
175
        nopts = nopts_sve = f->fw_ipnopt;
176
 
177
        for (; cnt > 0; cnt -= optlen, cp += optlen) {
178
                opt = cp[IPOPT_OPTVAL];
179
                if (opt == IPOPT_EOL)
180
                        break;
181
                if (opt == IPOPT_NOP)
182
                        optlen = 1;
183
                else {
184
                        optlen = cp[IPOPT_OLEN];
185
                        if (optlen <= 0 || optlen > cnt) {
186
                                return 0; /*XXX*/
187
                        }
188
                }
189
                switch (opt) {
190
 
191
                default:
192
                        break;
193
 
194
                case IPOPT_LSRR:
195
                        opts &= ~IP_FW_IPOPT_LSRR;
196
                        nopts &= ~IP_FW_IPOPT_LSRR;
197
                        break;
198
 
199
                case IPOPT_SSRR:
200
                        opts &= ~IP_FW_IPOPT_SSRR;
201
                        nopts &= ~IP_FW_IPOPT_SSRR;
202
                        break;
203
 
204
                case IPOPT_RR:
205
                        opts &= ~IP_FW_IPOPT_RR;
206
                        nopts &= ~IP_FW_IPOPT_RR;
207
                        break;
208
                case IPOPT_TS:
209
                        opts &= ~IP_FW_IPOPT_TS;
210
                        nopts &= ~IP_FW_IPOPT_TS;
211
                        break;
212
                }
213
                if (opts == nopts)
214
                        break;
215
        }
216
        if (opts == 0 && nopts == nopts_sve)
217
                return 1;
218
        else
219
                return 0;
220
}
221
 
222
static inline int
223
iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
224
{
225
        /* Check by name or by IP address */
226
        if (byname) {
227
                /* Check unit number (-1 is wildcard) */
228
                if (ifu->fu_via_if.unit != -1
229
                    && ifp->if_unit != ifu->fu_via_if.unit)
230
                        return(0);
231
                /* Check name */
232
                if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN))
233
                        return(0);
234
                return(1);
235
        } else if (ifu->fu_via_ip.s_addr != 0) { /* Zero == wildcard */
236
                struct ifaddr *ia;
237
 
238
                for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
239
                        if (ia->ifa_addr == NULL)
240
                                continue;
241
                        if (ia->ifa_addr->sa_family != AF_INET)
242
                                continue;
243
                        if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *)
244
                            (ia->ifa_addr))->sin_addr.s_addr)
245
                                continue;
246
                        return(1);
247
                }
248
                return(0);
249
        }
250
        return(1);
251
}
252
 
253
static void
254
ipfw_report(struct ip_fw *f, struct ip *ip,
255
        struct ifnet *rif, struct ifnet *oif)
256
{
257
        static int counter;
258
        struct tcphdr *const tcp = (struct tcphdr *) ((u_long *) ip+ ip->ip_hl);
259
        struct udphdr *const udp = (struct udphdr *) ((u_long *) ip+ ip->ip_hl);
260
        struct icmp *const icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl);
261
        int count;
262
 
263
        count = f ? f->fw_pcnt : ++counter;
264
        if (fw_verbose_limit != 0 && count > fw_verbose_limit)
265
                return;
266
 
267
        /* Print command name */
268
        printf("ipfw: %d ", f ? f->fw_number : -1);
269
        if (!f)
270
                printf("Refuse");
271
        else
272
                switch (f->fw_flg & IP_FW_F_COMMAND) {
273
                case IP_FW_F_DENY:
274
                        printf("Deny");
275
                        break;
276
                case IP_FW_F_REJECT:
277
                        if (f->fw_reject_code == IP_FW_REJECT_RST)
278
                                printf("Reset");
279
                        else
280
                                printf("Unreach");
281
                        break;
282
                case IP_FW_F_ACCEPT:
283
                        printf("Accept");
284
                        break;
285
                case IP_FW_F_COUNT:
286
                        printf("Count");
287
                        break;
288
                case IP_FW_F_DIVERT:
289
                        printf("Divert %d", f->fw_divert_port);
290
                        break;
291
                case IP_FW_F_TEE:
292
                        printf("Tee %d", f->fw_divert_port);
293
                        break;
294
                case IP_FW_F_SKIPTO:
295
                        printf("SkipTo %d", f->fw_skipto_rule);
296
                        break;
297
                default:
298
                        printf("UNKNOWN");
299
                        break;
300
                }
301
        printf(" ");
302
 
303
        switch (ip->ip_p) {
304
        case IPPROTO_TCP:
305
                printf("TCP ");
306
                print_ip(ip->ip_src);
307
                if ((ip->ip_off & IP_OFFMASK) == 0)
308
                        printf(":%d ", ntohs(tcp->th_sport));
309
                else
310
                        printf(" ");
311
                print_ip(ip->ip_dst);
312
                if ((ip->ip_off & IP_OFFMASK) == 0)
313
                        printf(":%d", ntohs(tcp->th_dport));
314
                break;
315
        case IPPROTO_UDP:
316
                printf("UDP ");
317
                print_ip(ip->ip_src);
318
                if ((ip->ip_off & IP_OFFMASK) == 0)
319
                        printf(":%d ", ntohs(udp->uh_sport));
320
                else
321
                        printf(" ");
322
                print_ip(ip->ip_dst);
323
                if ((ip->ip_off & IP_OFFMASK) == 0)
324
                        printf(":%d", ntohs(udp->uh_dport));
325
                break;
326
        case IPPROTO_ICMP:
327
                printf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code);
328
                print_ip(ip->ip_src);
329
                printf(" ");
330
                print_ip(ip->ip_dst);
331
                break;
332
        default:
333
                printf("P:%d ", ip->ip_p);
334
                print_ip(ip->ip_src);
335
                printf(" ");
336
                print_ip(ip->ip_dst);
337
                break;
338
        }
339
        if (oif)
340
                printf(" out via %s%d", oif->if_name, oif->if_unit);
341
        else if (rif)
342
                printf(" in via %s%d", rif->if_name, rif->if_unit);
343
        if ((ip->ip_off & IP_OFFMASK))
344
                printf(" Fragment = %d",ip->ip_off & IP_OFFMASK);
345
        printf("\n");
346
        if (fw_verbose_limit != 0 && count == fw_verbose_limit)
347
                printf("ipfw: limit reached on rule #%d\n",
348
                f ? f->fw_number : -1);
349
}
350
 
351
/*
352
 * Parameters:
353
 *
354
 *      ip      Pointer to packet header (struct ip *)
355
 *      hlen    Packet header length
356
 *      oif     Outgoing interface, or NULL if packet is incoming
357
 *      ignport Ignore all divert/tee rules to this port (if non-zero)
358
 *      *m      The packet; we set to NULL when/if we nuke it.
359
 *
360
 * Return value:
361
 *
362
 *      0        The packet is to be accepted and routed normally OR
363
 *              the packet was denied/rejected and has been dropped;
364
 *              in the latter case, *m is equal to NULL upon return.
365
 *      port    Divert the packet to port.
366
 */
367
 
368
static int
369
ip_fw_chk(struct ip **pip, int hlen,
370
        struct ifnet *oif, int ignport, struct mbuf **m)
371
{
372
        struct ip_fw_chain *chain;
373
        struct ip_fw *rule = NULL;
374
        struct ip *ip = *pip;
375
        struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
376
        u_short offset = (ip->ip_off & IP_OFFMASK);
377
        u_short src_port, dst_port;
378
 
379
        /*
380
         * Go down the chain, looking for enlightment
381
         */
382
        for (chain=ip_fw_chain.lh_first; chain; chain = chain->chain.le_next) {
383
                register struct ip_fw *const f = chain->rule;
384
 
385
                /* Check direction inbound */
386
                if (!oif && !(f->fw_flg & IP_FW_F_IN))
387
                        continue;
388
 
389
                /* Check direction outbound */
390
                if (oif && !(f->fw_flg & IP_FW_F_OUT))
391
                        continue;
392
 
393
                /* Fragments */
394
                if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK))
395
                        continue;
396
 
397
                /* If src-addr doesn't match, not this rule. */
398
                if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr
399
                    & f->fw_smsk.s_addr) != f->fw_src.s_addr))
400
                        continue;
401
 
402
                /* If dest-addr doesn't match, not this rule. */
403
                if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr
404
                    & f->fw_dmsk.s_addr) != f->fw_dst.s_addr))
405
                        continue;
406
 
407
                /* Interface check */
408
                if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
409
                        struct ifnet *const iface = oif ? oif : rif;
410
 
411
                        /* Backwards compatibility hack for "via" */
412
                        if (!iface || !iface_match(iface,
413
                            &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))
414
                                continue;
415
                } else {
416
                        /* Check receive interface */
417
                        if ((f->fw_flg & IP_FW_F_IIFACE)
418
                            && (!rif || !iface_match(rif,
419
                              &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))
420
                                continue;
421
                        /* Check outgoing interface */
422
                        if ((f->fw_flg & IP_FW_F_OIFACE)
423
                            && (!oif || !iface_match(oif,
424
                              &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))
425
                                continue;
426
                }
427
 
428
                /* Check IP options */
429
                if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
430
                        continue;
431
 
432
                /* Check protocol; if wildcard, match */
433
                if (f->fw_prot == IPPROTO_IP)
434
                        goto got_match;
435
 
436
                /* If different, don't match */
437
                if (ip->ip_p != f->fw_prot)
438
                        continue;
439
 
440
#define PULLUP_TO(len)  do {                                            \
441
                            if ((*m)->m_len < (len)                     \
442
                                && (*m = m_pullup(*m, (len))) == 0) {    \
443
                                    goto bogusfrag;                     \
444
                            }                                           \
445
                            *pip = ip = mtod(*m, struct ip *);          \
446
                            offset = (ip->ip_off & IP_OFFMASK);         \
447
                        } while (0)
448
 
449
                /* Protocol specific checks */
450
                switch (ip->ip_p) {
451
                case IPPROTO_TCP:
452
                    {
453
                        struct tcphdr *tcp;
454
 
455
                        if (offset == 1)        /* cf. RFC 1858 */
456
                                goto bogusfrag;
457
                        if (offset != 0) {
458
                                /*
459
                                 * TCP flags and ports aren't available in this
460
                                 * packet -- if this rule specified either one,
461
                                 * we consider the rule a non-match.
462
                                 */
463
                                if (f->fw_nports != 0 ||
464
                                    f->fw_tcpf != f->fw_tcpnf)
465
                                        continue;
466
 
467
                                break;
468
                        }
469
                        PULLUP_TO(hlen + 14);
470
                        tcp = (struct tcphdr *) ((u_long *)ip + ip->ip_hl);
471
                        if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
472
                                continue;
473
                        src_port = ntohs(tcp->th_sport);
474
                        dst_port = ntohs(tcp->th_dport);
475
                        goto check_ports;
476
                    }
477
 
478
                case IPPROTO_UDP:
479
                    {
480
                        struct udphdr *udp;
481
 
482
                        if (offset != 0) {
483
                                /*
484
                                 * Port specification is unavailable -- if this
485
                                 * rule specifies a port, we consider the rule
486
                                 * a non-match.
487
                                 */
488
                                if (f->fw_nports != 0)
489
                                        continue;
490
 
491
                                break;
492
                        }
493
                        PULLUP_TO(hlen + 4);
494
                        udp = (struct udphdr *) ((u_long *)ip + ip->ip_hl);
495
                        src_port = ntohs(udp->uh_sport);
496
                        dst_port = ntohs(udp->uh_dport);
497
check_ports:
498
                        if (!port_match(&f->fw_pts[0],
499
                            IP_FW_GETNSRCP(f), src_port,
500
                            f->fw_flg & IP_FW_F_SRNG))
501
                                continue;
502
                        if (!port_match(&f->fw_pts[IP_FW_GETNSRCP(f)],
503
                            IP_FW_GETNDSTP(f), dst_port,
504
                            f->fw_flg & IP_FW_F_DRNG))
505
                                continue;
506
                        break;
507
                    }
508
 
509
                case IPPROTO_ICMP:
510
                    {
511
                        struct icmp *icmp;
512
 
513
                        if (offset != 0) /* Type isn't valid */
514
                                break;
515
                        PULLUP_TO(hlen + 2);
516
                        icmp = (struct icmp *) ((u_long *)ip + ip->ip_hl);
517
                        if (!icmptype_match(icmp, f))
518
                                continue;
519
                        break;
520
                    }
521
#undef PULLUP_TO
522
 
523
bogusfrag:
524
                        if (fw_verbose)
525
                                ipfw_report(NULL, ip, rif, oif);
526
                        goto dropit;
527
                }
528
 
529
got_match:
530
                /* Ignore divert/tee rule if socket port is "ignport" */
531
                switch (f->fw_flg & IP_FW_F_COMMAND) {
532
                case IP_FW_F_DIVERT:
533
                case IP_FW_F_TEE:
534
                        if (f->fw_divert_port == ignport)
535
                                continue;       /* ignore this rule */
536
                        break;
537
                }
538
 
539
                /* Update statistics */
540
                f->fw_pcnt += 1;
541
                f->fw_bcnt += ip->ip_len;
542
                f->timestamp = rtems_bsdnet_seconds_since_boot();
543
 
544
                /* Log to console if desired */
545
                if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)
546
                        ipfw_report(f, ip, rif, oif);
547
 
548
                /* Take appropriate action */
549
                switch (f->fw_flg & IP_FW_F_COMMAND) {
550
                case IP_FW_F_ACCEPT:
551
                        return(0);
552
                case IP_FW_F_COUNT:
553
                        continue;
554
                case IP_FW_F_DIVERT:
555
                        return(f->fw_divert_port);
556
                case IP_FW_F_TEE:
557
                        /*
558
                         * XXX someday tee packet here, but beware that you
559
                         * can't use m_copym() or m_copypacket() because
560
                         * the divert input routine modifies the mbuf
561
                         * (and these routines only increment reference
562
                         * counts in the case of mbuf clusters), so need
563
                         * to write custom routine.
564
                         */
565
                        continue;
566
                case IP_FW_F_SKIPTO:
567
#ifdef DIAGNOSTIC
568
                        while (chain->chain.le_next
569
                            && chain->chain.le_next->rule->fw_number
570
                                < f->fw_skipto_rule)
571
#else
572
                        while (chain->chain.le_next->rule->fw_number
573
                            < f->fw_skipto_rule)
574
#endif
575
                                chain = chain->chain.le_next;
576
                        continue;
577
                }
578
 
579
                /* Deny/reject this packet using this rule */
580
                rule = f;
581
                break;
582
        }
583
 
584
#ifdef DIAGNOSTIC
585
        /* Rule 65535 should always be there and should always match */
586
        if (!chain)
587
                panic("ip_fw: chain");
588
#endif
589
 
590
        /*
591
         * At this point, we're going to drop the packet.
592
         * Send a reject notice if all of the following are true:
593
         *
594
         * - The packet matched a reject rule
595
         * - The packet is not an ICMP packet
596
         * - The packet is not a multicast or broadcast packet
597
         */
598
        if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
599
            && ip->ip_p != IPPROTO_ICMP
600
            && !((*m)->m_flags & (M_BCAST|M_MCAST))
601
            && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
602
                switch (rule->fw_reject_code) {
603
                case IP_FW_REJECT_RST:
604
                  {
605
                        struct tcphdr *const tcp =
606
                                (struct tcphdr *) ((u_long *)ip + ip->ip_hl);
607
                        struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;
608
 
609
                        if (offset != 0 || (tcp->th_flags & TH_RST))
610
                                break;
611
                        ti.ti_i = *((struct ipovly *) ip);
612
                        ti.ti_t = *tcp;
613
                        bcopy(&ti, ip, sizeof(ti));
614
                        NTOHL(tip->ti_seq);
615
                        NTOHL(tip->ti_ack);
616
                        tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
617
                        if (tcp->th_flags & TH_ACK) {
618
                                tcp_respond(NULL, tip, *m,
619
                                    (tcp_seq)0, ntohl(tcp->th_ack), TH_RST);
620
                        } else {
621
                                if (tcp->th_flags & TH_SYN)
622
                                        tip->ti_len++;
623
                                tcp_respond(NULL, tip, *m, tip->ti_seq
624
                                    + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
625
                        }
626
                        *m = NULL;
627
                        break;
628
                  }
629
                default:        /* Send an ICMP unreachable using code */
630
                        icmp_error(*m, ICMP_UNREACH,
631
                            rule->fw_reject_code, 0L, 0);
632
                        *m = NULL;
633
                        break;
634
                }
635
        }
636
 
637
dropit:
638
        /*
639
         * Finally, drop the packet.
640
         */
641
        if (*m) {
642
                m_freem(*m);
643
                *m = NULL;
644
        }
645
        return(0);
646
}
647
 
648
static int
649
add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl)
650
{
651
        struct ip_fw *ftmp = 0;
652
        struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0;
653
        u_short nbr = 0;
654
        int s;
655
 
656
        fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT);
657
        ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT);
658
        if (!fwc || !ftmp) {
659
                dprintf(("%s malloc said no\n", err_prefix));
660
                if (fwc)  free(fwc, M_IPFW);
661
                if (ftmp) free(ftmp, M_IPFW);
662
                return (ENOSPC);
663
        }
664
 
665
        bcopy(frwl, ftmp, sizeof(struct ip_fw));
666
        ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
667
        ftmp->fw_pcnt = 0L;
668
        ftmp->fw_bcnt = 0L;
669
        fwc->rule = ftmp;
670
 
671
        s = splnet();
672
 
673
        if (!chainptr->lh_first) {
674
                LIST_INSERT_HEAD(chainptr, fwc, chain);
675
                splx(s);
676
                return(0);
677
        } else if (ftmp->fw_number == (u_short)-1) {
678
                if (fwc)  free(fwc, M_IPFW);
679
                if (ftmp) free(ftmp, M_IPFW);
680
                splx(s);
681
                dprintf(("%s bad rule number\n", err_prefix));
682
                return (EINVAL);
683
        }
684
 
685
        /* If entry number is 0, find highest numbered rule and add 100 */
686
        if (ftmp->fw_number == 0) {
687
                for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
688
                        if (fcp->rule->fw_number != (u_short)-1)
689
                                nbr = fcp->rule->fw_number;
690
                        else
691
                                break;
692
                }
693
                if (nbr < (u_short)-1 - 100)
694
                        nbr += 100;
695
                ftmp->fw_number = nbr;
696
        }
697
 
698
        /* Got a valid number; now insert it, keeping the list ordered */
699
        for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
700
                if (fcp->rule->fw_number > ftmp->fw_number) {
701
                        if (fcpl) {
702
                                LIST_INSERT_AFTER(fcpl, fwc, chain);
703
                        } else {
704
                                LIST_INSERT_HEAD(chainptr, fwc, chain);
705
                        }
706
                        break;
707
                } else {
708
                        fcpl = fcp;
709
                }
710
        }
711
 
712
        splx(s);
713
        return (0);
714
}
715
 
716
static int
717
del_entry(struct ip_fw_head *chainptr, u_short number)
718
{
719
        struct ip_fw_chain *fcp;
720
        int s;
721
 
722
        s = splnet();
723
 
724
        fcp = chainptr->lh_first;
725
        if (number != (u_short)-1) {
726
                for (; fcp; fcp = fcp->chain.le_next) {
727
                        if (fcp->rule->fw_number == number) {
728
                                LIST_REMOVE(fcp, chain);
729
                                splx(s);
730
                                free(fcp->rule, M_IPFW);
731
                                free(fcp, M_IPFW);
732
                                return 0;
733
                        }
734
                }
735
        }
736
 
737
        splx(s);
738
        return (EINVAL);
739
}
740
 
741
static int
742
zero_entry(struct mbuf *m)
743
{
744
        struct ip_fw *frwl;
745
        struct ip_fw_chain *fcp;
746
        int s;
747
 
748
        if (m) {
749
                if (m->m_len != sizeof(struct ip_fw))
750
                        return(EINVAL);
751
                frwl = mtod(m, struct ip_fw *);
752
        }
753
        else
754
                frwl = NULL;
755
 
756
        /*
757
         *      It's possible to insert multiple chain entries with the
758
         *      same number, so we don't stop after finding the first
759
         *      match if zeroing a specific entry.
760
         */
761
        s = splnet();
762
        for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
763
                if (!frwl || frwl->fw_number == fcp->rule->fw_number) {
764
                        fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
765
                        fcp->rule->timestamp = 0;
766
                }
767
        splx(s);
768
 
769
        if (fw_verbose) {
770
                if (frwl)
771
                        printf("ipfw: Entry %d cleared.\n", frwl->fw_number);
772
                else
773
                        printf("ipfw: Accounting cleared.\n");
774
        }
775
 
776
        return(0);
777
}
778
 
779
static struct ip_fw *
780
check_ipfw_mbuf(struct mbuf *m)
781
{
782
        /* Check length */
783
        if (m->m_len != sizeof(struct ip_fw)) {
784
                dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
785
                    (int)sizeof(struct ip_fw)));
786
                return (NULL);
787
        }
788
        return(check_ipfw_struct(mtod(m, struct ip_fw *)));
789
}
790
 
791
static struct ip_fw *
792
check_ipfw_struct(struct ip_fw *frwl)
793
{
794
        /* Check for invalid flag bits */
795
        if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) {
796
                dprintf(("%s undefined flag bits set (flags=%x)\n",
797
                    err_prefix, frwl->fw_flg));
798
                return (NULL);
799
        }
800
        /* Must apply to incoming or outgoing (or both) */
801
        if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) {
802
                dprintf(("%s neither in nor out\n", err_prefix));
803
                return (NULL);
804
        }
805
        /* Empty interface name is no good */
806
        if (((frwl->fw_flg & IP_FW_F_IIFNAME)
807
              && !*frwl->fw_in_if.fu_via_if.name)
808
            || ((frwl->fw_flg & IP_FW_F_OIFNAME)
809
              && !*frwl->fw_out_if.fu_via_if.name)) {
810
                dprintf(("%s empty interface name\n", err_prefix));
811
                return (NULL);
812
        }
813
        /* Sanity check interface matching */
814
        if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
815
                ;               /* allow "via" backwards compatibility */
816
        } else if ((frwl->fw_flg & IP_FW_F_IN)
817
            && (frwl->fw_flg & IP_FW_F_OIFACE)) {
818
                dprintf(("%s outgoing interface check on incoming\n",
819
                    err_prefix));
820
                return (NULL);
821
        }
822
        /* Sanity check port ranges */
823
        if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) {
824
                dprintf(("%s src range set but n_src_p=%d\n",
825
                    err_prefix, IP_FW_GETNSRCP(frwl)));
826
                return (NULL);
827
        }
828
        if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) {
829
                dprintf(("%s dst range set but n_dst_p=%d\n",
830
                    err_prefix, IP_FW_GETNDSTP(frwl)));
831
                return (NULL);
832
        }
833
        if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) {
834
                dprintf(("%s too many ports (%d+%d)\n",
835
                    err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl)));
836
                return (NULL);
837
        }
838
        /*
839
         *      Protocols other than TCP/UDP don't use port range
840
         */
841
        if ((frwl->fw_prot != IPPROTO_TCP) &&
842
            (frwl->fw_prot != IPPROTO_UDP) &&
843
            (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) {
844
                dprintf(("%s port(s) specified for non TCP/UDP rule\n",
845
                    err_prefix));
846
                return(NULL);
847
        }
848
 
849
        /*
850
         *      Rather than modify the entry to make such entries work,
851
         *      we reject this rule and require user level utilities
852
         *      to enforce whatever policy they deem appropriate.
853
         */
854
        if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
855
                (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
856
                dprintf(("%s rule never matches\n", err_prefix));
857
                return(NULL);
858
        }
859
 
860
        if ((frwl->fw_flg & IP_FW_F_FRAG) &&
861
                (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
862
                if (frwl->fw_nports) {
863
                        dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
864
                        return(NULL);
865
                }
866
                if (frwl->fw_prot == IPPROTO_TCP &&
867
                        frwl->fw_tcpf != frwl->fw_tcpnf) {
868
                        dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix));
869
                        return(NULL);
870
                }
871
        }
872
 
873
        /* Check command specific stuff */
874
        switch (frwl->fw_flg & IP_FW_F_COMMAND)
875
        {
876
        case IP_FW_F_REJECT:
877
                if (frwl->fw_reject_code >= 0x100
878
                    && !(frwl->fw_prot == IPPROTO_TCP
879
                      && frwl->fw_reject_code == IP_FW_REJECT_RST)) {
880
                        dprintf(("%s unknown reject code\n", err_prefix));
881
                        return(NULL);
882
                }
883
                break;
884
        case IP_FW_F_DIVERT:            /* Diverting to port zero is invalid */
885
        case IP_FW_F_TEE:
886
                if (frwl->fw_divert_port == 0) {
887
                        dprintf(("%s can't divert to port 0\n", err_prefix));
888
                        return (NULL);
889
                }
890
                break;
891
        case IP_FW_F_DENY:
892
        case IP_FW_F_ACCEPT:
893
        case IP_FW_F_COUNT:
894
        case IP_FW_F_SKIPTO:
895
                break;
896
        default:
897
                dprintf(("%s invalid command\n", err_prefix));
898
                return(NULL);
899
        }
900
 
901
        return frwl;
902
}
903
 
904
static int
905
ip_fw_ctl(int stage, struct mbuf **mm)
906
{
907
        int error;
908
        struct mbuf *m;
909
 
910
        if (stage == IP_FW_GET) {
911
                struct ip_fw_chain *fcp = ip_fw_chain.lh_first;
912
                *mm = m = m_get(M_WAIT, MT_SOOPTS);
913
                for (; fcp; fcp = fcp->chain.le_next) {
914
                        memcpy(m->m_data, fcp->rule, sizeof *(fcp->rule));
915
                        m->m_len = sizeof *(fcp->rule);
916
                        m->m_next = m_get(M_WAIT, MT_SOOPTS);
917
                        m = m->m_next;
918
                        m->m_len = 0;
919
                }
920
                return (0);
921
        }
922
        m = *mm;
923
        /* only allow get calls if secure mode > 2 */
924
        if (securelevel > 2) {
925
                if (m) (void)m_free(m);
926
                return(EPERM);
927
        }
928
        if (stage == IP_FW_FLUSH) {
929
                while (ip_fw_chain.lh_first != NULL &&
930
                    ip_fw_chain.lh_first->rule->fw_number != (u_short)-1) {
931
                        struct ip_fw_chain *fcp = ip_fw_chain.lh_first;
932
                        int s = splnet();
933
                        LIST_REMOVE(ip_fw_chain.lh_first, chain);
934
                        splx(s);
935
                        free(fcp->rule, M_IPFW);
936
                        free(fcp, M_IPFW);
937
                }
938
                if (m) (void)m_free(m);
939
                return (0);
940
        }
941
        if (stage == IP_FW_ZERO) {
942
                error = zero_entry(m);
943
                if (m) (void)m_free(m);
944
                return (error);
945
        }
946
        if (m == NULL) {
947
                printf("%s NULL mbuf ptr\n", err_prefix);
948
                return (EINVAL);
949
        }
950
 
951
        if (stage == IP_FW_ADD) {
952
                struct ip_fw *frwl = check_ipfw_mbuf(m);
953
 
954
                if (!frwl)
955
                        error = EINVAL;
956
                else
957
                        error = add_entry(&ip_fw_chain, frwl);
958
                if (m) (void)m_free(m);
959
                return error;
960
        }
961
        if (stage == IP_FW_DEL) {
962
                if (m->m_len != sizeof(struct ip_fw)) {
963
                        dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
964
                            (int)sizeof(struct ip_fw)));
965
                        error = EINVAL;
966
                } else if (mtod(m, struct ip_fw *)->fw_number == (u_short)-1) {
967
                        dprintf(("%s can't delete rule 65535\n", err_prefix));
968
                        error = EINVAL;
969
                } else
970
                        error = del_entry(&ip_fw_chain,
971
                            mtod(m, struct ip_fw *)->fw_number);
972
                if (m) (void)m_free(m);
973
                return error;
974
        }
975
 
976
        dprintf(("%s unknown request %d\n", err_prefix, stage));
977
        if (m) (void)m_free(m);
978
        return (EINVAL);
979
}
980
 
981
void
982
ip_fw_init(void)
983
{
984
        struct ip_fw default_rule;
985
 
986
        ip_fw_chk_ptr = ip_fw_chk;
987
        ip_fw_ctl_ptr = ip_fw_ctl;
988
        LIST_INIT(&ip_fw_chain);
989
 
990
        bzero(&default_rule, sizeof default_rule);
991
        default_rule.fw_prot = IPPROTO_IP;
992
        default_rule.fw_number = (u_short)-1;
993
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
994
        default_rule.fw_flg |= IP_FW_F_ACCEPT;
995
#else
996
        default_rule.fw_flg |= IP_FW_F_DENY;
997
#endif
998
        default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT;
999
        if (check_ipfw_struct(&default_rule) == NULL ||
1000
                add_entry(&ip_fw_chain, &default_rule))
1001
                panic(__FUNCTION__);
1002
 
1003
        printf("IP packet filtering initialized, "
1004
#ifdef IPDIVERT
1005
                "divert enabled, ");
1006
#else
1007
                "divert disabled, ");
1008
#endif
1009
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
1010
        printf("default to accept, ");
1011
#endif
1012
#ifndef IPFIREWALL_VERBOSE
1013
        printf("logging disabled\n");
1014
#else
1015
        if (fw_verbose_limit == 0)
1016
                printf("unlimited logging\n");
1017
        else
1018
                printf("logging limited to %d packets/entry\n",
1019
                    fw_verbose_limit);
1020
#endif
1021
}
1022
 
1023
#ifdef IPFIREWALL_MODULE
1024
 
1025
#include <sys/exec.h>
1026
#include <sys/sysent.h>
1027
#include <sys/lkm.h>
1028
 
1029
MOD_MISC(ipfw);
1030
 
1031
static int
1032
ipfw_load(struct lkm_table *lkmtp, int cmd)
1033
{
1034
        int s=splnet();
1035
 
1036
        old_chk_ptr = ip_fw_chk_ptr;
1037
        old_ctl_ptr = ip_fw_ctl_ptr;
1038
 
1039
        ip_fw_init();
1040
        splx(s);
1041
        return 0;
1042
}
1043
 
1044
static int
1045
ipfw_unload(struct lkm_table *lkmtp, int cmd)
1046
{
1047
        int s=splnet();
1048
 
1049
        ip_fw_chk_ptr =  old_chk_ptr;
1050
        ip_fw_ctl_ptr =  old_ctl_ptr;
1051
 
1052
        while (ip_fw_chain.lh_first != NULL) {
1053
                struct ip_fw_chain *fcp = ip_fw_chain.lh_first;
1054
                LIST_REMOVE(ip_fw_chain.lh_first, chain);
1055
                free(fcp->rule, M_IPFW);
1056
                free(fcp, M_IPFW);
1057
        }
1058
 
1059
        splx(s);
1060
        printf("IP firewall unloaded\n");
1061
        return 0;
1062
}
1063
 
1064
int
1065
ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver)
1066
{
1067
        DISPATCH(lkmtp, cmd, ver, ipfw_load, ipfw_unload, lkm_nullcmd);
1068
}
1069
#endif

powered by: WebSVN 2.1.0

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