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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet6/] [ip6_fw.c] - Blame information for rev 307

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/ip6_fw.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*      $KAME: ip6_fw.c,v 1.29 2001/12/18 02:23:44 itojun Exp $ */
23
 
24
/*
25
 * Copyright (C) 1998, 1999, 2000 and 2001 WIDE Project.
26
 * All rights reserved.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. Neither the name of the project nor the names of its contributors
37
 *    may be used to endorse or promote products derived from this software
38
 *    without specific prior written permission.
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 */
52
 
53
/*
54
 * Copyright (c) 1993 Daniel Boulet
55
 * Copyright (c) 1994 Ugen J.S.Antsilevich
56
 * Copyright (c) 1996 Alex Nash
57
 *
58
 * Redistribution and use in source forms, with and without modification,
59
 * are permitted provided that this entire comment appears intact.
60
 *
61
 * Redistribution in binary form may occur without any restrictions.
62
 * Obviously, it would be nice if you gave credit where credit is due
63
 * but requiring it would be too onerous.
64
 *
65
 * This software is provided ``AS IS'' without any warranties of any kind.
66
 */
67
 
68
/*
69
 * Implement IPv6 packet firewall
70
 */
71
 
72
#ifdef IP6DIVERT
73
#error "NOT SUPPORTED IPV6 DIVERT"
74
#endif
75
#ifdef IP6FW_DIVERT_RESTART
76
#error "NOT SUPPORTED IPV6 DIVERT"
77
#endif
78
 
79
#include <sys/param.h>
80
#include <sys/systm.h>
81
#include <sys/malloc.h>
82
#include <sys/mbuf.h>
83
#include <sys/queue.h>
84
#include <sys/kernel.h>
85
#include <sys/socket.h>
86
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
87
#include <sys/socketvar.h>
88
#endif
89
#include <sys/syslog.h>
90
#include <sys/time.h>
91
#include <net/if.h>
92
#include <net/route.h>
93
#include <netinet/in_systm.h>
94
#include <netinet/in.h>
95
#include <netinet/ip.h>
96
 
97
#include <netinet/ip6.h>
98
#include <netinet6/ip6_var.h>
99
#include <netinet6/in6_var.h>
100
#include <netinet/icmp6.h>
101
 
102
#include <netinet/in_pcb.h>
103
 
104
#include <netinet6/ip6_fw.h>
105
#ifdef TCP6
106
#include <netinet6/tcp6.h>
107
#include <netinet6/tcp6_timer.h>
108
#include <netinet6/tcp6_var.h>
109
#endif
110
#include <netinet/ip_var.h>
111
#include <netinet/tcp.h>
112
#include <netinet/tcp_seq.h>
113
#include <netinet/tcp_timer.h>
114
#include <netinet/tcp_var.h>
115
#include <netinet/udp.h>
116
 
117
#if defined(__NetBSD__) || defined(__OpenBSD__)
118
#include <vm/vm.h>
119
#endif
120
#ifdef __FreeBSD__
121
#include <sys/sysctl.h>
122
#endif
123
 
124
#include <net/net_osdep.h>
125
 
126
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
127
MALLOC_DEFINE(M_IP6FW, "Ip6Fw/Ip6Acct", "Ip6Fw/Ip6Acct chain's");
128
#else
129
#ifndef M_IP6FW
130
#define M_IP6FW M_TEMP
131
#endif
132
#endif
133
 
134
#ifndef LOG_SECURITY
135
#define LOG_SECURITY LOG_AUTH
136
#endif
137
static int fw6_debug = 1;
138
#ifdef IPV6FIREWALL_VERBOSE
139
static int fw6_verbose = 1;
140
#else
141
static int fw6_verbose = 0;
142
#endif
143
#ifdef IPV6FIREWALL_VERBOSE_LIMIT
144
static int fw6_verbose_limit = IPV6FIREWALL_VERBOSE_LIMIT;
145
#else
146
static int fw6_verbose_limit = 0;
147
#endif
148
 
149
LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain;
150
 
151
#ifdef SYSCTL_NODE
152
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
153
SYSCTL_DECL(_net_inet6_ip6);
154
#endif
155
SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
156
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
157
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, enable, CTLFLAG_RW,
158
        &ip6_fw_enable, 0, "Enable ip6fw");
159
#endif
160
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, debug, CTLFLAG_RW, &fw6_debug, 0, "");
161
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw6_verbose, 0, "");
162
SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw6_verbose_limit, 0, "");
163
#endif
164
 
165
#define dprintf(a)      do {                                            \
166
                                if (fw6_debug)                          \
167
                                        printf a;                       \
168
                        } while (0)
169
#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
170
 
171
static int      add_entry6 __P((struct ip6_fw_head *chainptr, struct ip6_fw *frwl));
172
static int      del_entry6 __P((struct ip6_fw_head *chainptr, u_short number));
173
static int      zero_entry6 __P((struct mbuf *m));
174
static struct ip6_fw *check_ip6fw_struct __P((struct ip6_fw *m));
175
static struct ip6_fw *check_ip6fw_mbuf __P((struct mbuf *fw));
176
static int      ip6opts_match __P((struct ip6_hdr **ip6, struct ip6_fw *f,
177
                                   struct mbuf **m,
178
                                   int *off, int *nxt, u_short *offset));
179
static int      port_match6 __P((u_short *portptr, int nports, u_short port,
180
                                int range_flag));
181
static int      tcp6flg_match __P((struct tcphdr *tcp6, struct ip6_fw *f));
182
static int      icmp6type_match __P((struct icmp6_hdr *  icmp, struct ip6_fw * f));
183
static void     ip6fw_report __P((struct ip6_fw *f, struct ip6_hdr *ip6,
184
                                struct ifnet *rif, struct ifnet *oif, int off, int nxt));
185
 
186
static int      ip6_fw_chk __P((struct ip6_hdr **pip6, struct ifnet *oif,
187
                                struct mbuf **m));
188
static int      ip6_fw_ctl __P((int stage, struct mbuf **mm));
189
 
190
static char err_prefix[] = "ip6_fw_ctl:";
191
 
192
/*
193
 * Returns 1 if the port is matched by the vector, 0 otherwise
194
 */
195
static
196
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
197
__inline
198
#else
199
inline
200
#endif
201
int
202
port_match6(u_short *portptr, int nports, u_short port, int range_flag)
203
{
204
        if (!nports)
205
                return 1;
206
        if (range_flag) {
207
                if (portptr[0] <= port && port <= portptr[1]) {
208
                        return 1;
209
                }
210
                nports -= 2;
211
                portptr += 2;
212
        }
213
        while (nports-- > 0) {
214
                if (*portptr++ == port) {
215
                        return 1;
216
                }
217
        }
218
        return 0;
219
}
220
 
