Annotation of XNU/bsd/netinet/ip_fw.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Copyright (c) 1993 Daniel Boulet
                     24:  * Copyright (c) 1994 Ugen J.S.Antsilevich
                     25:  * Copyright (c) 1996 Alex Nash
                     26:  *
                     27:  * Redistribution and use in source forms, with and without modification,
                     28:  * are permitted provided that this entire comment appears intact.
                     29:  *
                     30:  * Redistribution in binary form may occur without any restrictions.
                     31:  * Obviously, it would be nice if you gave credit where credit is due
                     32:  * but requiring it would be too onerous.
                     33:  *
                     34:  * This software is provided ``AS IS'' without any warranties of any kind.
                     35:  *
                     36:  */
                     37: 
                     38: /*
                     39:  * Implement IP packet firewall
                     40:  */
                     41: #if ISFB31
                     42: #if !defined(KLD_MODULE) && !defined(IPFIREWALL_MODULE)
                     43: #include "opt_ipfw.h"
                     44: #include "opt_ipdn.h"
                     45: #include "opt_ipdivert.h"
                     46: #include "opt_inet.h"
                     47: #endif
                     48: #endif
                     49: #ifndef INET
                     50: #error IPFIREWALL requires INET.
                     51: #endif /* INET */
                     52: 
                     53: #include <sys/param.h>
                     54: #include <sys/systm.h>
                     55: #include <sys/malloc.h>
                     56: #include <sys/mbuf.h>
                     57: #include <sys/kernel.h>
                     58: #include <sys/socket.h>
                     59: #include <sys/socketvar.h>
                     60: #include <sys/sysctl.h>
                     61: #include <net/if.h>
                     62: #include <netinet/in.h>
                     63: #include <netinet/in_systm.h>
                     64: #include <netinet/ip.h>
                     65: #include <netinet/ip_var.h>
                     66: #include <netinet/ip_icmp.h>
                     67: #include <netinet/ip_fw.h>
                     68: #if DUMMYNET
                     69: #include <net/route.h>
                     70: #include <netinet/ip_dummynet.h>
                     71: #endif
                     72: #include <netinet/tcp.h>
                     73: #include <netinet/tcp_timer.h>
                     74: #include <netinet/tcp_var.h>
                     75: #include <netinet/tcpip.h>
                     76: #include <netinet/udp.h>
                     77: 
                     78: #include <netinet/if_ether.h> /* XXX ethertype_ip */
                     79: 
                     80: static int fw_debug = 1;
                     81: #if IPFIREWALL_VERBOSE
                     82: static int fw_verbose = 1;
                     83: #else
                     84: static int fw_verbose = 0;
                     85: #endif
                     86: static int fw_one_pass = 0; /* XXX */
                     87: #if IPFIREWALL_VERBOSE_LIMIT
                     88: static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
                     89: #else
                     90: static int fw_verbose_limit = 0;
                     91: #endif
                     92: 
                     93: #define        IPFW_DEFAULT_RULE       ((u_int)(u_short)~0)
                     94: 
                     95: LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;
                     96: 
                     97: MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
                     98: 
                     99: SYSCTL_DECL(_net_inet_ip);
                    100: SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
                    101: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "");
                    102: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, "");
                    103: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "");
                    104: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "");
                    105: 
                    106: #define dprintf(a)     if (!fw_debug); else kprintf a
                    107: 
                    108: #define print_ip(a)    kprintf("%d.%d.%d.%d",                          \
                    109:                            (int)(ntohl(a.s_addr) >> 24) & 0xFF,        \
                    110:                            (int)(ntohl(a.s_addr) >> 16) & 0xFF,        \
                    111:                            (int)(ntohl(a.s_addr) >> 8) & 0xFF,         \
                    112:                            (int)(ntohl(a.s_addr)) & 0xFF);
                    113: 
                    114: #define dprint_ip(a)   if (!fw_debug); else print_ip(a)
                    115: 
                    116: static int     add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));
                    117: static int     del_entry __P((struct ip_fw_head *chainptr, u_short number));
                    118: static int     zero_entry __P((struct ip_fw *));
                    119: static int     check_ipfw_struct __P((struct ip_fw *m));
                    120: static __inline int
                    121:                iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu,
                    122:                                 int byname));
                    123: static int     ipopts_match __P((struct ip *ip, struct ip_fw *f));
                    124: static __inline int
                    125:                port_match __P((u_short *portptr, int nports, u_short port,
                    126:                                int range_flag));
                    127: static int     tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));
                    128: static int     icmptype_match __P((struct icmp *  icmp, struct ip_fw * f));
                    129: static void    ipfw_report __P((struct ip_fw *f, struct ip *ip,
                    130:                                struct ifnet *rif, struct ifnet *oif));
                    131: 
                    132: static void flush_rule_ptrs(void);
                    133: 
                    134: static int     ip_fw_chk __P((struct ip **pip, int hlen,
                    135:                        struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
                    136:                        struct ip_fw_chain **flow_id,
                    137:                        struct sockaddr_in **next_hop));
                    138: static int     ip_fw_ctl __P((struct sockopt *sopt));
                    139: 
                    140: static char err_prefix[] = "ip_fw_ctl:";
                    141: 
                    142: /*
                    143:  * Returns 1 if the port is matched by the vector, 0 otherwise
                    144:  */
                    145: static __inline int 
                    146: port_match(u_short *portptr, int nports, u_short port, int range_flag)
                    147: {
                    148:        if (!nports)
                    149:                return 1;
                    150:        if (range_flag) {
                    151:                if (portptr[0] <= port && port <= portptr[1]) {
                    152:                        return 1;
                    153:                }
                    154:                nports -= 2;
                    155:                portptr += 2;
                    156:        }
                    157:        while (nports-- > 0) {
                    158:                if (*portptr++ == port) {
                    159:                        return 1;
                    160:                }
                    161:        }
                    162:        return 0;
                    163: }
                    164: 
                    165: static int
                    166: tcpflg_match(struct tcphdr *tcp, struct ip_fw *f)
                    167: {
                    168:        u_char          flg_set, flg_clr;
                    169:        
                    170:        if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) &&
                    171:            (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK)))
                    172:                return 1;
                    173: 
                    174:        flg_set = tcp->th_flags & f->fw_tcpf;
                    175:        flg_clr = tcp->th_flags & f->fw_tcpnf;
                    176: 
                    177:        if (flg_set != f->fw_tcpf)
                    178:                return 0;
                    179:        if (flg_clr)
                    180:                return 0;
                    181: 
                    182:        return 1;
                    183: }
                    184: 
                    185: static int
                    186: icmptype_match(struct icmp *icmp, struct ip_fw *f)
                    187: {
                    188:        int type;
                    189: 
                    190:        if (!(f->fw_flg & IP_FW_F_ICMPBIT))
                    191:                return(1);
                    192: 
                    193:        type = icmp->icmp_type;
                    194: 
                    195:        /* check for matching type in the bitmap */
                    196:        if (type < IP_FW_ICMPTYPES_MAX &&
                    197:                (f->fw_uar.fw_icmptypes[type / (sizeof(unsigned) * 8)] & 
                    198:                (1U << (type % (8 * sizeof(unsigned))))))
                    199:                return(1);
                    200: 
                    201:        return(0); /* no match */
                    202: }
                    203: 
                    204: static int
                    205: is_icmp_query(struct ip *ip)
                    206: {
                    207:        const struct icmp *icmp;
                    208:        int icmp_type;
                    209: 
                    210:        icmp = (struct icmp *)((u_int32_t *)ip + ip->ip_hl);
                    211:        icmp_type = icmp->icmp_type;
                    212: 
                    213:        if (icmp_type == ICMP_ECHO || icmp_type == ICMP_ROUTERSOLICIT ||
                    214:            icmp_type == ICMP_TSTAMP || icmp_type == ICMP_IREQ ||
                    215:            icmp_type == ICMP_MASKREQ)
                    216:                return(1);
                    217: 
                    218:        return(0);
                    219: }
                    220: 
                    221: static int
                    222: ipopts_match(struct ip *ip, struct ip_fw *f)
                    223: {
                    224:        register u_char *cp;
                    225:        int opt, optlen, cnt;
                    226:        u_char  opts, nopts, nopts_sve;
                    227: 
                    228:        cp = (u_char *)(ip + 1);
                    229:        cnt = (ip->ip_hl << 2) - sizeof (struct ip);
                    230:        opts = f->fw_ipopt;
                    231:        nopts = nopts_sve = f->fw_ipnopt;
                    232: 
                    233:        for (; cnt > 0; cnt -= optlen, cp += optlen) {
                    234:                opt = cp[IPOPT_OPTVAL];
                    235:                if (opt == IPOPT_EOL)
                    236:                        break;
                    237:                if (opt == IPOPT_NOP)
                    238:                        optlen = 1;
                    239:                else {
                    240:                        optlen = cp[IPOPT_OLEN];
                    241:                        if (optlen <= 0 || optlen > cnt) {
                    242:                                return 0; /*XXX*/
                    243:                        }
                    244:                }
                    245:                switch (opt) {
                    246: 
                    247:                default:
                    248:                        break;
                    249: 
                    250:                case IPOPT_LSRR:
                    251:                        opts &= ~IP_FW_IPOPT_LSRR;
                    252:                        nopts &= ~IP_FW_IPOPT_LSRR;
                    253:                        break;
                    254: 
                    255:                case IPOPT_SSRR:
                    256:                        opts &= ~IP_FW_IPOPT_SSRR;
                    257:                        nopts &= ~IP_FW_IPOPT_SSRR;
                    258:                        break;
                    259: 
                    260:                case IPOPT_RR:
                    261:                        opts &= ~IP_FW_IPOPT_RR;
                    262:                        nopts &= ~IP_FW_IPOPT_RR;
                    263:                        break;
                    264:                case IPOPT_TS:
                    265:                        opts &= ~IP_FW_IPOPT_TS;
                    266:                        nopts &= ~IP_FW_IPOPT_TS;
                    267:                        break;
                    268:                }
                    269:                if (opts == nopts)
                    270:                        break;
                    271:        }
                    272:        if (opts == 0 && nopts == nopts_sve)
                    273:                return 1;
                    274:        else
                    275:                return 0;
                    276: }
                    277: 
                    278: static __inline int
                    279: iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
                    280: {
                    281:        /* Check by name or by IP address */
                    282:        if (byname) {
                    283:                /* Check unit number (-1 is wildcard) */
                    284:                if (ifu->fu_via_if.unit != -1
                    285:                    && ifp->if_unit != ifu->fu_via_if.unit)
                    286:                        return(0);
                    287:                /* Check name */
                    288:                if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN))
                    289:                        return(0);
                    290:                return(1);
                    291:        } else if (ifu->fu_via_ip.s_addr != 0) {        /* Zero == wildcard */
                    292:                struct ifaddr *ia;
                    293: 
                    294:                for (ia = ifp->if_addrhead.tqh_first;
                    295:                    ia != NULL; ia = ia->ifa_link.tqe_next) {
                    296:                        if (ia->ifa_addr == NULL)
                    297:                                continue;
                    298:                        if (ia->ifa_addr->sa_family != AF_INET)
                    299:                                continue;
                    300:                        if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *)
                    301:                            (ia->ifa_addr))->sin_addr.s_addr)
                    302:                                continue;
                    303:                        return(1);
                    304:                }
                    305:                return(0);
                    306:        }
                    307:        return(1);
                    308: }
                    309: 
                    310: static void
                    311: ipfw_report(struct ip_fw *f, struct ip *ip,
                    312:        struct ifnet *rif, struct ifnet *oif)
                    313: {
                    314:     if (ip) {
                    315:        static u_int64_t counter;
                    316:        struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl);
                    317:        struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl);
                    318:        struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl);
                    319:        int count;
                    320: 
                    321:        count = f ? f->fw_pcnt : ++counter;
                    322:        if (fw_verbose_limit != 0 && count > fw_verbose_limit)
                    323:                return;
                    324: 
                    325:        /* Print command name */
                    326:        kprintf("ipfw: %d ", f ? f->fw_number : -1);
                    327:        if (!f)
                    328:                kprintf("Refuse");
                    329:        else
                    330:                switch (f->fw_flg & IP_FW_F_COMMAND) {
                    331:                case IP_FW_F_DENY:
                    332:                        kprintf("Deny");
                    333:                        break;
                    334:                case IP_FW_F_REJECT:
                    335:                        if (f->fw_reject_code == IP_FW_REJECT_RST)
                    336:                                kprintf("Reset");
                    337:                        else
                    338:                                kprintf("Unreach");
                    339:                        break;
                    340:                case IP_FW_F_ACCEPT:
                    341:                        kprintf("Accept");
                    342:                        break;
                    343:                case IP_FW_F_COUNT:
                    344:                        kprintf("Count");
                    345:                        break;
                    346:                case IP_FW_F_DIVERT:
                    347:                        kprintf("Divert %d", f->fw_divert_port);
                    348:                        break;
                    349:                case IP_FW_F_TEE:
                    350:                        kprintf("Tee %d", f->fw_divert_port);
                    351:                        break;
                    352:                case IP_FW_F_SKIPTO:
                    353:                        kprintf("SkipTo %d", f->fw_skipto_rule);
                    354:                        break;
                    355: #if DUMMYNET
                    356:                case IP_FW_F_PIPE:
                    357:                        kprintf("Pipe %d", f->fw_skipto_rule);
                    358:                        break;
                    359: #endif
                    360: #if IPFIREWALL_FORWARD
                    361:                case IP_FW_F_FWD:
                    362:                        kprintf("Forward to ");
                    363:                        print_ip(f->fw_fwd_ip.sin_addr);
                    364:                        if (f->fw_fwd_ip.sin_port)
                    365:                                kprintf(":%d", f->fw_fwd_ip.sin_port);
                    366:                        break;
                    367: #endif
                    368:                default:        
                    369:                        kprintf("UNKNOWN");
                    370:                        break;
                    371:                }
                    372:        kprintf(" ");
                    373: 
                    374:        switch (ip->ip_p) {
                    375:        case IPPROTO_TCP:
                    376:                kprintf("TCP ");
                    377:                print_ip(ip->ip_src);
                    378:                if ((ip->ip_off & IP_OFFMASK) == 0)
                    379:                        kprintf(":%d ", ntohs(tcp->th_sport));
                    380:                else
                    381:                        kprintf(" ");
                    382:                print_ip(ip->ip_dst);
                    383:                if ((ip->ip_off & IP_OFFMASK) == 0)
                    384:                        kprintf(":%d", ntohs(tcp->th_dport));
                    385:                break;
                    386:        case IPPROTO_UDP:
                    387:                kprintf("UDP ");
                    388:                print_ip(ip->ip_src);
                    389:                if ((ip->ip_off & IP_OFFMASK) == 0)
                    390:                        kprintf(":%d ", ntohs(udp->uh_sport));
                    391:                else
                    392:                        kprintf(" ");
                    393:                print_ip(ip->ip_dst);
                    394:                if ((ip->ip_off & IP_OFFMASK) == 0)
                    395:                        kprintf(":%d", ntohs(udp->uh_dport));
                    396:                break;
                    397:        case IPPROTO_ICMP:
                    398:                if ((ip->ip_off & IP_OFFMASK) == 0)
                    399:                        kprintf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code);
                    400:                else
                    401:                        kprintf("ICMP ");
                    402:                print_ip(ip->ip_src);
                    403:                kprintf(" ");
                    404:                print_ip(ip->ip_dst);
                    405:                break;
                    406:        default:
                    407:                kprintf("P:%d ", ip->ip_p);
                    408:                print_ip(ip->ip_src);
                    409:                kprintf(" ");
                    410:                print_ip(ip->ip_dst);
                    411:                break;
                    412:        }
                    413:        if (oif)
                    414:                kprintf(" out via %s%d", oif->if_name, oif->if_unit);
                    415:        else if (rif)
                    416:                kprintf(" in via %s%d", rif->if_name, rif->if_unit);
                    417:        if ((ip->ip_off & IP_OFFMASK)) 
                    418:                kprintf(" Fragment = %d",ip->ip_off & IP_OFFMASK);
                    419:        kprintf("\n");
                    420:        if (fw_verbose_limit != 0 && count == fw_verbose_limit)
                    421:                kprintf("ipfw: limit reached on rule #%d\n",
                    422:                f ? f->fw_number : -1);
                    423:     }
                    424: }
                    425: 
                    426: /*
                    427:  * given an ip_fw_chain *, lookup_next_rule will return a pointer
                    428:  * of the same type to the next one. This can be either the jump
                    429:  * target (for skipto instructions) or the next one in the chain (in
                    430:  * all other cases including a missing jump target).
                    431:  * Backward jumps are not allowed, so start looking from the next
                    432:  * rule...
                    433:  */ 
                    434: static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me);
                    435: 
                    436: static struct ip_fw_chain *
                    437: lookup_next_rule(struct ip_fw_chain *me)
                    438: {
                    439:     struct ip_fw_chain *chain ;
                    440:     int rule = me->rule->fw_skipto_rule ; /* guess... */
                    441: 
                    442:     if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO )
                    443:        for (chain = me->chain.le_next; chain ; chain = chain->chain.le_next )
                    444:            if (chain->rule->fw_number >= rule)
                    445:                 return chain ;
                    446:     return me->chain.le_next ; /* failure or not a skipto */
                    447: }
                    448: 
                    449: /*
                    450:  * Parameters:
                    451:  *
                    452:  *     pip     Pointer to packet header (struct ip **)
                    453:  *      bridge_ipfw extension: pip = NULL means a complete ethernet packet
                    454:  *      including ethernet header in the mbuf. Other fields
                    455:  *      are ignored/invalid.
                    456:  *
                    457:  *     hlen    Packet header length
                    458:  *     oif     Outgoing interface, or NULL if packet is incoming
                    459:  *     *cookie Skip up to the first rule past this rule number;
                    460:  *     *m      The packet; we set to NULL when/if we nuke it.
                    461:  *     *flow_id pointer to the last matching rule (in/out)
                    462:  *     *next_hop socket we are forwarding to (in/out).
                    463:  *
                    464:  * Return value:
                    465:  *
                    466:  *     0       The packet is to be accepted and routed normally OR
                    467:  *             the packet was denied/rejected and has been dropped;
                    468:  *             in the latter case, *m is equal to NULL upon return.
                    469:  *     port    Divert the packet to port.
                    470:  */
                    471: 
                    472: static int 
                    473: ip_fw_chk(struct ip **pip, int hlen,
                    474:        struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
                    475:        struct ip_fw_chain **flow_id,
                    476:         struct sockaddr_in **next_hop)
                    477: {
                    478:        struct ip_fw_chain *chain;
                    479:        struct ip_fw *rule = NULL;
                    480:        struct ip *ip = NULL ;
                    481:        struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
                    482:        u_short offset = 0 ;
                    483:        u_short src_port, dst_port;
                    484:        u_int16_t skipto = *cookie;
                    485: 
                    486:        if (pip) { /* normal ip packet */
                    487:            ip = *pip;
                    488:            offset = (ip->ip_off & IP_OFFMASK);
                    489:        } else { /* bridged or non-ip packet */
                    490:            struct ether_header *eh = mtod(*m, struct ether_header *);
                    491:            switch (ntohs(eh->ether_type)) {
                    492:            case ETHERTYPE_IP :
                    493:                if ((*m)->m_len<sizeof(struct ether_header) + sizeof(struct ip))
                    494:                    goto non_ip ;
                    495:                ip = (struct ip *)(eh + 1 );
                    496:                if (ip->ip_v != IPVERSION)
                    497:                    goto non_ip ;
                    498:                hlen = ip->ip_hl << 2;
                    499:                if (hlen < sizeof(struct ip)) /* minimum header length */
                    500:                    goto non_ip ;
                    501:                if ((*m)->m_len < 14 + hlen + 14) {
                    502:                    kprintf("-- m_len %d, need more...\n", (*m)->m_len);
                    503:                    goto non_ip ;
                    504:                }
                    505:                offset = (ip->ip_off & IP_OFFMASK);
                    506:                break ;
                    507:            default :
                    508: non_ip:         ip = NULL ;
                    509:                break ;
                    510:            }
                    511:        }
                    512: 
                    513:        if (*flow_id) {
                    514:            if (fw_one_pass)
                    515:                return 0 ; /* accept if passed first test */
                    516:            /*
                    517:             * pkt has already been tagged. Look for the next rule
                    518:             * to restart processing
                    519:             */
                    520:            chain = LIST_NEXT( *flow_id, chain);
                    521: 
                    522:            if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL )
                    523:                chain = (*flow_id)->rule->next_rule_ptr =
                    524:                        lookup_next_rule(*flow_id) ;
                    525:                if (! chain) goto dropit;
                    526:        } else {
                    527:        /*
                    528:         * Go down the chain, looking for enlightment
                    529:         * If we've been asked to start at a given rule immediatly, do so.
                    530:         */
                    531:        chain = LIST_FIRST(&ip_fw_chain);
                    532:        if ( skipto ) {
                    533:                if (skipto >= IPFW_DEFAULT_RULE)
                    534:                        goto dropit;
                    535:                while (chain && (chain->rule->fw_number <= skipto)) {
                    536:                        chain = LIST_NEXT(chain, chain);
                    537:                }
                    538:                if (! chain) goto dropit;
                    539:        }
                    540:        }
                    541:        *cookie = 0;
                    542:        for (; chain; chain = LIST_NEXT(chain, chain)) {
                    543:                register struct ip_fw * f ;
                    544: again:
                    545:                f = chain->rule;
                    546: 
                    547:                if (oif) {
                    548:                        /* Check direction outbound */
                    549:                        if (!(f->fw_flg & IP_FW_F_OUT))
                    550:                                continue;
                    551:                } else {
                    552:                        /* Check direction inbound */
                    553:                        if (!(f->fw_flg & IP_FW_F_IN))
                    554:                                continue;
                    555:                }
                    556:                if (ip == NULL ) {
                    557:                    /*
                    558:                     * do relevant checks for non-ip packets:
                    559:                     * after this, only goto got_match or continue
                    560:                     */
                    561:                    struct ether_header *eh = mtod(*m, struct ether_header *);
                    562: 
                    563:                    /*
                    564:                     * make default rule always match or we have a panic
                    565:                     */
                    566:                    if (f->fw_number == IPFW_DEFAULT_RULE)
                    567:                        goto got_match ;
                    568:                    /*
                    569:                     * temporary hack: 
                    570:                     *   udp from 0.0.0.0 means this rule applies.
                    571:                     *   1 src port is match ether type
                    572:                     *   2 src ports (interval) is match ether type
                    573:                     *   3 src ports is match ether address
                    574:                     */
                    575:                    if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP
                    576:                        || f->fw_smsk.s_addr != 0xffffffff )
                    577:                        continue;
                    578:                    switch (IP_FW_GETNSRCP(f)) {
                    579:                    case 1: /* match one type */
                    580:                        if (  /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */
                    581:                                ( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) )  ) {
                    582:                            goto got_match ;
                    583:                        }
                    584:                        break ;
                    585:                    default:
                    586:                        break ;
                    587:                    }
                    588:                    continue ;
                    589:                }
                    590: 
                    591:                /* Fragments */
                    592:                if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 )
                    593:                        continue;
                    594: 
                    595:                /* If src-addr doesn't match, not this rule. */
                    596:                if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr
                    597:                    & f->fw_smsk.s_addr) != f->fw_src.s_addr))
                    598:                        continue;
                    599: 
                    600:                /* If dest-addr doesn't match, not this rule. */
                    601:                if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr
                    602:                    & f->fw_dmsk.s_addr) != f->fw_dst.s_addr))
                    603:                        continue;
                    604: 
                    605:                /* Interface check */
                    606:                if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
                    607:                        struct ifnet *const iface = oif ? oif : rif;
                    608: 
                    609:                        /* Backwards compatibility hack for "via" */
                    610:                        if (!iface || !iface_match(iface,
                    611:                            &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))
                    612:                                continue;
                    613:                } else {
                    614:                        /* Check receive interface */
                    615:                        if ((f->fw_flg & IP_FW_F_IIFACE)
                    616:                            && (!rif || !iface_match(rif,
                    617:                              &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))
                    618:                                continue;
                    619:                        /* Check outgoing interface */
                    620:                        if ((f->fw_flg & IP_FW_F_OIFACE)
                    621:                            && (!oif || !iface_match(oif,
                    622:                              &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))
                    623:                                continue;
                    624:                }
                    625: 
                    626:                /* Check IP options */
                    627:                if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
                    628:                        continue;
                    629: 
                    630:                /* Check protocol; if wildcard, match */
                    631:                if (f->fw_prot == IPPROTO_IP)
                    632:                        goto got_match;
                    633: 
                    634:                /* If different, don't match */
                    635:                if (ip->ip_p != f->fw_prot) 
                    636:                        continue;
                    637: 
                    638: /*
                    639:  * here, pip==NULL for bridged pkts -- they include the ethernet
                    640:  * header so i have to adjust lengths accordingly
                    641:  */
                    642: #define PULLUP_TO(l)   do {                                            \
                    643:                            int len = (pip ? l : l + 14 ) ;             \
                    644:                            if ((*m)->m_len < (len) ) {                 \
                    645:                                if ( (*m = m_pullup(*m, (len))) == 0)   \
                    646:                                    goto bogusfrag;                     \
                    647:                                ip = mtod(*m, struct ip *);             \
                    648:                                if (pip)                                \
                    649:                                    *pip = ip ;                         \
                    650:                                else                                    \
                    651:                                    ip = (struct ip *)((int)ip + 14);   \
                    652:                                offset = (ip->ip_off & IP_OFFMASK);     \
                    653:                            }                                           \
                    654:                        } while (0)
                    655: 
                    656:                /* Protocol specific checks */
                    657:                switch (ip->ip_p) {
                    658:                case IPPROTO_TCP:
                    659:                    {
                    660:                        struct tcphdr *tcp;
                    661: 
                    662:                        if (offset == 1)        /* cf. RFC 1858 */
                    663:                                goto bogusfrag;
                    664:                        if (offset != 0) {
                    665:                                /*
                    666:                                 * TCP flags and ports aren't available in this
                    667:                                 * packet -- if this rule specified either one,
                    668:                                 * we consider the rule a non-match.
                    669:                                 */
                    670:                                if (f->fw_nports != 0 ||
                    671:                                    f->fw_tcpf != f->fw_tcpnf)
                    672:                                        continue;
                    673: 
                    674:                                break;
                    675:                        }
                    676:                        PULLUP_TO(hlen + 14);
                    677:                        tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
                    678:                        if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
                    679:                                continue;
                    680:                        src_port = ntohs(tcp->th_sport);
                    681:                        dst_port = ntohs(tcp->th_dport);
                    682:                        goto check_ports;
                    683:                    }
                    684: 
                    685:                case IPPROTO_UDP:
                    686:                    {
                    687:                        struct udphdr *udp;
                    688: 
                    689:                        if (offset != 0) {
                    690:                                /*
                    691:                                 * Port specification is unavailable -- if this
                    692:                                 * rule specifies a port, we consider the rule
                    693:                                 * a non-match.
                    694:                                 */
                    695:                                if (f->fw_nports != 0)
                    696:                                        continue;
                    697: 
                    698:                                break;
                    699:                        }
                    700:                        PULLUP_TO(hlen + 4);
                    701:                        udp = (struct udphdr *) ((u_int32_t *)ip + ip->ip_hl);
                    702:                        src_port = ntohs(udp->uh_sport);
                    703:                        dst_port = ntohs(udp->uh_dport);
                    704: check_ports:
                    705:                        if (!port_match(&f->fw_uar.fw_pts[0],
                    706:                            IP_FW_GETNSRCP(f), src_port,
                    707:                            f->fw_flg & IP_FW_F_SRNG))
                    708:                                continue;
                    709:                        if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)],
                    710:                            IP_FW_GETNDSTP(f), dst_port,
                    711:                            f->fw_flg & IP_FW_F_DRNG)) 
                    712:                                continue;
                    713:                        break;
                    714:                    }
                    715: 
                    716:                case IPPROTO_ICMP:
                    717:                    {
                    718:                        struct icmp *icmp;
                    719: 
                    720:                        if (offset != 0)        /* Type isn't valid */
                    721:                                break;
                    722:                        PULLUP_TO(hlen + 2);
                    723:                        icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl);
                    724:                        if (!icmptype_match(icmp, f))
                    725:                                continue;
                    726:                        break;
                    727:                    }
                    728: #undef PULLUP_TO
                    729: 
                    730: bogusfrag:
                    731:                        if (fw_verbose)
                    732:                                ipfw_report(NULL, ip, rif, oif);
                    733:                        goto dropit;
                    734:                }
                    735: 
                    736: got_match:
                    737:                *flow_id = chain ; /* XXX set flow id */
                    738:                /* Update statistics */
                    739:                f->fw_pcnt += 1;
                    740:                if (ip) {
                    741:                    f->fw_bcnt += ip->ip_len;
                    742:                }
                    743:                f->timestamp = time_second;
                    744: 
                    745:                /* Log to console if desired */
                    746:                if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)
                    747:                        ipfw_report(f, ip, rif, oif);
                    748: 
                    749:                /* Take appropriate action */
                    750:                switch (f->fw_flg & IP_FW_F_COMMAND) {
                    751:                case IP_FW_F_ACCEPT:
                    752:                        return(0);
                    753:                case IP_FW_F_COUNT:
                    754:                        continue;
                    755: #if IPDIVERT
                    756:                case IP_FW_F_DIVERT:
                    757:                        *cookie = f->fw_number;
                    758:                        return(f->fw_divert_port);
                    759: #endif
                    760:                case IP_FW_F_TEE:
                    761:                        /*
                    762:                         * XXX someday tee packet here, but beware that you
                    763:                         * can't use m_copym() or m_copypacket() because
                    764:                         * the divert input routine modifies the mbuf
                    765:                         * (and these routines only increment reference
                    766:                         * counts in the case of mbuf clusters), so need
                    767:                         * to write custom routine.
                    768:                         */
                    769:                        continue;
                    770:                case IP_FW_F_SKIPTO: /* XXX check */
                    771:                        if ( f->next_rule_ptr )
                    772:                            chain = f->next_rule_ptr ;
                    773:                        else
                    774:                            chain = lookup_next_rule(chain) ;
                    775:                        if (! chain) goto dropit;
                    776:                        goto again ;
                    777: #if DUMMYNET
                    778:                case IP_FW_F_PIPE:
                    779:                        return(f->fw_pipe_nr | 0x10000 );
                    780: #endif
                    781: #if IPFIREWALL_FORWARD
                    782:                case IP_FW_F_FWD:
                    783:                        /* Change the next-hop address for this packet.
                    784:                         * Initially we'll only worry about directly
                    785:                         * reachable next-hop's, but ultimately
                    786:                         * we will work out for next-hops that aren't
                    787:                         * direct the route we would take for it. We
                    788:                         * [cs]ould leave this latter problem to
                    789:                         * ip_output.c. We hope to high [name the abode of
                    790:                         * your favourite deity] that ip_output doesn't modify
                    791:                         * the new value of next_hop (which is dst there)
                    792:                         */
                    793:                        if (next_hop != NULL) /* Make sure, first... */
                    794:                                *next_hop = &(f->fw_fwd_ip);
                    795:                        return(0); /* Allow the packet */
                    796: #endif
                    797:                }
                    798: 
                    799:                /* Deny/reject this packet using this rule */
                    800:                rule = f;
                    801:                break;
                    802: 
                    803:        }
                    804: 
                    805: #if DIAGNOSTIC
                    806:        /* Rule IPFW_DEFAULT_RULE should always be there and should always match */
                    807:        if (!chain)
                    808:                panic("ip_fw: chain");
                    809: #endif
                    810: 
                    811:        /*
                    812:         * At this point, we're going to drop the packet.
                    813:         * Send a reject notice if all of the following are true:
                    814:         *
                    815:         * - The packet matched a reject rule
                    816:         * - The packet is not an ICMP packet, or is an ICMP query packet
                    817:         * - The packet is not a multicast or broadcast packet
                    818:         */
                    819:        if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
                    820:            && ip
                    821:            && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip))
                    822:            && !((*m)->m_flags & (M_BCAST|M_MCAST))
                    823:            && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
                    824:                switch (rule->fw_reject_code) {
                    825:                case IP_FW_REJECT_RST:
                    826:                  {
                    827:                        struct tcphdr *const tcp =
                    828:                                (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
                    829:                        struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;
                    830: 
                    831:                        if (offset != 0 || (tcp->th_flags & TH_RST))
                    832:                                break;
                    833:                        ti.ti_i = *((struct ipovly *) ip);
                    834:                        ti.ti_t = *tcp;
                    835:                        bcopy(&ti, ip, sizeof(ti));
                    836:                        NTOHL(tip->ti_seq);
                    837:                        NTOHL(tip->ti_ack);
                    838:                        tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
                    839:                        if (tcp->th_flags & TH_ACK) {
                    840:                                tcp_respond(NULL, tip, *m,
                    841:                                    (tcp_seq)0, ntohl(tcp->th_ack), TH_RST);
                    842:                        } else {
                    843:                                if (tcp->th_flags & TH_SYN)
                    844:                                        tip->ti_len++;
                    845:                                tcp_respond(NULL, tip, *m, tip->ti_seq
                    846:                                    + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
                    847:                        }
                    848:                        *m = NULL;
                    849:                        break;
                    850:                  }
                    851:                default:        /* Send an ICMP unreachable using code */
                    852:                        icmp_error(*m, ICMP_UNREACH,
                    853:                            rule->fw_reject_code, 0L, 0);
                    854:                        *m = NULL;
                    855:                        break;
                    856:                }
                    857:        }
                    858: 
                    859: dropit:
                    860:        /*
                    861:         * Finally, drop the packet.
                    862:         */
                    863:        /* *cookie = 0; */ /* XXX is this necessary ? */
                    864:        if (*m) {
                    865:                m_freem(*m);
                    866:                *m = NULL;
                    867:        }
                    868:        return(0);
                    869: }
                    870: 
                    871: /*
                    872:  * when a rule is added/deleted, zero the direct pointers within
                    873:  * all firewall rules. These will be reconstructed on the fly
                    874:  * as packets are matched.
                    875:  * Must be called at splnet().
                    876:  */
                    877: static void
                    878: flush_rule_ptrs()
                    879: {
                    880:     struct ip_fw_chain *fcp ;
                    881: 
                    882:     for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) {
                    883:        fcp->rule->next_rule_ptr = NULL ;
                    884:     }
                    885: }
                    886: 
                    887: static int
                    888: add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl)
                    889: {
                    890:        struct ip_fw *ftmp = 0;
                    891:        struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0;
                    892:        u_short nbr = 0;
                    893:        int s;
                    894: 
                    895:        fwc = _MALLOC(sizeof *fwc, M_IPFW, M_DONTWAIT);
                    896:        ftmp = _MALLOC(sizeof *ftmp, M_IPFW, M_DONTWAIT);
                    897:        if (!fwc || !ftmp) {
                    898:                dprintf(("%s MALLOC said no\n", err_prefix));
                    899:                if (fwc)  FREE(fwc, M_IPFW);
                    900:                if (ftmp) FREE(ftmp, M_IPFW);
                    901:                return (ENOSPC);
                    902:        }
                    903: 
                    904:        bcopy(frwl, ftmp, sizeof(struct ip_fw));
                    905:        ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
                    906:        ftmp->fw_pcnt = 0L;
                    907:        ftmp->fw_bcnt = 0L;
                    908:        ftmp->next_rule_ptr = NULL ;
                    909:        ftmp->pipe_ptr = NULL ;
                    910:        fwc->rule = ftmp;
                    911:        
                    912:        s = splnet();
                    913: 
                    914:        if (chainptr->lh_first == 0) {
                    915:                LIST_INSERT_HEAD(chainptr, fwc, chain);
                    916:                splx(s);
                    917:                return(0);
                    918:         }
                    919: 
                    920:        /* If entry number is 0, find highest numbered rule and add 100 */
                    921:        if (ftmp->fw_number == 0) {
                    922:                for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {
                    923:                        if (fcp->rule->fw_number != (u_short)-1)
                    924:                                nbr = fcp->rule->fw_number;
                    925:                        else
                    926:                                break;
                    927:                }
                    928:                if (nbr < IPFW_DEFAULT_RULE - 100)
                    929:                        nbr += 100;
                    930:                ftmp->fw_number = nbr;
                    931:        }
                    932: 
                    933:        /* Got a valid number; now insert it, keeping the list ordered */
                    934:        for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {
                    935:                if (fcp->rule->fw_number > ftmp->fw_number) {
                    936:                        if (fcpl) {
                    937:                                LIST_INSERT_AFTER(fcpl, fwc, chain);
                    938:                        } else {
                    939:                                LIST_INSERT_HEAD(chainptr, fwc, chain);
                    940:                        }
                    941:                        break;
                    942:                } else {
                    943:                        fcpl = fcp;
                    944:                }
                    945:        }
                    946:        flush_rule_ptrs();
                    947: 
                    948:        splx(s);
                    949:        return (0);
                    950: }
                    951: 
                    952: static int
                    953: del_entry(struct ip_fw_head *chainptr, u_short number)
                    954: {
                    955:        struct ip_fw_chain *fcp;
                    956: 
                    957:        fcp = LIST_FIRST(chainptr);
                    958:        if (number != (u_short)-1) {
                    959:                for (; fcp; fcp = LIST_NEXT(fcp, chain)) {
                    960:                        if (fcp->rule->fw_number == number) {
                    961:                                int s;
                    962: 
                    963:                                /* prevent access to rules while removing them */
                    964:                                s = splnet();
                    965:                                while (fcp && fcp->rule->fw_number == number) {
                    966:                                        struct ip_fw_chain *next;
                    967: 
                    968:                                        next = LIST_NEXT(fcp, chain);
                    969:                                        LIST_REMOVE(fcp, chain);
                    970: #if DUMMYNET
                    971:                                        dn_rule_delete(fcp) ;
                    972: #endif
                    973:                                        flush_rule_ptrs();
                    974:                                        FREE(fcp->rule, M_IPFW);
                    975:                                        FREE(fcp, M_IPFW);
                    976:                                        fcp = next;
                    977:                                }
                    978:                                splx(s);
                    979:                                return 0;
                    980:                        }
                    981:                }
                    982:        }
                    983: 
                    984:        return (EINVAL);
                    985: }
                    986: 
                    987: static int
                    988: zero_entry(struct ip_fw *frwl)
                    989: {
                    990:        struct ip_fw_chain *fcp;
                    991:        int s, cleared;
                    992: 
                    993:        if (frwl == 0) {
                    994:                s = splnet();
                    995:                for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) {
                    996:                        fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
                    997:                        fcp->rule->timestamp = 0;
                    998:                }
                    999:                splx(s);
                   1000:        }
                   1001:        else {
                   1002:                cleared = 0;
                   1003: 
                   1004:                /*
                   1005:                 *      It's possible to insert multiple chain entries with the
                   1006:                 *      same number, so we don't stop after finding the first
                   1007:                 *      match if zeroing a specific entry.
                   1008:                 */
                   1009:                for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain))
                   1010:                        if (frwl->fw_number == fcp->rule->fw_number) {
                   1011:                                s = splnet();
                   1012:                                while (fcp && frwl->fw_number == fcp->rule->fw_number) {
                   1013:                                        fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
                   1014:                                        fcp->rule->timestamp = 0;
                   1015:                                        fcp = LIST_NEXT(fcp, chain);
                   1016:                                }
                   1017:                                splx(s);
                   1018:                                cleared = 1;
                   1019:                                break;
                   1020:                        }
                   1021:                if (!cleared)   /* we didn't find any matching rules */
                   1022:                        return (EINVAL);
                   1023:        }
                   1024: 
                   1025:        if (fw_verbose) {
                   1026:                if (frwl)
                   1027:                        kprintf("ipfw: Entry %d cleared.\n", frwl->fw_number);
                   1028:                else
                   1029:                        kprintf("ipfw: Accounting cleared.\n");
                   1030:        }
                   1031: 
                   1032:        return (0);
                   1033: }
                   1034: 
                   1035: static int
                   1036: check_ipfw_struct(struct ip_fw *frwl)
                   1037: {
                   1038:        /* Check for invalid flag bits */
                   1039:        if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) {
                   1040:                dprintf(("%s undefined flag bits set (flags=%x)\n",
                   1041:                    err_prefix, frwl->fw_flg));
                   1042:                return (EINVAL);
                   1043:        }
                   1044:        /* Must apply to incoming or outgoing (or both) */
                   1045:        if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) {
                   1046:                dprintf(("%s neither in nor out\n", err_prefix));
                   1047:                return (EINVAL);
                   1048:        }
                   1049:        /* Empty interface name is no good */
                   1050:        if (((frwl->fw_flg & IP_FW_F_IIFNAME)
                   1051:              && !*frwl->fw_in_if.fu_via_if.name)
                   1052:            || ((frwl->fw_flg & IP_FW_F_OIFNAME)
                   1053:              && !*frwl->fw_out_if.fu_via_if.name)) {
                   1054:                dprintf(("%s empty interface name\n", err_prefix));
                   1055:                return (EINVAL);
                   1056:        }
                   1057:        /* Sanity check interface matching */
                   1058:        if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
                   1059:                ;               /* allow "via" backwards compatibility */
                   1060:        } else if ((frwl->fw_flg & IP_FW_F_IN)
                   1061:            && (frwl->fw_flg & IP_FW_F_OIFACE)) {
                   1062:                dprintf(("%s outgoing interface check on incoming\n",
                   1063:                    err_prefix));
                   1064:                return (EINVAL);
                   1065:        }
                   1066:        /* Sanity check port ranges */
                   1067:        if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) {
                   1068:                dprintf(("%s src range set but n_src_p=%d\n",
                   1069:                    err_prefix, IP_FW_GETNSRCP(frwl)));
                   1070:                return (EINVAL);
                   1071:        }
                   1072:        if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) {
                   1073:                dprintf(("%s dst range set but n_dst_p=%d\n",
                   1074:                    err_prefix, IP_FW_GETNDSTP(frwl)));
                   1075:                return (EINVAL);
                   1076:        }
                   1077:        if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) {
                   1078:                dprintf(("%s too many ports (%d+%d)\n",
                   1079:                    err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl)));
                   1080:                return (EINVAL);
                   1081:        }
                   1082:        /*
                   1083:         *      Protocols other than TCP/UDP don't use port range
                   1084:         */
                   1085:        if ((frwl->fw_prot != IPPROTO_TCP) &&
                   1086:            (frwl->fw_prot != IPPROTO_UDP) &&
                   1087:            (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) {
                   1088:                dprintf(("%s port(s) specified for non TCP/UDP rule\n",
                   1089:                    err_prefix));
                   1090:                return (EINVAL);
                   1091:        }
                   1092: 
                   1093:        /*
                   1094:         *      Rather than modify the entry to make such entries work, 
                   1095:         *      we reject this rule and require user level utilities
                   1096:         *      to enforce whatever policy they deem appropriate.
                   1097:         */
                   1098:        if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || 
                   1099:                (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
                   1100:                dprintf(("%s rule never matches\n", err_prefix));
                   1101:                return (EINVAL);
                   1102:        }
                   1103: 
                   1104:        if ((frwl->fw_flg & IP_FW_F_FRAG) &&
                   1105:                (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
                   1106:                if (frwl->fw_nports) {
                   1107:                        dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
                   1108:                        return (EINVAL);
                   1109:                }
                   1110:                if (frwl->fw_prot == IPPROTO_TCP &&
                   1111:                        frwl->fw_tcpf != frwl->fw_tcpnf) {
                   1112:                        dprintf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
                   1113:                        return (EINVAL);
                   1114:                }
                   1115:        }
                   1116: 
                   1117:        /* Check command specific stuff */
                   1118:        switch (frwl->fw_flg & IP_FW_F_COMMAND)
                   1119:        {
                   1120:        case IP_FW_F_REJECT:
                   1121:                if (frwl->fw_reject_code >= 0x100
                   1122:                    && !(frwl->fw_prot == IPPROTO_TCP
                   1123:                      && frwl->fw_reject_code == IP_FW_REJECT_RST)) {
                   1124:                        dprintf(("%s unknown reject code\n", err_prefix));
                   1125:                        return (EINVAL);
                   1126:                }
                   1127:                break;
                   1128:        case IP_FW_F_DIVERT:            /* Diverting to port zero is invalid */
                   1129:        case IP_FW_F_PIPE:              /* piping through 0 is invalid */
                   1130:        case IP_FW_F_TEE:
                   1131:                if (frwl->fw_divert_port == 0) {
                   1132:                        dprintf(("%s can't divert to port 0\n", err_prefix));
                   1133:                        return (EINVAL);
                   1134:                }
                   1135:                break;
                   1136:        case IP_FW_F_DENY:
                   1137:        case IP_FW_F_ACCEPT:
                   1138:        case IP_FW_F_COUNT:
                   1139:        case IP_FW_F_SKIPTO:
                   1140: #if IPFIREWALL_FORWARD
                   1141:        case IP_FW_F_FWD:
                   1142: #endif
                   1143:                break;
                   1144:        default:
                   1145:                dprintf(("%s invalid command\n", err_prefix));
                   1146:                return (EINVAL);
                   1147:        }
                   1148: 
                   1149:        return 0;
                   1150: }
                   1151: 
                   1152: static int
                   1153: ip_fw_ctl(struct sockopt *sopt)
                   1154: {
                   1155:        int error, s;
                   1156:        size_t size;
                   1157:        char *buf, *bp;
                   1158:        struct ip_fw_chain *fcp;
                   1159:        struct ip_fw frwl;
                   1160: 
                   1161:        /* Disallow sets in really-really secure mode. */
                   1162:        if (sopt->sopt_dir == SOPT_SET && securelevel >= 3)
                   1163:                        return (EPERM);
                   1164:        error = 0;
                   1165: 
                   1166:        switch (sopt->sopt_name) {
                   1167:        case IP_FW_GET:
                   1168:                for (fcp = LIST_FIRST(&ip_fw_chain), size = 0; fcp;
                   1169:                     fcp = LIST_NEXT(fcp, chain))
                   1170:                        size += sizeof *fcp->rule;
                   1171:                buf = _MALLOC(size, M_TEMP, M_WAITOK);
                   1172:                if (buf == 0) {
                   1173:                        error = ENOBUFS;
                   1174:                        break;
                   1175:                }
                   1176: 
                   1177:                for (fcp = LIST_FIRST(&ip_fw_chain), bp = buf; fcp;
                   1178:                     fcp = LIST_NEXT(fcp, chain)) {
                   1179:                        bcopy(fcp->rule, bp, sizeof *fcp->rule);
                   1180:                        bp += sizeof *fcp->rule;
                   1181:                }
                   1182:                error = sooptcopyout(sopt, buf, size);
                   1183:                FREE(buf, M_TEMP);
                   1184:                break;
                   1185: 
                   1186:        case IP_FW_FLUSH:
                   1187:                for (fcp = ip_fw_chain.lh_first; 
                   1188:                     fcp != 0 && fcp->rule->fw_number != IPFW_DEFAULT_RULE;
                   1189:                     fcp = ip_fw_chain.lh_first) {
                   1190:                        s = splnet();
                   1191:                        LIST_REMOVE(fcp, chain);
                   1192:                        FREE(fcp->rule, M_IPFW);
                   1193:                        FREE(fcp, M_IPFW);
                   1194:                        splx(s);
                   1195:                }
                   1196:                break;
                   1197: 
                   1198:        case IP_FW_ZERO:
                   1199:                if (sopt->sopt_val != 0) {
                   1200:                        error = sooptcopyin(sopt, &frwl, sizeof frwl,
                   1201:                                            sizeof frwl);
                   1202:                        if (error || (error = zero_entry(&frwl)))
                   1203:                                break;
                   1204:                } else {
                   1205:                        error = zero_entry(0);
                   1206:                }
                   1207:                break;
                   1208: 
                   1209:        case IP_FW_ADD:
                   1210:                error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
                   1211:                if (error || (error = check_ipfw_struct(&frwl)))
                   1212:                        break;
                   1213: 
                   1214:                if (frwl.fw_number == IPFW_DEFAULT_RULE) {
                   1215:                        dprintf(("%s can't add rule %u\n", err_prefix,
                   1216:                                 (unsigned)IPFW_DEFAULT_RULE));
                   1217:                        error = EINVAL;
                   1218:                } else {
                   1219:                        error = add_entry(&ip_fw_chain, &frwl);
                   1220:                }
                   1221:                break;
                   1222: 
                   1223:        case IP_FW_DEL:
                   1224:                error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
                   1225:                if (error)
                   1226:                        break;
                   1227: 
                   1228:                if (frwl.fw_number == IPFW_DEFAULT_RULE) {
                   1229:                        dprintf(("%s can't delete rule %u\n", err_prefix,
                   1230:                                 (unsigned)IPFW_DEFAULT_RULE));
                   1231:                        error = EINVAL;
                   1232:                } else {
                   1233:                        error = del_entry(&ip_fw_chain, frwl.fw_number);
                   1234:                }
                   1235:                break;
                   1236: 
                   1237:        default:
                   1238:                kprintf("ip_fw_ctl invalid option %d\n", sopt->sopt_name);
                   1239:                error = EINVAL ;
                   1240:        }
                   1241: 
                   1242:        return (error);
                   1243: }
                   1244: 
                   1245: struct ip_fw_chain *ip_fw_default_rule ;
                   1246: 
                   1247: void
                   1248: ip_fw_init(void)
                   1249: {
                   1250:        struct ip_fw default_rule;
                   1251: 
                   1252:        ip_fw_chk_ptr = ip_fw_chk;
                   1253:        ip_fw_ctl_ptr = ip_fw_ctl;
                   1254:        LIST_INIT(&ip_fw_chain);
                   1255: 
                   1256:        bzero(&default_rule, sizeof default_rule);
                   1257:        default_rule.fw_prot = IPPROTO_IP;
                   1258:        default_rule.fw_number = IPFW_DEFAULT_RULE;
                   1259: #if IPFIREWALL_DEFAULT_TO_ACCEPT
                   1260:        default_rule.fw_flg |= IP_FW_F_ACCEPT;
                   1261: #else
                   1262:        default_rule.fw_flg |= IP_FW_F_DENY;
                   1263: #endif
                   1264:        default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT;
                   1265:        if (check_ipfw_struct(&default_rule) != 0 ||
                   1266:            add_entry(&ip_fw_chain, &default_rule))
                   1267:                panic("ip_fw_init");
                   1268: 
                   1269:        ip_fw_default_rule = ip_fw_chain.lh_first ;
                   1270:        kprintf("IP packet filtering initialized, "
                   1271: #if IPDIVERT
                   1272:                "divert enabled, ");
                   1273: #else
                   1274:                "divert disabled, ");
                   1275: #endif
                   1276: #if IPFIREWALL_FORWARD
                   1277:        kprintf("rule-based forwarding enabled, ");
                   1278: #else
                   1279:        kprintf("rule-based forwarding disabled, ");
                   1280: #endif
                   1281: #if IPFIREWALL_DEFAULT_TO_ACCEPT
                   1282:        kprintf("default to accept, ");
                   1283: #endif
                   1284: #ifndef IPFIREWALL_VERBOSE
                   1285:        kprintf("logging disabled\n");
                   1286: #else
                   1287:        if (fw_verbose_limit == 0)
                   1288:                kprintf("unlimited logging\n");
                   1289:        else
                   1290:                kprintf("logging limited to %d packets/entry\n",
                   1291:                    fw_verbose_limit);
                   1292: #endif
                   1293: }
                   1294: 
                   1295: #if ISFB31
                   1296: 
                   1297: /*
                   1298:  * ### LD 08/04/99: This is used if IPFIREWALL is a FreeBSD "KLD" module
                   1299:  *     Right now, we're linked to the kernel all the time
                   1300:  *     will be fixed with the use of an NKE?
                   1301:  *
                   1302:  * Note: ip_fw_init is called from div_init() in xnu
                   1303:  */ 
                   1304: 
                   1305: static ip_fw_chk_t *old_chk_ptr;
                   1306: static ip_fw_ctl_t *old_ctl_ptr;
                   1307: 
                   1308: #if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE)
                   1309: 
                   1310: #include <sys/exec.h>
                   1311: #include <sys/sysent.h>
                   1312: #include <sys/lkm.h>
                   1313: 
                   1314: MOD_MISC(ipfw);
                   1315: 
                   1316: static int
                   1317: ipfw_load(struct lkm_table *lkmtp, int cmd)
                   1318: {
                   1319:        int s=splnet();
                   1320: 
                   1321:        old_chk_ptr = ip_fw_chk_ptr;
                   1322:        old_ctl_ptr = ip_fw_ctl_ptr;
                   1323: 
                   1324:        ip_fw_init();
                   1325:        splx(s);
                   1326:        return 0;
                   1327: }
                   1328: 
                   1329: static int
                   1330: ipfw_unload(struct lkm_table *lkmtp, int cmd)
                   1331: {
                   1332:        int s=splnet();
                   1333: 
                   1334:        ip_fw_chk_ptr =  old_chk_ptr;
                   1335:        ip_fw_ctl_ptr =  old_ctl_ptr;
                   1336: 
                   1337:        while (LIST_FIRST(&ip_fw_chain) != NULL) {
                   1338:                struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain);
                   1339:                LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain);
                   1340:                FREE(fcp->rule, M_IPFW);
                   1341:                FREE(fcp, M_IPFW);
                   1342:        }
                   1343:        
                   1344:        splx(s);
                   1345:        kprintf("IP firewall unloaded\n");
                   1346:        return 0;
                   1347: }
                   1348: 
                   1349: int
                   1350: ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver)
                   1351: {
                   1352:        MOD_DISPATCH(ipfw, lkmtp, cmd, ver,
                   1353:                ipfw_load, ipfw_unload, lkm_nullcmd);
                   1354: }
                   1355: #else
                   1356: static int
                   1357: ipfw_modevent(module_t mod, int type, void *unused)
                   1358: {
                   1359:        int s;
                   1360:        
                   1361:        switch (type) {
                   1362:        case MOD_LOAD:
                   1363:                s = splnet();
                   1364: 
                   1365:                old_chk_ptr = ip_fw_chk_ptr;
                   1366:                old_ctl_ptr = ip_fw_ctl_ptr;
                   1367: 
                   1368:                ip_fw_init();
                   1369:                splx(s);
                   1370:                return 0;
                   1371:        case MOD_UNLOAD:
                   1372:                s = splnet();
                   1373: 
                   1374:                ip_fw_chk_ptr =  old_chk_ptr;
                   1375:                ip_fw_ctl_ptr =  old_ctl_ptr;
                   1376: 
                   1377:                while (LIST_FIRST(&ip_fw_chain) != NULL) {
                   1378:                        struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain);
                   1379:                        LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain);
                   1380:                        FREE(fcp->rule, M_IPFW);
                   1381:                        FREE(fcp, M_IPFW);
                   1382:                }
                   1383:        
                   1384:                splx(s);
                   1385:                kprintf("IP firewall unloaded\n");
                   1386:                return 0;
                   1387:        default:
                   1388:                break;
                   1389:        }
                   1390:        return 0;
                   1391: }
                   1392: 
                   1393: static moduledata_t ipfwmod = {
                   1394:        "ipfw",
                   1395:        ipfw_modevent,
                   1396:        0
                   1397: };
                   1398: DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
                   1399: #endif
                   1400: #endif /* ISFB31 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.