Annotation of XNU/bsd/netinet/ip_fw.c, revision 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.