221
static int
222
tcp6flg_match(struct tcphdr *tcp6, struct ip6_fw *f)
223
{
224
        u_char          flg_set, flg_clr;
225
 
226
        /*
227
         * If an established connection is required, reject packets that
228
         * have only SYN of RST|ACK|SYN set.  Otherwise, fall through to
229
         * other flag requirements.
230
         */
231
        if ((f->fw_ipflg & IPV6_FW_IF_TCPEST) &&
232
            ((tcp6->th_flags & (IPV6_FW_TCPF_RST | IPV6_FW_TCPF_ACK |
233
            IPV6_FW_TCPF_SYN)) == IPV6_FW_TCPF_SYN))
234
                return 0;
235
 
236
        flg_set = tcp6->th_flags & f->fw_tcpf;
237
        flg_clr = tcp6->th_flags & f->fw_tcpnf;
238
 
239
        if (flg_set != f->fw_tcpf)
240
                return 0;
241
        if (flg_clr)
242
                return 0;
243
 
244
        return 1;
245
}
246
 
247
static int
248
icmp6type_match(struct icmp6_hdr *icmp6, struct ip6_fw *f)
249
{
250
        int type;
251
 
252
        if (!(f->fw_flg & IPV6_FW_F_ICMPBIT))
253
                return(1);
254
 
255
        type = icmp6->icmp6_type;
256
 
257
        /* check for matching type in the bitmap */
258
        if (type < IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8 &&
259
                (f->fw_icmp6types[type / (sizeof(unsigned) * 8)] &
260
                (1U << (type % (8 * sizeof(unsigned))))))
261
                return(1);
262
 
263
        return(0); /* no match */
264
}
265
 
266
static int
267
is_icmp6_query(struct ip6_hdr *ip6, int off)
268
{
269
        const struct icmp6_hdr *icmp6;
270
        int icmp6_type;
271
 
272
        icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
273
        icmp6_type = icmp6->icmp6_type;
274
 
275
        if (icmp6_type == ICMP6_ECHO_REQUEST ||
276
            icmp6_type == ICMP6_MEMBERSHIP_QUERY ||
277
            icmp6_type == ICMP6_WRUREQUEST ||
278
            icmp6_type == ICMP6_FQDN_QUERY ||
279
            icmp6_type == ICMP6_NI_QUERY)
280
                return(1);
281
 
282
        return(0);
283
}
284
 
285
static int
286
ip6opts_match(struct ip6_hdr **pip6, struct ip6_fw *f, struct mbuf **m,
287
              int *off, int *nxt, u_short *offset)
288
{
289
        int len;
290
        struct ip6_hdr *ip6 = *pip6;
291
        struct ip6_ext *ip6e;
292
        u_char  opts, nopts, nopts_sve;
293
 
294
        opts = f->fw_ip6opt;
295
        nopts = nopts_sve = f->fw_ip6nopt;
296
 
297
        *nxt = ip6->ip6_nxt;
298
        *off = sizeof(struct ip6_hdr);
299
        len = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr);
300
        while (*off < len) {
301
                ip6e = (struct ip6_ext *)((caddr_t) ip6 + *off);
302
                if ((*m)->m_len < *off + sizeof(*ip6e))
303
                        goto opts_check;        /* XXX */
304
 
305
                switch (*nxt) {
306
                case IPPROTO_FRAGMENT:
307
                        if ((*m)->m_len >= *off + sizeof(struct ip6_frag)) {
308
                                struct ip6_frag *ip6f;
309
 
310
                                ip6f = (struct ip6_frag *) ((caddr_t)ip6 + *off);
311
                                *offset = ip6f->ip6f_offlg & IP6F_OFF_MASK;
312
                        }
313
                        opts &= ~IPV6_FW_IP6OPT_FRAG;
314
                        nopts &= ~IPV6_FW_IP6OPT_FRAG;
315
                        *off += sizeof(struct ip6_frag);
316
                        break;
317
                case IPPROTO_AH:
318
                        opts &= ~IPV6_FW_IP6OPT_AH;
319
                        nopts &= ~IPV6_FW_IP6OPT_AH;
320
                        *off += (ip6e->ip6e_len + 2) << 2;
321
                        break;
322
                default:
323
                        switch (*nxt) {
324
                        case IPPROTO_HOPOPTS:
325
                                opts &= ~IPV6_FW_IP6OPT_HOPOPT;
326
                                nopts &= ~IPV6_FW_IP6OPT_HOPOPT;
327
                                break;
328
                        case IPPROTO_ROUTING:
329
                                opts &= ~IPV6_FW_IP6OPT_ROUTE;
330
                                nopts &= ~IPV6_FW_IP6OPT_ROUTE;
331
                                break;
332
                        case IPPROTO_ESP:
333
                                opts &= ~IPV6_FW_IP6OPT_ESP;
334
                                nopts &= ~IPV6_FW_IP6OPT_ESP;
335
                                break;
336
                        case IPPROTO_NONE:
337
                                opts &= ~IPV6_FW_IP6OPT_NONXT;
338
                                nopts &= ~IPV6_FW_IP6OPT_NONXT;
339
                                goto opts_check;
340
                                break;
341
                        case IPPROTO_DSTOPTS:
342
                                opts &= ~IPV6_FW_IP6OPT_OPTS;
343
                                nopts &= ~IPV6_FW_IP6OPT_OPTS;
344
                                break;
345
                        default:
346
                                goto opts_check;
347
                                break;
348
                        }
349
                        *off += (ip6e->ip6e_len + 1) << 3;
350
                        break;
351
                }
352
                *nxt = ip6e->ip6e_nxt;
353
 
354
        }
355
 opts_check:
356
        if (f->fw_ip6opt == f->fw_ip6nopt)      /* XXX */
357
                return 1;
358
 
359
        if (opts == 0 && nopts == nopts_sve)
360
                return 1;
361
        else
362
                return 0;
363
}
364
 
365
static
366
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
367
__inline
368
#else
369
inline
370
#endif
371
int
372
iface_match(struct ifnet *ifp, union ip6_fw_if *ifu, int byname)
373
{
374
        /* Check by name or by IP address */
375
        if (byname) {
376
#ifdef __NetBSD__
377
            {
378
                char xname[IFNAMSIZ];
379
                snprintf(xname, sizeof(xname), "%s%d", ifu->fu_via_if.name,
380
                        ifu->fu_via_if.unit);
381
                if (strcmp(ifp->if_xname, xname))
382
                        return(0);
383
            }
384
#else
385
                /* Check unit number (-1 is wildcard) */
386
                if (ifu->fu_via_if.unit != -1
387
                    && ifp->if_unit != ifu->fu_via_if.unit)
388
                        return(0);
389
                /* Check name */
390
                if (strncmp(ifp->if_name, ifu->fu_via_if.name, IP6FW_IFNLEN))
391
                        return(0);
392
#endif
393
                return(1);
394
        } else if (!IN6_IS_ADDR_UNSPECIFIED(&ifu->fu_via_ip6)) {        /* Zero == wildcard */
395
                struct ifaddr *ia;
396
 
397
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
398
                for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next)
399
#else
400
                for (ia = ifp->if_addrlist.tqh_first; ia; ia = ia->ifa_list.tqe_next)
401
#endif
402
                {
403
 
404
                        if (ia->ifa_addr == NULL)
405
                                continue;
406
                        if (ia->ifa_addr->sa_family != AF_INET6)
407
                                continue;
408
                        if (!IN6_ARE_ADDR_EQUAL(&ifu->fu_via_ip6,
409
                            &(((struct sockaddr_in6 *)
410
                            (ia->ifa_addr))->sin6_addr)))
411
                                continue;
412
                        return(1);
413
                }
414
                return(0);
415
        }
416
        return(1);
417
}
418
 
419
static void
420
ip6fw_report(struct ip6_fw *f, struct ip6_hdr *ip6,
421
        struct ifnet *rif, struct ifnet *oif, int off, int nxt)
422
{
423
        static int counter;
424
        struct tcphdr *const tcp6 = (struct tcphdr *) ((caddr_t) ip6+ off);
425
        struct udphdr *const udp = (struct udphdr *) ((caddr_t) ip6+ off);
426
        struct icmp6_hdr *const icmp6 = (struct icmp6_hdr *) ((caddr_t) ip6+ off);
427
        int count;
428
        char *action;
429
        char action2[32], proto[102], name[18];
430
        int len;
431
 
432
        count = f ? f->fw_pcnt : ++counter;
433
        if (fw6_verbose_limit != 0 && count > fw6_verbose_limit)
434
                return;
435
 
436
        /* Print command name */
437
        snprintf(SNPARGS(name, 0), "ip6fw: %d", f ? f->fw_number : -1);
438
 
439
        action = action2;
440
        if (!f)
441
                action = "Refuse";
442
        else {
443
                switch (f->fw_flg & IPV6_FW_F_COMMAND) {
444
                case IPV6_FW_F_DENY:
445
                        action = "Deny";
446
                        break;
447
                case IPV6_FW_F_REJECT:
448
                        if (f->fw_reject_code == IPV6_FW_REJECT_RST)
449
                                action = "Reset";
450
                        else
451
                                action = "Unreach";
452
                        break;
453
                case IPV6_FW_F_ACCEPT:
454
                        action = "Accept";
455
                        break;
456
                case IPV6_FW_F_COUNT:
457
                        action = "Count";
458
                        break;
459
                case IPV6_FW_F_DIVERT:
460
                        snprintf(SNPARGS(action2, 0), "Divert %d",
461
                            f->fw_divert_port);
462
                        break;
463
                case IPV6_FW_F_TEE:
464
                        snprintf(SNPARGS(action2, 0), "Tee %d",
465
                            f->fw_divert_port);
466
                        break;
467
                case IPV6_FW_F_SKIPTO:
468
                        snprintf(SNPARGS(action2, 0), "SkipTo %d",
469
                            f->fw_skipto_rule);
470
                        break;
471
                default:
472
                        action = "UNKNOWN";
473
                        break;
474
                }
475
        }
476
 
477
        switch (nxt) {
478
        case IPPROTO_TCP:
479
                len = snprintf(SNPARGS(proto, 0), "TCP [%s]",
480
                    ip6_sprintf(&ip6->ip6_src));
481
                if (off > 0)
482
                        len += snprintf(SNPARGS(proto, len), ":%d ",
483
                            ntohs(tcp6->th_sport));
484
                else
485
                        len += snprintf(SNPARGS(proto, len), " ");
486
                len += snprintf(SNPARGS(proto, len), "[%s]",
487
                    ip6_sprintf(&ip6->ip6_dst));
488
                if (off > 0)
489
                        snprintf(SNPARGS(proto, len), ":%d",
490
                            ntohs(tcp6->th_dport));
491
                break;
492
        case IPPROTO_UDP:
493
                len = snprintf(SNPARGS(proto, 0), "UDP [%s]",
494
                    ip6_sprintf(&ip6->ip6_src));
495
                if (off > 0)
496
                        len += snprintf(SNPARGS(proto, len), ":%d ",
497
                            ntohs(udp->uh_sport));
498
                else
499
                    len += snprintf(SNPARGS(proto, len), " ");
500
                len += snprintf(SNPARGS(proto, len), "[%s]",
501
                    ip6_sprintf(&ip6->ip6_dst));
502
                if (off > 0)
503
                        snprintf(SNPARGS(proto, len), ":%d",
504
                            ntohs(udp->uh_dport));
505
                break;
506
        case IPPROTO_ICMPV6:
507
                if (off > 0)
508
                        len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ",
509
                            icmp6->icmp6_type, icmp6->icmp6_code);
510
                else
511
                        len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP ");
512
                len += snprintf(SNPARGS(proto, len), "[%s]",
513
                    ip6_sprintf(&ip6->ip6_src));
514
                snprintf(SNPARGS(proto, len), " [%s]",
515
                    ip6_sprintf(&ip6->ip6_dst));
516
                break;
517
        default:
518
                len = snprintf(SNPARGS(proto, 0), "P:%d [%s]", nxt,
519
                    ip6_sprintf(&ip6->ip6_src));
520
                snprintf(SNPARGS(proto, len), " [%s]",
521
                    ip6_sprintf(&ip6->ip6_dst));
522
                break;
523
        }
524
 
525
        if (oif)
526
                log(LOG_SECURITY | LOG_INFO, "%s %s %s out via %s\n",
527
                    name, action, proto, if_name(oif));
528
        else if (rif)
529
                log(LOG_SECURITY | LOG_INFO, "%s %s %s in via %s\n",
530
                    name, action, proto, if_name(rif));
531
        else
532
                log(LOG_SECURITY | LOG_INFO, "%s %s %s",
533
                    name, action, proto);
534
        if (fw6_verbose_limit != 0 && count == fw6_verbose_limit)
535
            log(LOG_SECURITY | LOG_INFO, "ip6fw: limit reached on entry %d\n",
536
                f ? f->fw_number : -1);
537
}
538
 
539
/*
540
 * Parameters:
541
 *
542
 *      ip      Pointer to packet header (struct ip6_hdr *)
543
 *      hlen    Packet header length
544
 *      oif     Outgoing interface, or NULL if packet is incoming
545
 *      *m      The packet; we set to NULL when/if we nuke it.
546
 *
547
 * Return value:
548
 *
549
 *      0        The packet is to be accepted and routed normally OR
550
 *              the packet was denied/rejected and has been dropped;
551
 *              in the latter case, *m is equal to NULL upon return.
552
 *      port    Divert the packet to port.
553
 */
554
 
555
static int
556
ip6_fw_chk(struct ip6_hdr **pip6,
557
        struct ifnet *oif, struct mbuf **m)
558
{
559
        struct ip6_fw_chain *chain;
560
        struct ip6_fw *rule = NULL;
561
        struct ip6_hdr *ip6 = *pip6;
562
        struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
563
        u_short offset = 0;
564
        int off = sizeof(struct ip6_hdr), nxt = ip6->ip6_nxt;
565
        u_short src_port, dst_port;
566
#ifdef  IP6FW_DIVERT_RESTART
567
        u_int16_t skipto = 0;
568
#else
569
        u_int16_t ignport = 0;
570
#endif
571
 
572
        /*
573
         * Go down the chain, looking for enlightment
574
         * #ifdef IP6FW_DIVERT_RESTART
575
         * If we've been asked to start at a given rule immediatly, do so.
576
         * #endif
577
         */
578
        chain = LIST_FIRST(&ip6_fw_chain);
579
#ifdef IP6FW_DIVERT_RESTART
580
        if (skipto) {
581
                if (skipto >= 65535)
582
                        goto dropit;
583
                while (chain && (chain->rule->fw_number <= skipto)) {
584
                        chain = LIST_NEXT(chain, chain);
585
                }
586
                if (! chain) goto dropit;
587
        }
588
#endif /* IP6FW_DIVERT_RESTART */
589
        for (; chain; chain = LIST_NEXT(chain, chain)) {
590
                struct ip6_fw *const f = chain->rule;
591
 
592
                if (oif) {
593
                        /* Check direction outbound */
594
                        if (!(f->fw_flg & IPV6_FW_F_OUT))
595
                                continue;
596
                } else {
597
                        /* Check direction inbound */
598
                        if (!(f->fw_flg & IPV6_FW_F_IN))
599
                                continue;
600
                }
601
 
602
#define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\
603
        (((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \
604
        (((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \
605
        (((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \
606
        (((x)->s6_addr32[3] & (y)->s6_addr32[3]) == (z)->s6_addr32[3]))
607
 
608
                /* If src-addr doesn't match, not this rule. */
609
                if (((f->fw_flg & IPV6_FW_F_INVSRC) != 0) ^
610
                        (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_src,&f->fw_smsk,&f->fw_src)))
611
                        continue;
612
 
613
                /* If dest-addr doesn't match, not this rule. */
614
                if (((f->fw_flg & IPV6_FW_F_INVDST) != 0) ^
615
                        (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_dst,&f->fw_dmsk,&f->fw_dst)))
616
                        continue;
617
 
618
#undef IN6_ARE_ADDR_MASKEQUAL
619
                /* Interface check */
620
                if ((f->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
621
                        struct ifnet *const iface = oif ? oif : rif;
622
 
623
                        /* Backwards compatibility hack for "via" */
624
                        if (!iface || !iface_match(iface,
625
                            &f->fw_in_if, f->fw_flg & IPV6_FW_F_OIFNAME))
626
                                continue;
627
                } else {
628
                        /* Check receive interface */
629
                        if ((f->fw_flg & IPV6_FW_F_IIFACE)
630
                            && (!rif || !iface_match(rif,
631
                              &f->fw_in_if, f->fw_flg & IPV6_FW_F_IIFNAME)))
632
                                continue;
633
                        /* Check outgoing interface */
634
                        if ((f->fw_flg & IPV6_FW_F_OIFACE)
635
                            && (!oif || !iface_match(oif,
636
                              &f->fw_out_if, f->fw_flg & IPV6_FW_F_OIFNAME)))
637
                                continue;
638
                }
639
 
640
                /* Check IP options */
641
                if (!ip6opts_match(&ip6, f, m, &off, &nxt, &offset))
642
                        continue;
643
 
644
                /* Fragments */
645
                if ((f->fw_flg & IPV6_FW_F_FRAG) && !offset)
646
                        continue;
647
 
648
                /* Check protocol; if wildcard, match */
649
                if (f->fw_prot == IPPROTO_IPV6)
650
                        goto got_match;
651
 
652
                /* If different, don't match */
653
                if (nxt != f->fw_prot)
654
                        continue;
655
 
656
#define PULLUP_TO(len)  do {                                            \
657
                            if ((*m)->m_len < (len)                     \
658
                                && (*m = m_pullup(*m, (len))) == 0) {    \
659
                                    goto dropit;                        \
660
                            }                                           \
661
                            *pip6 = ip6 = mtod(*m, struct ip6_hdr *);   \
662
                        } while (0)
663
 
664
                /* Protocol specific checks */
665
                switch (nxt) {
666
                case IPPROTO_TCP:
667
                    {
668
                        struct tcphdr *tcp6;
669
 
670
                        if (offset == 1) {      /* cf. RFC 1858 */
671
                                PULLUP_TO(off + 4); /* XXX ? */
672
                                goto bogusfrag;
673
                        }
674
                        if (offset != 0) {
675
                                /*
676
                                 * TCP flags and ports aren't available in this
677
                                 * packet -- if this rule specified either one,
678
                                 * we consider the rule a non-match.
679
                                 */
680
                                if (f->fw_nports != 0 ||
681
                                    f->fw_tcpf != f->fw_tcpnf)
682
                                        continue;
683
 
684
                                break;
685
                        }
686
                        PULLUP_TO(off + 14);
687
                        tcp6 = (struct tcphdr *) ((caddr_t)ip6 + off);
688
                        if (((f->fw_tcpf != f->fw_tcpnf) ||
689
                           (f->fw_ipflg & IPV6_FW_IF_TCPEST))  &&
690
                           !tcp6flg_match(tcp6, f))
691
                                continue;
692
                        src_port = ntohs(tcp6->th_sport);
693
                        dst_port = ntohs(tcp6->th_dport);
694
                        goto check_ports;
695
                    }
696
 
697
                case IPPROTO_UDP:
698
                    {
699
                        struct udphdr *udp;
700
 
701
                        if (offset != 0) {
702
                                /*
703
                                 * Port specification is unavailable -- if this
704
                                 * rule specifies a port, we consider the rule
705
                                 * a non-match.
706
                                 */
707
                                if (f->fw_nports != 0)
708
                                        continue;
709
 
710
                                break;
711
                        }
712
                        PULLUP_TO(off + 4);
713
                        udp = (struct udphdr *) ((caddr_t)ip6 + off);
714
                        src_port = ntohs(udp->uh_sport);
715
                        dst_port = ntohs(udp->uh_dport);
716
check_ports:
717
                        if (!port_match6(&f->fw_pts[0],
718
                            IPV6_FW_GETNSRCP(f), src_port,
719
                            f->fw_flg & IPV6_FW_F_SRNG))
720
                                continue;
721
                        if (!port_match6(&f->fw_pts[IPV6_FW_GETNSRCP(f)],
722
                            IPV6_FW_GETNDSTP(f), dst_port,
723
                            f->fw_flg & IPV6_FW_F_DRNG))
724
                                continue;
725
                        break;
726
                    }
727
 
728
                case IPPROTO_ICMPV6:
729
                    {
730
                        struct icmp6_hdr *icmp;
731
 
732
                        if (offset != 0) /* Type isn't valid */
733
                                break;
734
                        PULLUP_TO(off + 2);
735
                        icmp = (struct icmp6_hdr *) ((caddr_t)ip6 + off);
736
                        if (!icmp6type_match(icmp, f))
737
                                continue;
738
                        break;
739
                    }
740
#undef PULLUP_TO
741
 
742
bogusfrag:
743
                        if (fw6_verbose)
744
                                ip6fw_report(NULL, ip6, rif, oif, off, nxt);
745
                        goto dropit;
746
                }
747
 
748
got_match:
749
#ifndef IP6FW_DIVERT_RESTART
750
                /* Ignore divert/tee rule if socket port is "ignport" */
751
                switch (f->fw_flg & IPV6_FW_F_COMMAND) {
752
                case IPV6_FW_F_DIVERT:
753
                case IPV6_FW_F_TEE:
754
                        if (f->fw_divert_port == ignport)
755
                                continue;       /* ignore this rule */
756
                        break;
757
                }
758
 
759
#endif /* IP6FW_DIVERT_RESTART */
760
                /* Update statistics */
761
                f->fw_pcnt += 1;
762
                f->fw_bcnt += ntohs(ip6->ip6_plen);
763
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
764
                f->timestamp = time_second;
765
#else
766
                f->timestamp = time.tv_sec;
767
#endif
768
 
769
                /* Log to console if desired */
770
                if ((f->fw_flg & IPV6_FW_F_PRN) && fw6_verbose)
771
                        ip6fw_report(f, ip6, rif, oif, off, nxt);
772
 
773
                /* Take appropriate action */
774
                switch (f->fw_flg & IPV6_FW_F_COMMAND) {
775
                case IPV6_FW_F_ACCEPT:
776
                        return(0);
777
                case IPV6_FW_F_COUNT:
778
                        continue;
779
                case IPV6_FW_F_DIVERT:
780
                        return(f->fw_divert_port);
781
                case IPV6_FW_F_TEE:
782
                        /*
783
                         * XXX someday tee packet here, but beware that you
784
                         * can't use m_copym() or m_copypacket() because
785
                         * the divert input routine modifies the mbuf
786
                         * (and these routines only increment reference
787
                         * counts in the case of mbuf clusters), so need
788
                         * to write custom routine.
789
                         */
790
                        continue;
791
                case IPV6_FW_F_SKIPTO:
792
#ifdef DIAGNOSTIC
793
                        while (chain->chain.le_next
794
                            && chain->chain.le_next->rule->fw_number
795
                                < f->fw_skipto_rule)
796
#else
797
                        while (chain->chain.le_next->rule->fw_number
798
                            < f->fw_skipto_rule)
799
#endif
800
                                chain = chain->chain.le_next;
801
                        continue;
802
                }
803
 
804
                /* Deny/reject this packet using this rule */
805
                rule = f;
806
                break;
807
        }
808
 
809
#ifdef DIAGNOSTIC
810
        /* Rule 65535 should always be there and should always match */
811
        if (!chain)
812
                panic("ip6_fw: chain");
813
#endif
814
 
815
        /*
816
         * At this point, we're going to drop the packet.
817
         * Send a reject notice if all of the following are true:
818
         *
819
         * - The packet matched a reject rule
820
         * - The packet is not an ICMP packet, or is an ICMP query packet
821
         * - The packet is not a multicast or broadcast packet
822
         */
823
        if ((rule->fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT
824
            && (nxt != IPPROTO_ICMPV6 || is_icmp6_query(ip6, off))
825
            && !((*m)->m_flags & (M_BCAST|M_MCAST))
826
            && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
827
                switch (rule->fw_reject_code) {
828
                case IPV6_FW_REJECT_RST:
829
#if 1   /* not tested */
830
                  {
831
                        struct tcphdr *const tcp =
832
                                (struct tcphdr *) ((caddr_t)ip6 + off);
833
                        struct {
834
                                struct ip6_hdr ip6;
835
                                struct tcphdr th;
836
                        } ti;
837
                        tcp_seq ack, seq;
838
                        int flags;
839
 
840
                        if (offset != 0 || (tcp->th_flags & TH_RST))
841
                                break;
842
 
843
                        ti.ip6 = *ip6;
844
                        ti.th = *tcp;
845
                        NTOHL(ti.th.th_seq);
846
                        NTOHL(ti.th.th_ack);
847
                        ti.ip6.ip6_nxt = IPPROTO_TCP;
848
                        if (ti.th.th_flags & TH_ACK) {
849
                                ack = 0;
850
                                seq = ti.th.th_ack;
851
                                flags = TH_RST;
852
                        } else {
853
                                ack = ti.th.th_seq;
854
                                if (((*m)->m_flags & M_PKTHDR) != 0) {
855
                                        ack += (*m)->m_pkthdr.len - off
856
                                                - (ti.th.th_off << 2);
857
                                } else if (ip6->ip6_plen) {
858
                                        ack += ntohs(ip6->ip6_plen) + sizeof(*ip6)
859
                                                - off - (ti.th.th_off << 2);
860
                                } else {
861
                                        m_freem(*m);
862
                                        *m = 0;
863
                                        break;
864
                                }
865
                                seq = 0;
866
                                flags = TH_RST|TH_ACK;
867
                        }
868
                        bcopy(&ti, ip6, sizeof(ti));
869
#ifdef TCP6
870
                        tcp6_respond(NULL, ip6, (struct tcp6hdr *)(ip6 + 1),
871
                                *m, ack, seq, flags);
872
#elif defined(__NetBSD__)
873
                        tcp_respond(NULL, NULL, *m, (struct tcphdr *)(ip6 + 1),
874
                                ack, seq, flags);
875
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
876
                        tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
877
                                *m, ack, seq, flags);
878
#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
879
                        tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
880
                                *m, ack, seq, flags, 1);
881
#else
882
                        m_freem(*m);
883
#endif
884
                        *m = NULL;
885
                        break;
886
                  }
887
#endif
888
                default:        /* Send an ICMP unreachable using code */
889
                        if (oif)
890
                                (*m)->m_pkthdr.rcvif = oif;
891
                        icmp6_error(*m, ICMP6_DST_UNREACH,
892
                            rule->fw_reject_code, 0);
893
                        *m = NULL;
894
                        break;
895
                }
896
        }
897
 
898
dropit:
899
        /*
900
         * Finally, drop the packet.
901
         */
902
        if (*m) {
903
                m_freem(*m);
904
                *m = NULL;
905
        }
906
        return(0);
907
}
908
 
909
static int
910
add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
911
{
912
        struct ip6_fw *ftmp = 0;
913
        struct ip6_fw_chain *fwc = 0, *fcp, *fcpl = 0;
914
        u_short nbr = 0;
915
        int s;
916
 
917
        fwc = malloc(sizeof *fwc, M_IP6FW, M_DONTWAIT);
918
        ftmp = malloc(sizeof *ftmp, M_IP6FW, M_DONTWAIT);
919
        if (!fwc || !ftmp) {
920
                dprintf(("%s malloc said no\n", err_prefix));
921
                if (fwc)  free(fwc, M_IP6FW);
922
                if (ftmp) free(ftmp, M_IP6FW);
923
                return (ENOSPC);
924
        }
925
 
926
        bcopy(frwl, ftmp, sizeof(struct ip6_fw));
927
        ftmp->fw_in_if.fu_via_if.name[IP6FW_IFNLEN - 1] = '\0';
928
        ftmp->fw_pcnt = 0L;
929
        ftmp->fw_bcnt = 0L;
930
        fwc->rule = ftmp;
931
 
932
        s = splnet();
933
 
934
        if (!chainptr->lh_first) {
935
                LIST_INSERT_HEAD(chainptr, fwc, chain);
936
                splx(s);
937
                return(0);
938
        } else if (ftmp->fw_number == (u_short)-1) {
939
                if (fwc)  free(fwc, M_IP6FW);
940
                if (ftmp) free(ftmp, M_IP6FW);
941
                splx(s);
942
                dprintf(("%s bad rule number\n", err_prefix));
943
                return (EINVAL);
944
        }
945
 
946
        /* If entry number is 0, find highest numbered rule and add 100 */
947
        if (ftmp->fw_number == 0) {
948
                for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
949
                        if (fcp->rule->fw_number != (u_short)-1)
950
                                nbr = fcp->rule->fw_number;
951
                        else
952
                                break;
953
                }
954
                if (nbr < (u_short)-1 - 100)
955
                        nbr += 100;
956
                ftmp->fw_number = nbr;
957
        }
958
 
959
        /* Got a valid number; now insert it, keeping the list ordered */
960
        for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
961
                if (fcp->rule->fw_number > ftmp->fw_number) {
962
                        if (fcpl) {
963
                                LIST_INSERT_AFTER(fcpl, fwc, chain);
964
                        } else {
965
                                LIST_INSERT_HEAD(chainptr, fwc, chain);
966
                        }
967
                        break;
968
                } else {
969
                        fcpl = fcp;
970
                }
971
        }
972
 
973
        splx(s);
974
        return (0);
975
}
976
 
977
static int
978
del_entry6(struct ip6_fw_head *chainptr, u_short number)
979
{
980
        struct ip6_fw_chain *fcp;
981
        int s;
982
 
983
        s = splnet();
984
 
985
        fcp = chainptr->lh_first;
986
        if (number != (u_short)-1) {
987
                for (; fcp; fcp = fcp->chain.le_next) {
988
                        if (fcp->rule->fw_number == number) {
989
                                LIST_REMOVE(fcp, chain);
990
                                splx(s);
991
                                free(fcp->rule, M_IP6FW);
992
                                free(fcp, M_IP6FW);
993
                                return 0;
994
                        }
995
                }
996
        }
997
 
998
        splx(s);
999
        return (EINVAL);
1000
}
1001
 
1002
static int
1003
zero_entry6(struct mbuf *m)
1004
{
1005
        struct ip6_fw *frwl;
1006
        struct ip6_fw_chain *fcp;
1007
        int s;
1008
 
1009
        if (m && m->m_len != 0) {
1010
                if (m->m_len != sizeof(struct ip6_fw))
1011
                        return(EINVAL);
1012
                frwl = mtod(m, struct ip6_fw *);
1013
        }
1014
        else
1015
                frwl = NULL;
1016
 
1017
        /*
1018
         *      It's possible to insert multiple chain entries with the
1019
         *      same number, so we don't stop after finding the first
1020
         *      match if zeroing a specific entry.
1021
         */
1022
        s = splnet();
1023
        for (fcp = ip6_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
1024
                if (!frwl || frwl->fw_number == fcp->rule->fw_number) {
1025
                        fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
1026
                        fcp->rule->timestamp = 0;
1027
                }
1028
        splx(s);
1029
 
1030
        if (fw6_verbose) {
1031
                if (frwl)
1032
                        log(LOG_SECURITY | LOG_NOTICE,
1033
                            "ip6fw: Entry %d cleared.\n", frwl->fw_number);
1034
                else
1035
                        log(LOG_SECURITY | LOG_NOTICE,
1036
                            "ip6fw: Accounting cleared.\n");
1037
        }
1038
 
1039
        return(0);
1040
}
1041
 
1042
static struct ip6_fw *
1043
check_ip6fw_mbuf(struct mbuf *m)
1044
{
1045
        /* Check length */
1046
        if (m->m_len != sizeof(struct ip6_fw)) {
1047
                dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
1048
                    sizeof(struct ip6_fw)));
1049
                return (NULL);
1050
        }
1051
        return(check_ip6fw_struct(mtod(m, struct ip6_fw *)));
1052
}
1053
 
1054
static struct ip6_fw *
1055
check_ip6fw_struct(struct ip6_fw *frwl)
1056
{
1057
        /* Check for invalid flag bits */
1058
        if ((frwl->fw_flg & ~IPV6_FW_F_MASK) != 0) {
1059
                dprintf(("%s undefined flag bits set (flags=%x)\n",
1060
                    err_prefix, frwl->fw_flg));
1061
                return (NULL);
1062
        }
1063
        /* Must apply to incoming or outgoing (or both) */
1064
        if (!(frwl->fw_flg & (IPV6_FW_F_IN | IPV6_FW_F_OUT))) {
1065
                dprintf(("%s neither in nor out\n", err_prefix));
1066
                return (NULL);
1067
        }
1068
        /* Empty interface name is no good */
1069
        if (((frwl->fw_flg & IPV6_FW_F_IIFNAME)
1070
              && !*frwl->fw_in_if.fu_via_if.name)
1071
            || ((frwl->fw_flg & IPV6_FW_F_OIFNAME)
1072
              && !*frwl->fw_out_if.fu_via_if.name)) {
1073
                dprintf(("%s empty interface name\n", err_prefix));
1074
                return (NULL);
1075
        }
1076
        /* Sanity check interface matching */
1077
        if ((frwl->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
1078
                ;               /* allow "via" backwards compatibility */
1079
        } else if ((frwl->fw_flg & IPV6_FW_F_IN)
1080
            && (frwl->fw_flg & IPV6_FW_F_OIFACE)) {
1081
                dprintf(("%s outgoing interface check on incoming\n",
1082
                    err_prefix));
1083
                return (NULL);
1084
        }
1085
        /* Sanity check port ranges */
1086
        if ((frwl->fw_flg & IPV6_FW_F_SRNG) && IPV6_FW_GETNSRCP(frwl) < 2) {
1087
                dprintf(("%s src range set but n_src_p=%d\n",
1088
                    err_prefix, IPV6_FW_GETNSRCP(frwl)));
1089
                return (NULL);
1090
        }
1091
        if ((frwl->fw_flg & IPV6_FW_F_DRNG) && IPV6_FW_GETNDSTP(frwl) < 2) {
1092
                dprintf(("%s dst range set but n_dst_p=%d\n",
1093
                    err_prefix, IPV6_FW_GETNDSTP(frwl)));
1094
                return (NULL);
1095
        }
1096
        if (IPV6_FW_GETNSRCP(frwl) + IPV6_FW_GETNDSTP(frwl) > IPV6_FW_MAX_PORTS) {
1097
                dprintf(("%s too many ports (%d+%d)\n",
1098
                    err_prefix, IPV6_FW_GETNSRCP(frwl), IPV6_FW_GETNDSTP(frwl)));
1099
                return (NULL);
1100
        }
1101
        /*
1102
         *      Protocols other than TCP/UDP don't use port range
1103
         */
1104
        if ((frwl->fw_prot != IPPROTO_TCP) &&
1105
            (frwl->fw_prot != IPPROTO_UDP) &&
1106
            (IPV6_FW_GETNSRCP(frwl) || IPV6_FW_GETNDSTP(frwl))) {
1107
                dprintf(("%s port(s) specified for non TCP/UDP rule\n",
1108
                    err_prefix));
1109
                return(NULL);
1110
        }
1111
 
1112
        /*
1113
         *      Rather than modify the entry to make such entries work,
1114
         *      we reject this rule and require user level utilities
1115
         *      to enforce whatever policy they deem appropriate.
1116
         */
1117
        if ((frwl->fw_src.s6_addr32[0] & (~frwl->fw_smsk.s6_addr32[0])) ||
1118
                (frwl->fw_src.s6_addr32[1] & (~frwl->fw_smsk.s6_addr32[1])) ||
1119
                (frwl->fw_src.s6_addr32[2] & (~frwl->fw_smsk.s6_addr32[2])) ||
1120
                (frwl->fw_src.s6_addr32[3] & (~frwl->fw_smsk.s6_addr32[3])) ||
1121
                (frwl->fw_dst.s6_addr32[0] & (~frwl->fw_dmsk.s6_addr32[0])) ||
1122
                (frwl->fw_dst.s6_addr32[1] & (~frwl->fw_dmsk.s6_addr32[1])) ||
1123
                (frwl->fw_dst.s6_addr32[2] & (~frwl->fw_dmsk.s6_addr32[2])) ||
1124
                (frwl->fw_dst.s6_addr32[3] & (~frwl->fw_dmsk.s6_addr32[3]))) {
1125
                dprintf(("%s rule never matches\n", err_prefix));
1126
                return(NULL);
1127
        }
1128
 
1129
        if ((frwl->fw_flg & IPV6_FW_F_FRAG) &&
1130
                (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1131
                if (frwl->fw_nports) {
1132
                        dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
1133
                        return(NULL);
1134
                }
1135
                if (frwl->fw_prot == IPPROTO_TCP &&
1136
                        frwl->fw_tcpf != frwl->fw_tcpnf) {
1137
                        dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix));
1138
                        return(NULL);
1139
                }
1140
        }
1141
 
1142
        /* Check command specific stuff */
1143
        switch (frwl->fw_flg & IPV6_FW_F_COMMAND)
1144
        {
1145
        case IPV6_FW_F_REJECT:
1146
                if (frwl->fw_reject_code >= 0x100
1147
                    && !(frwl->fw_prot == IPPROTO_TCP
1148
                      && frwl->fw_reject_code == IPV6_FW_REJECT_RST)) {
1149
                        dprintf(("%s unknown reject code\n", err_prefix));
1150
                        return(NULL);
1151
                }
1152
                break;
1153
        case IPV6_FW_F_DIVERT:          /* Diverting to port zero is invalid */
1154
        case IPV6_FW_F_TEE:
1155
                if (frwl->fw_divert_port == 0) {
1156
                        dprintf(("%s can't divert to port 0\n", err_prefix));
1157
                        return (NULL);
1158
                }
1159
                break;
1160
        case IPV6_FW_F_DENY:
1161
        case IPV6_FW_F_ACCEPT:
1162
        case IPV6_FW_F_COUNT:
1163
        case IPV6_FW_F_SKIPTO:
1164
                break;
1165
        default:
1166
                dprintf(("%s invalid command\n", err_prefix));
1167
                return(NULL);
1168
        }
1169
 
1170
        return frwl;
1171
}
1172
 
1173
static int
1174
ip6_fw_ctl(int stage, struct mbuf **mm)
1175
{
1176
        int error;
1177
        struct mbuf *m;
1178
 
1179
        if (stage == IPV6_FW_GET) {
1180
                struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
1181
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1182
                *mm = m = m_get(M_WAIT, MT_DATA); /* XXX */
1183
#else
1184
                *mm = m = m_get(M_WAIT, MT_SOOPTS);
1185
#endif
1186
                if (!m)
1187
                        return(ENOBUFS);
1188
                if (sizeof *(fcp->rule) > MLEN) {
1189
                        MCLGET(m, M_WAIT);
1190
                        if ((m->m_flags & M_EXT) == 0) {
1191
                                m_free(m);
1192
                                return(ENOBUFS);
1193
                        }
1194
                }
1195
                for (; fcp; fcp = fcp->chain.le_next) {
1196
                        bcopy(fcp->rule, m->m_data, sizeof *(fcp->rule));
1197
                        m->m_len = sizeof *(fcp->rule);
1198
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1199
                        m->m_next = m_get(M_WAIT, MT_DATA); /* XXX */
1200
#else
1201
                        m->m_next = m_get(M_WAIT, MT_SOOPTS);
1202
#endif
1203
                        if (!m->m_next) {
1204
                                m_freem(*mm);
1205
                                return(ENOBUFS);
1206
                        }
1207
                        m = m->m_next;
1208
                        if (sizeof *(fcp->rule) > MLEN) {
1209
                                MCLGET(m, M_WAIT);
1210
                                if ((m->m_flags & M_EXT) == 0) {
1211
                                        m_freem(*mm);
1212
                                        return(ENOBUFS);
1213
                                }
1214
                        }
1215
                        m->m_len = 0;
1216
                }
1217
                return (0);
1218
        }
1219
        m = *mm;
1220
        /* only allow get calls if secure mode > 2 */
1221
        if (securelevel > 2) {
1222
                if (m) {
1223
                        (void)m_freem(m);
1224
                        *mm = 0;
1225
                }
1226
                return(EPERM);
1227
        }
1228
        if (stage == IPV6_FW_FLUSH) {
1229
                while (ip6_fw_chain.lh_first != NULL &&
1230
                    ip6_fw_chain.lh_first->rule->fw_number != (u_short)-1) {
1231
                        struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
1232
                        int s = splnet();
1233
                        LIST_REMOVE(ip6_fw_chain.lh_first, chain);
1234
                        splx(s);
1235
                        free(fcp->rule, M_IP6FW);
1236
                        free(fcp, M_IP6FW);
1237
                }
1238
                if (m) {
1239
                        (void)m_freem(m);
1240
                        *mm = 0;
1241
                }
1242
                return (0);
1243
        }
1244
        if (stage == IPV6_FW_ZERO) {
1245
                error = zero_entry6(m);
1246
                if (m) {
1247
                        (void)m_freem(m);
1248
                        *mm = 0;
1249
                }
1250
                return (error);
1251
        }
1252
        if (m == NULL) {
1253
                printf("%s NULL mbuf ptr\n", err_prefix);
1254
                return (EINVAL);
1255
        }
1256
 
1257
        if (stage == IPV6_FW_ADD) {
1258
                struct ip6_fw *frwl = check_ip6fw_mbuf(m);
1259
 
1260
                if (!frwl)
1261
                        error = EINVAL;
1262
                else
1263
                        error = add_entry6(&ip6_fw_chain, frwl);
1264
                if (m) {
1265
                        (void)m_freem(m);
1266
                        *mm = 0;
1267
                }
1268
                return error;
1269
        }
1270
        if (stage == IPV6_FW_DEL) {
1271
                if (m->m_len != sizeof(struct ip6_fw)) {
1272
                        dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
1273
                            sizeof(struct ip6_fw)));
1274
                        error = EINVAL;
1275
                } else if (mtod(m, struct ip6_fw *)->fw_number == (u_short)-1) {
1276
                        dprintf(("%s can't delete rule 65535\n", err_prefix));
1277
                        error = EINVAL;
1278
                } else
1279
                        error = del_entry6(&ip6_fw_chain,
1280
                            mtod(m, struct ip6_fw *)->fw_number);
1281
                if (m) {
1282
                        (void)m_freem(m);
1283
                        *mm = 0;
1284
                }
1285
                return error;
1286
        }
1287
 
1288
        dprintf(("%s unknown request %d\n", err_prefix, stage));
1289
        if (m) {
1290
                (void)m_freem(m);
1291
                *mm = 0;
1292
        }
1293
        return (EINVAL);
1294
}
1295
 
1296
void
1297
ip6_fw_init(void)
1298
{
1299
        struct ip6_fw default_rule;
1300
 
1301
        ip6_fw_chk_ptr = ip6_fw_chk;
1302
        ip6_fw_ctl_ptr = ip6_fw_ctl;
1303
        LIST_INIT(&ip6_fw_chain);
1304
 
1305
        bzero(&default_rule, sizeof default_rule);
1306
        default_rule.fw_prot = IPPROTO_IPV6;
1307
        default_rule.fw_number = (u_short)-1;
1308
#ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1309
        default_rule.fw_flg |= IPV6_FW_F_ACCEPT;
1310
#else
1311
        default_rule.fw_flg |= IPV6_FW_F_DENY;
1312
#endif
1313
        default_rule.fw_flg |= IPV6_FW_F_IN | IPV6_FW_F_OUT;
1314
        if (check_ip6fw_struct(&default_rule) == NULL ||
1315
                add_entry6(&ip6_fw_chain, &default_rule))
1316
                panic(__FUNCTION__);
1317
 
1318
#if 1   /* NOT SUPPORTED IPV6 DIVERT */
1319
        printf("IPv6 packet filtering initialized, ");
1320
#else
1321
        printf("IPv6 packet filtering initialized, "
1322
#ifdef IP6DIVERT
1323
                "divert enabled, ");
1324
#else
1325
                "divert disabled, ");
1326
#endif
1327
#endif
1328
#ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1329
        printf("default to accept, ");
1330
#endif
1331
#ifndef IPV6FIREWALL_VERBOSE
1332
        printf("logging disabled\n");
1333
#else
1334
        if (fw6_verbose_limit == 0)
1335
                printf("unlimited logging\n");
1336
        else
1337
                printf("logging limited to %d packets/entry\n",
1338
                    fw6_verbose_limit);
1339
#endif
1340
}
1341
 
1342
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
1343
static ip6_fw_chk_t *old_chk_ptr;
1344
static ip6_fw_ctl_t *old_ctl_ptr;
1345
 
1346
static int
1347
ip6fw_modevent(module_t mod, int type, void *unused)
1348
{
1349
        int s;
1350
 
1351
        switch (type) {
1352
        case MOD_LOAD:
1353
                s = splnet();
1354
 
1355
                old_chk_ptr = ip6_fw_chk_ptr;
1356
                old_ctl_ptr = ip6_fw_ctl_ptr;
1357
 
1358
                ip6_fw_init();
1359
                splx(s);
1360
                return 0;
1361
        case MOD_UNLOAD:
1362
                s = splnet();
1363
                ip6_fw_chk_ptr =  old_chk_ptr;
1364
                ip6_fw_ctl_ptr =  old_ctl_ptr;
1365
                while (LIST_FIRST(&ip6_fw_chain) != NULL) {
1366
                        struct ip6_fw_chain *fcp = LIST_FIRST(&ip6_fw_chain);
1367
                        LIST_REMOVE(LIST_FIRST(&ip6_fw_chain), chain);
1368
                        free(fcp->rule, M_IP6FW);
1369
                        free(fcp, M_IP6FW);
1370
                }
1371
 
1372
                splx(s);
1373
                printf("IPv6 firewall unloaded\n");
1374
                return 0;
1375
        default:
1376
                break;
1377
        }
1378
        return 0;
1379
}
1380
 
1381
static moduledata_t ip6fwmod = {
1382
        "ip6fw",
1383
        ip6fw_modevent,
1384
 
1385
};
1386
DECLARE_MODULE(ip6fw, ip6fwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
1387
#endif
1388
 
1389
 

powered by: WebSVN 2.1.0

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