The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_fw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1993 Daniel Boulet
    3  * Copyright (c) 1994 Ugen J.S.Antsilevich
    4  * Copyright (c) 1996 Alex Nash
    5  * Copyright (c) 2000-2002 Luigi Rizzo
    6  *
    7  * Redistribution and use in source forms, with and without modification,
    8  * are permitted provided that this entire comment appears intact.
    9  *
   10  * Redistribution in binary form may occur without any restrictions.
   11  * Obviously, it would be nice if you gave credit where credit is due
   12  * but requiring it would be too onerous.
   13  *
   14  * This software is provided ``AS IS'' without any warranties of any kind.
   15  *
   16  * $FreeBSD: releng/5.1/sys/netinet/ip_fw.c 111119 2003-02-19 05:47:46Z imp $
   17  */
   18 
   19 #define        DEB(x)
   20 #define        DDB(x) x
   21 
   22 /*
   23  * Implement IP packet firewall
   24  */
   25 
   26 #if !defined(KLD_MODULE)
   27 #include "opt_ipfw.h"
   28 #include "opt_ipdn.h"
   29 #include "opt_ipdivert.h"
   30 #include "opt_inet.h"
   31 #ifndef INET
   32 #error IPFIREWALL requires INET.
   33 #endif /* INET */
   34 #endif
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/kernel.h>
   41 #include <sys/proc.h>
   42 #include <sys/socket.h>
   43 #include <sys/socketvar.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/syslog.h>
   46 #include <sys/ucred.h>
   47 #include <net/if.h>
   48 #include <net/route.h>
   49 #include <netinet/in.h>
   50 #include <netinet/in_systm.h>
   51 #include <netinet/in_var.h>
   52 #include <netinet/in_pcb.h>
   53 #include <netinet/ip.h>
   54 #include <netinet/ip_var.h>
   55 #include <netinet/ip_icmp.h>
   56 #include <netinet/ip_fw.h>
   57 #include <netinet/ip_dummynet.h>
   58 #include <netinet/tcp.h>
   59 #include <netinet/tcp_timer.h>
   60 #include <netinet/tcp_var.h>
   61 #include <netinet/tcpip.h>
   62 #include <netinet/udp.h>
   63 #include <netinet/udp_var.h>
   64 
   65 #include <netinet/if_ether.h> /* XXX ethertype_ip */
   66 
   67 static int fw_debug = 1;
   68 #ifdef IPFIREWALL_VERBOSE
   69 static int fw_verbose = 1;
   70 #else
   71 static int fw_verbose = 0;
   72 #endif
   73 int fw_one_pass = 1 ;
   74 #ifdef IPFIREWALL_VERBOSE_LIMIT
   75 static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
   76 #else
   77 static int fw_verbose_limit = 0;
   78 #endif
   79 static int fw_permanent_rules = 0;
   80 
   81 /*
   82  * Right now, two fields in the IP header are changed to host format
   83  * by the IP layer before calling the firewall. Ideally, we would like
   84  * to have them in network format so that the packet can be
   85  * used as it comes from the device driver (and is thus readonly).
   86  */
   87 
   88 static u_int64_t counter;       /* counter for ipfw_report(NULL...) */
   89 
   90 #define IPFW_DEFAULT_RULE       ((u_int)(u_short)~0)
   91 
   92 LIST_HEAD (ip_fw_head, ip_fw) ip_fw_chain_head;
   93 
   94 MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
   95 
   96 #ifdef SYSCTL_NODE
   97 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
   98 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, enable, CTLFLAG_RW,
   99     &fw_enable, 0, "Enable ipfw");
  100 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, 
  101     &fw_one_pass, 0, 
  102     "Only do a single pass through ipfw when using dummynet(4)");
  103 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, 
  104     &fw_debug, 0, "Enable printing of debug ip_fw statements");
  105 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, 
  106     &fw_verbose, 0, "Log matches to ipfw rules");
  107 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, 
  108     &fw_verbose_limit, 0, "Set upper limit of matches of ipfw rules logged");
  109 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, permanent_rules, CTLFLAG_RW, 
  110     &fw_permanent_rules, 0, "Set rule number, below which rules are permanent");
  111 
  112 /*
  113  * Extension for stateful ipfw.
  114  *
  115  * Dynamic rules are stored in lists accessed through a hash table
  116  * (ipfw_dyn_v) whose size is curr_dyn_buckets. This value can
  117  * be modified through the sysctl variable dyn_buckets which is
  118  * updated when the table becomes empty.
  119  *
  120  * XXX currently there is only one list, ipfw_dyn.
  121  *
  122  * When a packet is received, it is first hashed, then matched
  123  * against the entries in the corresponding list.
  124  * Matching occurs according to the rule type. The default is to
  125  * match the four fields and the protocol, and rules are bidirectional.
  126  *
  127  * For a busy proxy/web server we will have lots of connections to
  128  * the server. We could decide for a rule type where we ignore
  129  * ports (different hashing) and avoid special SYN/RST/FIN handling.
  130  *
  131  * XXX when we decide to support more than one rule type, we should
  132  * repeat the hashing multiple times uing only the useful fields.
  133  * Or, we could run the various tests in parallel, because the
  134  * 'move to front' technique should shorten the average search.
  135  *
  136  * The lifetime of dynamic rules is regulated by dyn_*_lifetime,
  137  * measured in seconds and depending on the flags.
  138  *
  139  * The total number of dynamic rules is stored in dyn_count.
  140  * The max number of dynamic rules is dyn_max. When we reach
  141  * the maximum number of rules we do not create anymore. This is
  142  * done to avoid consuming too much memory, but also too much
  143  * time when searching on each packet (ideally, we should try instead
  144  * to put a limit on the length of the list on each bucket...).
  145  *
  146  * Each dynamic rules holds a pointer to the parent ipfw rule so
  147  * we know what action to perform. Dynamic rules are removed when
  148  * the parent rule is deleted.
  149  * There are some limitations with dynamic rules -- we do not
  150  * obey the 'randomized match', and we do not do multiple
  151  * passes through the firewall.
  152  * XXX check the latter!!!
  153  */
  154 static struct ipfw_dyn_rule **ipfw_dyn_v = NULL ;
  155 static u_int32_t dyn_buckets = 256 ; /* must be power of 2 */
  156 static u_int32_t curr_dyn_buckets = 256 ; /* must be power of 2 */
  157 
  158 /*
  159  * timeouts for various events in handing dynamic rules.
  160  */
  161 static u_int32_t dyn_ack_lifetime = 300 ;
  162 static u_int32_t dyn_syn_lifetime = 20 ;
  163 static u_int32_t dyn_fin_lifetime = 1 ;
  164 static u_int32_t dyn_rst_lifetime = 1 ;
  165 static u_int32_t dyn_udp_lifetime = 10 ;
  166 static u_int32_t dyn_short_lifetime = 5 ;
  167 
  168 /*
  169  * after reaching 0, dynamic rules are considered still valid for
  170  * an additional grace time, unless there is lack of resources.
  171  */
  172 static u_int32_t dyn_grace_time = 10 ;
  173 
  174 static u_int32_t static_count = 0 ;     /* # of static rules */
  175 static u_int32_t dyn_count = 0 ;        /* # of dynamic rules */
  176 static u_int32_t dyn_max = 1000 ;       /* max # of dynamic rules */
  177 
  178 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets, CTLFLAG_RW,
  179     &dyn_buckets, 0, "Number of dyn. buckets");
  180 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets, CTLFLAG_RD,
  181     &curr_dyn_buckets, 0, "Current Number of dyn. buckets");
  182 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_count, CTLFLAG_RD,
  183     &dyn_count, 0, "Number of dyn. rules");
  184 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_max, CTLFLAG_RW,
  185     &dyn_max, 0, "Max number of dyn. rules");
  186 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, static_count, CTLFLAG_RD,
  187     &static_count, 0, "Number of static rules");
  188 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime, CTLFLAG_RW,
  189     &dyn_ack_lifetime, 0, "Lifetime of dyn. rules for acks");
  190 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime, CTLFLAG_RW,
  191     &dyn_syn_lifetime, 0, "Lifetime of dyn. rules for syn");
  192 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime, CTLFLAG_RW,
  193     &dyn_fin_lifetime, 0, "Lifetime of dyn. rules for fin");
  194 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime, CTLFLAG_RW,
  195     &dyn_rst_lifetime, 0, "Lifetime of dyn. rules for rst");
  196 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime, CTLFLAG_RW,
  197     &dyn_udp_lifetime, 0, "Lifetime of dyn. rules for UDP");
  198 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW,
  199     &dyn_short_lifetime, 0, "Lifetime of dyn. rules for other situations");
  200 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_grace_time, CTLFLAG_RD,
  201     &dyn_grace_time, 0, "Grace time for dyn. rules");
  202 
  203 #endif /* SYSCTL_NODE */
  204 
  205 #define dprintf(a)      do {                                            \
  206                                 if (fw_debug)                           \
  207                                         printf a;                       \
  208                         } while (0)
  209 #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
  210 
  211 static int      add_entry (struct ip_fw_head *chainptr, struct ip_fw *frwl);
  212 static int      del_entry (struct ip_fw_head *chainptr, u_short number);
  213 static int      zero_entry (struct ip_fw *, int);
  214 static int      check_ipfw_struct (struct ip_fw *m);
  215 static int      iface_match (struct ifnet *ifp, union ip_fw_if *ifu,
  216                                  int byname);
  217 static int      ipopts_match (struct ip *ip, struct ip_fw *f);
  218 static int      iptos_match (struct ip *ip, struct ip_fw *f);
  219 static __inline int
  220                 port_match (u_short *portptr, int nports, u_short port,
  221                                 int range_flag, int mask);
  222 static int      tcpflg_match (struct tcphdr *tcp, struct ip_fw *f);
  223 static int      icmptype_match (struct icmp *  icmp, struct ip_fw * f);
  224 static void     ipfw_report (struct ip_fw *f, struct ip *ip, int ip_off,
  225                                 int ip_len, struct ifnet *rif,
  226                                 struct ifnet *oif);
  227 
  228 static void flush_rule_ptrs(void);
  229 
  230 static ip_fw_chk_t      ip_fw_chk;
  231 static int      ip_fw_ctl (struct sockopt *sopt);
  232 
  233 ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;
  234 
  235 static char err_prefix[] = "ip_fw_ctl:";
  236 
  237 /*
  238  * Returns 1 if the port is matched by the vector, 0 otherwise
  239  */
  240 static __inline int 
  241 port_match(u_short *portptr, int nports, u_short port, int range_flag, int mask)
  242 {
  243         if (!nports)
  244                 return 1;
  245         if (mask) {
  246                 if ( 0 == ((portptr[0] ^ port) & portptr[1]) )
  247                         return 1;
  248                 nports -= 2;
  249                 portptr += 2;
  250         }
  251         if (range_flag) {
  252                 if (portptr[0] <= port && port <= portptr[1])
  253                         return 1;
  254                 nports -= 2;
  255                 portptr += 2;
  256         }
  257         while (nports-- > 0)
  258                 if (*portptr++ == port)
  259                         return 1;
  260         return 0;
  261 }
  262 
  263 static int
  264 tcpflg_match(struct tcphdr *tcp, struct ip_fw *f)
  265 {
  266         u_char          flg_set, flg_clr;
  267 
  268         /*
  269          * If an established connection is required, reject packets that
  270          * have only SYN of RST|ACK|SYN set.  Otherwise, fall through to
  271          * other flag requirements.
  272          */
  273         if ((f->fw_ipflg & IP_FW_IF_TCPEST) &&
  274             ((tcp->th_flags & (TH_RST | TH_ACK | TH_SYN)) == TH_SYN))
  275                 return 0;
  276 
  277         flg_set = tcp->th_flags & f->fw_tcpf;
  278         flg_clr = tcp->th_flags & f->fw_tcpnf;
  279 
  280         if (flg_set != f->fw_tcpf)
  281                 return 0;
  282         if (flg_clr)
  283                 return 0;
  284 
  285         return 1;
  286 }
  287 
  288 static int
  289 icmptype_match(struct icmp *icmp, struct ip_fw *f)
  290 {
  291         int type;
  292 
  293         if (!(f->fw_flg & IP_FW_F_ICMPBIT))
  294                 return(1);
  295 
  296         type = icmp->icmp_type;
  297 
  298         /* check for matching type in the bitmap */
  299         if (type < IP_FW_ICMPTYPES_MAX &&
  300             (f->fw_uar.fw_icmptypes[type / (sizeof(unsigned) * NBBY)] & 
  301             (1U << (type % (sizeof(unsigned) * NBBY)))))
  302                 return(1);
  303 
  304         return(0); /* no match */
  305 }
  306 
  307 static int
  308 is_icmp_query(struct ip *ip)
  309 {
  310         const struct icmp *icmp;
  311         int icmp_type;
  312 
  313         icmp = (struct icmp *)((u_int32_t *)ip + ip->ip_hl);
  314         icmp_type = icmp->icmp_type;
  315 
  316         if (icmp_type == ICMP_ECHO || icmp_type == ICMP_ROUTERSOLICIT ||
  317             icmp_type == ICMP_TSTAMP || icmp_type == ICMP_IREQ ||
  318             icmp_type == ICMP_MASKREQ)
  319                 return(1);
  320 
  321         return(0);
  322 }
  323 
  324 static int
  325 ipopts_match(struct ip *ip, struct ip_fw *f)
  326 {
  327         register u_char *cp;
  328         int opt, optlen, cnt;
  329         u_char  opts, nopts, nopts_sve;
  330 
  331         cp = (u_char *)(ip + 1);
  332         cnt = (ip->ip_hl << 2) - sizeof (struct ip);
  333         opts = f->fw_ipopt;
  334         nopts = nopts_sve = f->fw_ipnopt;
  335 
  336         for (; cnt > 0; cnt -= optlen, cp += optlen) {
  337                 opt = cp[IPOPT_OPTVAL];
  338                 if (opt == IPOPT_EOL)
  339                         break;
  340                 if (opt == IPOPT_NOP)
  341                         optlen = 1;
  342                 else {
  343                         optlen = cp[IPOPT_OLEN];
  344                         if (optlen <= 0 || optlen > cnt) {
  345                                 return 0; /*XXX*/
  346                         }
  347                 }
  348                 switch (opt) {
  349 
  350                 default:
  351                         break;
  352 
  353                 case IPOPT_LSRR:
  354                         opts &= ~IP_FW_IPOPT_LSRR;
  355                         nopts &= ~IP_FW_IPOPT_LSRR;
  356                         break;
  357 
  358                 case IPOPT_SSRR:
  359                         opts &= ~IP_FW_IPOPT_SSRR;
  360                         nopts &= ~IP_FW_IPOPT_SSRR;
  361                         break;
  362 
  363                 case IPOPT_RR:
  364                         opts &= ~IP_FW_IPOPT_RR;
  365                         nopts &= ~IP_FW_IPOPT_RR;
  366                         break;
  367                 case IPOPT_TS:
  368                         opts &= ~IP_FW_IPOPT_TS;
  369                         nopts &= ~IP_FW_IPOPT_TS;
  370                         break;
  371                 }
  372                 if (opts == nopts)
  373                         break;
  374         }
  375         if (opts == 0 && nopts == nopts_sve)
  376                 return 1;
  377         else
  378                 return 0;
  379 }
  380 
  381 static int
  382 iptos_match(struct ip *ip, struct ip_fw *f)
  383 {
  384 
  385         u_int flags = (ip->ip_tos & 0x1f);
  386         u_char opts, nopts, nopts_sve;
  387 
  388         opts = (f->fw_iptos & 0x1f);
  389         nopts = nopts_sve = f->fw_ipntos;
  390 
  391         while (flags != 0) {
  392                 u_int flag;
  393 
  394                 flag = 1 << (ffs(flags) -1);
  395                 opts &= ~flag;
  396                 nopts &= ~flag;
  397                 flags &= ~flag;
  398         }
  399 
  400         if (opts == 0 && nopts == nopts_sve)
  401                 return 1;
  402         else
  403                 return 0;
  404 
  405 }
  406 
  407 
  408 static int
  409 tcpopts_match(struct tcphdr *tcp, struct ip_fw *f)
  410 {
  411         register u_char *cp;
  412         int opt, optlen, cnt;
  413         u_char  opts, nopts, nopts_sve;
  414 
  415         cp = (u_char *)(tcp + 1);
  416         cnt = (tcp->th_off << 2) - sizeof (struct tcphdr);
  417         opts = f->fw_tcpopt;
  418         nopts = nopts_sve = f->fw_tcpnopt;
  419 
  420         for (; cnt > 0; cnt -= optlen, cp += optlen) {
  421                 opt = cp[0];
  422                 if (opt == TCPOPT_EOL)
  423                         break;
  424                 if (opt == TCPOPT_NOP)
  425                         optlen = 1;
  426                 else {
  427                         optlen = cp[1];
  428                         if (optlen <= 0)
  429                                 break;
  430                 }
  431 
  432 
  433                 switch (opt) {
  434 
  435                 default:
  436                         break;
  437 
  438                 case TCPOPT_MAXSEG:
  439                         opts &= ~IP_FW_TCPOPT_MSS;
  440                         nopts &= ~IP_FW_TCPOPT_MSS;
  441                         break;
  442 
  443                 case TCPOPT_WINDOW:
  444                         opts &= ~IP_FW_TCPOPT_WINDOW;
  445                         nopts &= ~IP_FW_TCPOPT_WINDOW;
  446                         break;
  447 
  448                 case TCPOPT_SACK_PERMITTED:
  449                 case TCPOPT_SACK:
  450                         opts &= ~IP_FW_TCPOPT_SACK;
  451                         nopts &= ~IP_FW_TCPOPT_SACK;
  452                         break;
  453 
  454                 case TCPOPT_TIMESTAMP:
  455                         opts &= ~IP_FW_TCPOPT_TS;
  456                         nopts &= ~IP_FW_TCPOPT_TS;
  457                         break;
  458 
  459                 case TCPOPT_CC:
  460                 case TCPOPT_CCNEW:
  461                 case TCPOPT_CCECHO:
  462                         opts &= ~IP_FW_TCPOPT_CC;
  463                         nopts &= ~IP_FW_TCPOPT_CC;
  464                         break;
  465                 }
  466                 if (opts == nopts)
  467                         break;
  468         }
  469         if (opts == 0 && nopts == nopts_sve)
  470                 return 1;
  471         else
  472                 return 0;
  473 }
  474 
  475 static int
  476 iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
  477 {
  478         /* Check by name or by IP address */
  479         if (byname) {
  480                 /* Check unit number (-1 is wildcard) */
  481                 if (ifu->fu_via_if.unit != -1
  482                     && ifp->if_unit != ifu->fu_via_if.unit)
  483                         return(0);
  484                 /* Check name */
  485                 if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN))
  486                         return(0);
  487                 return(1);
  488         } else if (ifu->fu_via_ip.s_addr != 0) {        /* Zero == wildcard */
  489                 struct ifaddr *ia;
  490 
  491                 TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) {
  492                         if (ia->ifa_addr == NULL)
  493                                 continue;
  494                         if (ia->ifa_addr->sa_family != AF_INET)
  495                                 continue;
  496                         if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *)
  497                             (ia->ifa_addr))->sin_addr.s_addr)
  498                                 continue;
  499                         return(1);
  500                 }
  501                 return(0);
  502         }
  503         return(1);
  504 }
  505 
  506 static void
  507 ipfw_report(struct ip_fw *f, struct ip *ip, int ip_off, int ip_len,
  508         struct ifnet *rif, struct ifnet *oif)
  509 {
  510     struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl);
  511     struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl);
  512     struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl);
  513     u_int64_t count;
  514     char *action;
  515     char action2[32], proto[47], name[18], fragment[27];
  516     int len;
  517     int offset = ip_off & IP_OFFMASK;
  518 
  519     count = f ? f->fw_pcnt : ++counter;
  520     if ((f == NULL && fw_verbose_limit != 0 && count > fw_verbose_limit) ||
  521         (f && f->fw_logamount != 0 && count > f->fw_loghighest))
  522             return;
  523 
  524     /* Print command name */
  525     snprintf(SNPARGS(name, 0), "ipfw: %d", f ? f->fw_number : -1);
  526 
  527     action = action2;
  528     if (!f)
  529             action = "Refuse";
  530     else {
  531             switch (f->fw_flg & IP_FW_F_COMMAND) {
  532             case IP_FW_F_DENY:
  533                     action = "Deny";
  534                     break;
  535             case IP_FW_F_REJECT:
  536                     if (f->fw_reject_code == IP_FW_REJECT_RST)
  537                             action = "Reset";
  538                     else
  539                             action = "Unreach";
  540                     break;
  541             case IP_FW_F_ACCEPT:
  542                     action = "Accept";
  543                     break;
  544             case IP_FW_F_COUNT:
  545                     action = "Count";
  546                     break;
  547 #ifdef IPDIVERT
  548             case IP_FW_F_DIVERT:
  549                     snprintf(SNPARGS(action2, 0), "Divert %d",
  550                         f->fw_divert_port);
  551                     break;
  552             case IP_FW_F_TEE:
  553                     snprintf(SNPARGS(action2, 0), "Tee %d",
  554                         f->fw_divert_port);
  555                     break;
  556 #endif
  557             case IP_FW_F_SKIPTO:
  558                     snprintf(SNPARGS(action2, 0), "SkipTo %d",
  559                         f->fw_skipto_rule);
  560                     break;
  561             case IP_FW_F_PIPE:
  562                     snprintf(SNPARGS(action2, 0), "Pipe %d",
  563                         f->fw_skipto_rule);
  564                     break;
  565             case IP_FW_F_QUEUE:
  566                     snprintf(SNPARGS(action2, 0), "Queue %d",
  567                         f->fw_skipto_rule);
  568                     break;
  569 
  570             case IP_FW_F_FWD:
  571                     if (f->fw_fwd_ip.sin_port)
  572                             snprintf(SNPARGS(action2, 0),
  573                                 "Forward to %s:%d",
  574                                 inet_ntoa(f->fw_fwd_ip.sin_addr),
  575                                 f->fw_fwd_ip.sin_port);
  576                     else
  577                             snprintf(SNPARGS(action2, 0), "Forward to %s",
  578                                 inet_ntoa(f->fw_fwd_ip.sin_addr));
  579                     break;
  580 
  581             default:    
  582                     action = "UNKNOWN";
  583                     break;
  584             }
  585     }
  586 
  587     switch (ip->ip_p) {
  588     case IPPROTO_TCP:
  589             len = snprintf(SNPARGS(proto, 0), "TCP %s",
  590                 inet_ntoa(ip->ip_src));
  591             if (offset == 0)
  592                     len += snprintf(SNPARGS(proto, len), ":%d ",
  593                         ntohs(tcp->th_sport));
  594             else
  595                     len += snprintf(SNPARGS(proto, len), " ");
  596             len += snprintf(SNPARGS(proto, len), "%s",
  597                 inet_ntoa(ip->ip_dst));
  598             if (offset == 0)
  599                     snprintf(SNPARGS(proto, len), ":%d",
  600                         ntohs(tcp->th_dport));
  601             break;
  602     case IPPROTO_UDP:
  603             len = snprintf(SNPARGS(proto, 0), "UDP %s",
  604                 inet_ntoa(ip->ip_src));
  605             if (offset == 0)
  606                     len += snprintf(SNPARGS(proto, len), ":%d ",
  607                         ntohs(udp->uh_sport));
  608             else
  609                     len += snprintf(SNPARGS(proto, len), " ");
  610             len += snprintf(SNPARGS(proto, len), "%s",
  611                 inet_ntoa(ip->ip_dst));
  612             if (offset == 0)
  613                     snprintf(SNPARGS(proto, len), ":%d",
  614                         ntohs(udp->uh_dport));
  615             break;
  616     case IPPROTO_ICMP:
  617             if (offset == 0)
  618                     len = snprintf(SNPARGS(proto, 0), "ICMP:%u.%u ",
  619                         icmp->icmp_type, icmp->icmp_code);
  620             else
  621                     len = snprintf(SNPARGS(proto, 0), "ICMP ");
  622             len += snprintf(SNPARGS(proto, len), "%s",
  623                 inet_ntoa(ip->ip_src));
  624             snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst));
  625             break;
  626     default:
  627             len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p,
  628                 inet_ntoa(ip->ip_src));
  629             snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst));
  630             break;
  631     }
  632 
  633     if (ip_off & (IP_MF | IP_OFFMASK))
  634             snprintf(SNPARGS(fragment, 0), " (frag %d:%d@%d%s)",
  635                      ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2),
  636                      offset << 3,
  637                      (ip_off & IP_MF) ? "+" : "");
  638     else
  639             fragment[0] = '\0';
  640     if (oif)
  641             log(LOG_SECURITY | LOG_INFO, "%s %s %s out via %s%d%s\n",
  642                 name, action, proto, oif->if_name, oif->if_unit, fragment);
  643     else if (rif)
  644             log(LOG_SECURITY | LOG_INFO, "%s %s %s in via %s%d%s\n", name,
  645                 action, proto, rif->if_name, rif->if_unit, fragment);
  646     else
  647             log(LOG_SECURITY | LOG_INFO, "%s %s %s%s\n", name, action,
  648                 proto, fragment);
  649     if ((f ? f->fw_logamount != 0 : 1) &&
  650         count == (f ? f->fw_loghighest : fw_verbose_limit))
  651             log(LOG_SECURITY | LOG_NOTICE,
  652                 "ipfw: limit %d reached on entry %d\n",
  653                 f ? f->fw_logamount : fw_verbose_limit,
  654                 f ? f->fw_number : -1);
  655 }
  656 
  657 static __inline int
  658 hash_packet(struct ipfw_flow_id *id)
  659 {
  660     u_int32_t i ;
  661 
  662     i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);
  663     i &= (curr_dyn_buckets - 1) ;
  664     return i ;
  665 }
  666 
  667 /**
  668  * unlink a dynamic rule from a chain. prev is a pointer to
  669  * the previous one, q is a pointer to the rule to delete,
  670  * head is a pointer to the head of the queue.
  671  * Modifies q and potentially also head.
  672  */
  673 #define UNLINK_DYN_RULE(prev, head, q) {                                \
  674         struct ipfw_dyn_rule *old_q = q;                                \
  675                                                                         \
  676         /* remove a refcount to the parent */                           \
  677         if (q->dyn_type == DYN_LIMIT)                                   \
  678                 q->parent->count--;                                     \
  679         DEB(printf("-- unlink entry 0x%08x %d -> 0x%08x %d, %d left\n", \
  680                 (q->id.src_ip), (q->id.src_port),                       \
  681                 (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); )      \
  682         if (prev != NULL)                                               \
  683                 prev->next = q = q->next ;                              \
  684         else                                                            \
  685                 ipfw_dyn_v[i] = q = q->next ;                           \
  686         dyn_count-- ;                                                   \
  687         free(old_q, M_IPFW); }
  688 
  689 #define TIME_LEQ(a,b)       ((int)((a)-(b)) <= 0)
  690 /**
  691  * Remove all dynamic rules pointing to a given rule, or all
  692  * rules if rule == NULL. Second parameter is 1 if we want to
  693  * delete unconditionally, otherwise only expired rules are removed.
  694  */
  695 static void
  696 remove_dyn_rule(struct ip_fw *rule, int force)
  697 {
  698     struct ipfw_dyn_rule *prev, *q;
  699     int i, pass, max_pass ;
  700     static u_int32_t last_remove = 0 ;
  701 
  702     if (ipfw_dyn_v == NULL || dyn_count == 0)
  703         return ;
  704     /* do not expire more than once per second, it is useless */
  705     if (force == 0 && last_remove == time_second)
  706         return ;
  707     last_remove = time_second ;
  708 
  709     /*
  710      * because DYN_LIMIT refer to parent rules, during the first pass only
  711      * remove child and mark any pending LIMIT_PARENT, and remove
  712      * them in a second pass.
  713      */
  714   for (pass = max_pass = 0; pass <= max_pass ; pass++ ) {
  715     for (i = 0 ; i < curr_dyn_buckets ; i++) {
  716         for (prev=NULL, q = ipfw_dyn_v[i] ; q ; ) {
  717             /*
  718              * logic can become complex here, so we split tests.
  719              * First, test if we match any rule,
  720              * then make sure the rule is expired or we want to kill it,
  721              * and possibly more in the future.
  722              */
  723             int zap = ( rule == NULL || rule == q->rule);
  724             if (zap)
  725                 zap = force || TIME_LEQ( q->expire , time_second );
  726             /* do not zap parent in first pass, record we need a second pass */
  727             if (q->dyn_type == DYN_LIMIT_PARENT) {
  728                 max_pass = 1; /* we need a second pass */
  729                 if (zap == 1 && (pass == 0 || q->count != 0) ) {
  730                     zap = 0 ;
  731                     if (pass == 1) /* should not happen */
  732                         printf("OUCH! cannot remove rule, count %d\n",
  733                                 q->count);
  734                 }
  735             }
  736             if (zap) {
  737                 UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
  738             } else {
  739                 prev = q ;
  740                 q = q->next ;
  741             }
  742         }
  743     }
  744   }
  745 }
  746 
  747 #define EXPIRE_DYN_CHAIN(rule) remove_dyn_rule(rule, 0 /* expired ones */)
  748 #define EXPIRE_DYN_CHAINS() remove_dyn_rule(NULL, 0 /* expired ones */)
  749 #define DELETE_DYN_CHAIN(rule) remove_dyn_rule(rule, 1 /* force removal */)
  750 #define DELETE_DYN_CHAINS() remove_dyn_rule(NULL, 1 /* force removal */)
  751 
  752 /**
  753  * lookup a dynamic rule.
  754  */
  755 static struct ipfw_dyn_rule *
  756 lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction)
  757 {
  758     /*
  759      * stateful ipfw extensions.
  760      * Lookup into dynamic session queue
  761      */
  762     struct ipfw_dyn_rule *prev, *q ;
  763     int i, dir = 0;
  764 #define MATCH_FORWARD 1
  765 
  766     if (ipfw_dyn_v == NULL)
  767         return NULL ;
  768     i = hash_packet( pkt );
  769     for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) {
  770         if (q->dyn_type == DYN_LIMIT_PARENT)
  771             goto next;
  772         if (TIME_LEQ( q->expire , time_second ) ) { /* expire entry */
  773             UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
  774             continue;
  775         }
  776         if ( pkt->proto == q->id.proto) {
  777             if (pkt->src_ip == q->id.src_ip &&
  778                     pkt->dst_ip == q->id.dst_ip &&
  779                     pkt->src_port == q->id.src_port &&
  780                     pkt->dst_port == q->id.dst_port ) {
  781                 dir = MATCH_FORWARD ;
  782                 goto found ;
  783             }
  784             if (pkt->src_ip == q->id.dst_ip &&
  785                     pkt->dst_ip == q->id.src_ip &&
  786                     pkt->src_port == q->id.dst_port &&
  787                     pkt->dst_port == q->id.src_port ) {
  788                 dir = 0 ; /* reverse match */
  789                 goto found ;
  790             }
  791         }
  792 next:
  793         prev = q ;
  794         q = q->next ;
  795     }
  796     return NULL ; /* clearly not found */
  797 found:
  798     if ( prev != NULL) { /* found and not in front */
  799         prev->next = q->next ;
  800         q->next = ipfw_dyn_v[i] ;
  801         ipfw_dyn_v[i] = q ;
  802     }
  803     if (pkt->proto == IPPROTO_TCP) {
  804         /* update state according to flags */
  805         u_char flags = pkt->flags & (TH_FIN|TH_SYN|TH_RST);
  806         q->state |= (dir == MATCH_FORWARD ) ? flags : (flags << 8);
  807         switch (q->state) {
  808         case TH_SYN :
  809             /* opening */
  810             q->expire = time_second + dyn_syn_lifetime ;
  811             break ;
  812         case TH_SYN | (TH_SYN << 8) :
  813             /* move to established */
  814             q->expire = time_second + dyn_ack_lifetime ;
  815             break ;
  816         case TH_SYN | (TH_SYN << 8) | TH_FIN :
  817         case TH_SYN | (TH_SYN << 8) | (TH_FIN << 8) :
  818             /* one side tries to close */
  819             q->expire = time_second + dyn_ack_lifetime ;
  820             break ;
  821         case TH_SYN | (TH_SYN << 8) | TH_FIN | (TH_FIN << 8) :
  822             /* both sides closed */
  823             q->expire = time_second + dyn_fin_lifetime ;
  824             break ;
  825         default:
  826 #if 0
  827             /*
  828              * reset or some invalid combination, but can also
  829              * occur if we use keep-state the wrong way.
  830              */
  831             if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0)
  832                 printf("invalid state: 0x%x\n", q->state);
  833 #endif
  834             q->expire = time_second + dyn_rst_lifetime ;
  835             break ;
  836         }
  837     } else if (pkt->proto == IPPROTO_UDP) {
  838         q->expire = time_second + dyn_udp_lifetime ;
  839     } else {
  840         /* other protocols */
  841         q->expire = time_second + dyn_short_lifetime ;
  842     }
  843     if (match_direction)
  844         *match_direction = dir ;
  845     return q ;
  846 }
  847 
  848 /**
  849  * Install state of type 'type' for a dynamic session.
  850  * The hash table contains two type of rules:
  851  * - regular rules (DYN_KEEP_STATE)
  852  * - rules for sessions with limited number of sess per user
  853  *   (DYN_LIMIT). When they are created, the parent is
  854  *   increased by 1, and decreased on delete. In this case,
  855  *   the third parameter is the parent rule and not the chain.
  856  * - "parent" rules for the above (DYN_LIMIT_PARENT).
  857  */
  858 
  859 static struct ipfw_dyn_rule *
  860 add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule)
  861 {
  862     struct ipfw_dyn_rule *r ;
  863 
  864     int i ;
  865     if (ipfw_dyn_v == NULL ||
  866                 (dyn_count == 0 && dyn_buckets != curr_dyn_buckets)) {
  867         /* try reallocation, make sure we have a power of 2 */
  868         u_int32_t i = dyn_buckets ;
  869         while ( i > 0 && (i & 1) == 0 )
  870             i >>= 1 ;
  871         if (i != 1) /* not a power of 2 */
  872             dyn_buckets = curr_dyn_buckets ; /* reset */
  873         else {
  874             curr_dyn_buckets = dyn_buckets ;
  875             if (ipfw_dyn_v != NULL)
  876                 free(ipfw_dyn_v, M_IPFW);
  877             ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof r,
  878                    M_IPFW, M_DONTWAIT | M_ZERO);
  879             if (ipfw_dyn_v == NULL)
  880                 return NULL; /* failed ! */
  881         }
  882     }
  883     i = hash_packet(id);
  884 
  885     r = malloc(sizeof *r, M_IPFW, M_NOWAIT | M_ZERO);
  886     if (r == NULL) {
  887         printf ("sorry cannot allocate state\n");
  888         return NULL ;
  889     }
  890 
  891     /* increase refcount on parent, and set pointer */
  892     if (dyn_type == DYN_LIMIT) {
  893         struct ipfw_dyn_rule *parent = (struct ipfw_dyn_rule *)rule;
  894         if ( parent->dyn_type != DYN_LIMIT_PARENT)
  895             panic("invalid parent");
  896         parent->count++ ;
  897         r->parent = parent ;
  898         rule = parent->rule;
  899     }
  900 
  901     r->id = *id ;
  902     r->expire = time_second + dyn_syn_lifetime ;
  903     r->rule = rule ;
  904     r->dyn_type = dyn_type ;
  905     r->pcnt = r->bcnt = 0 ;
  906     r->count = 0 ;
  907 
  908     r->bucket = i ;
  909     r->next = ipfw_dyn_v[i] ;
  910     ipfw_dyn_v[i] = r ;
  911     dyn_count++ ;
  912     DEB(printf("-- add entry 0x%08x %d -> 0x%08x %d, total %d\n",
  913        (r->id.src_ip), (r->id.src_port),
  914        (r->id.dst_ip), (r->id.dst_port),
  915        dyn_count ); )
  916     return r;
  917 }
  918 
  919 /**
  920  * lookup dynamic parent rule using pkt and rule as search keys.
  921  * If the lookup fails, then install one.
  922  */
  923 static struct ipfw_dyn_rule *
  924 lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
  925 {
  926     struct ipfw_dyn_rule *q;
  927     int i;
  928 
  929     if (ipfw_dyn_v) {
  930         i = hash_packet( pkt );
  931         for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
  932             if (q->dyn_type == DYN_LIMIT_PARENT && rule == q->rule &&
  933                     pkt->proto == q->id.proto &&
  934                     pkt->src_ip == q->id.src_ip &&
  935                     pkt->dst_ip == q->id.dst_ip &&
  936                     pkt->src_port == q->id.src_port &&
  937                     pkt->dst_port == q->id.dst_port) {
  938                 q->expire = time_second + dyn_short_lifetime ;
  939                 DEB(printf("lookup_dyn_parent found 0x%p\n", q);)
  940                 return q;
  941             }
  942     }
  943     return add_dyn_rule(pkt, DYN_LIMIT_PARENT, rule);
  944 }
  945 
  946 /*
  947  * Install dynamic state.
  948  * There are different types of dynamic rules which can be installed.
  949  * The type is in rule->dyn_type.
  950  * Type 0 (default) is a bidirectional rule
  951  *
  952  * Returns 1 (failure) if state is not installed because of errors or because
  953  * session limitations are enforced.
  954  */
  955 static int
  956 install_state(struct ip_fw *rule, struct ip_fw_args *args)
  957 {
  958     struct ipfw_dyn_rule *q ;
  959     static int last_log ;
  960 
  961     u_int8_t type = rule->dyn_type ;
  962 
  963     DEB(printf("-- install state type %d 0x%08x %u -> 0x%08x %u\n",
  964        type,
  965        (args->f_id.src_ip), (args->f_id.src_port),
  966        (args->f_id.dst_ip), (args->f_id.dst_port) );)
  967 
  968     q = lookup_dyn_rule(&args->f_id, NULL) ;
  969     if (q != NULL) { /* should never occur */
  970         if (last_log != time_second) {
  971             last_log = time_second ;
  972             printf(" entry already present, done\n");
  973         }
  974         return 0 ;
  975     }
  976     if (dyn_count >= dyn_max) /* try remove old ones... */
  977         EXPIRE_DYN_CHAINS();
  978     if (dyn_count >= dyn_max) {
  979         if (last_log != time_second) {
  980             last_log = time_second ;
  981             printf(" Too many dynamic rules, sorry\n");
  982         }
  983         return 1; /* cannot install, notify caller */
  984     }
  985 
  986     switch (type) {
  987     case DYN_KEEP_STATE: /* bidir rule */
  988         add_dyn_rule(&args->f_id, DYN_KEEP_STATE, rule);
  989         break ;
  990     case DYN_LIMIT: /* limit number of sessions */
  991         {
  992         u_int16_t limit_mask = rule->limit_mask ;
  993         u_int16_t conn_limit = rule->conn_limit ;
  994         struct ipfw_flow_id id;
  995         struct ipfw_dyn_rule *parent;
  996 
  997         DEB(printf("installing dyn-limit rule %d\n", conn_limit);)
  998 
  999         id.dst_ip = id.src_ip = 0;
 1000         id.dst_port = id.src_port = 0 ;
 1001         id.proto = args->f_id.proto ;
 1002 
 1003         if (limit_mask & DYN_SRC_ADDR)
 1004             id.src_ip = args->f_id.src_ip;
 1005         if (limit_mask & DYN_DST_ADDR)
 1006             id.dst_ip = args->f_id.dst_ip;
 1007         if (limit_mask & DYN_SRC_PORT)
 1008             id.src_port = args->f_id.src_port;
 1009         if (limit_mask & DYN_DST_PORT)
 1010             id.dst_port = args->f_id.dst_port;
 1011         parent = lookup_dyn_parent(&id, rule);
 1012         if (parent == NULL) {
 1013             printf("add parent failed\n");
 1014             return 1;
 1015         }
 1016         if (parent->count >= conn_limit) {
 1017             EXPIRE_DYN_CHAIN(rule); /* try to expire some */
 1018             if (parent->count >= conn_limit) {
 1019                 printf("drop session, too many entries\n");
 1020                 return 1;
 1021             }
 1022         }
 1023         add_dyn_rule(&args->f_id, DYN_LIMIT, (struct ip_fw *)parent);
 1024         }
 1025         break ;
 1026     default:
 1027         printf("unknown dynamic rule type %u\n", type);
 1028         return 1 ;
 1029     }
 1030     lookup_dyn_rule(&args->f_id, NULL) ; /* XXX just set the lifetime */
 1031     return 0;
 1032 }
 1033 
 1034 /*
 1035  * given an ip_fw *, lookup_next_rule will return a pointer
 1036  * of the same type to the next one. This can be either the jump
 1037  * target (for skipto instructions) or the next one in the list (in
 1038  * all other cases including a missing jump target).
 1039  * Backward jumps are not allowed, so start looking from the next
 1040  * rule...
 1041  */ 
 1042 static struct ip_fw * lookup_next_rule(struct ip_fw *me);
 1043 
 1044 static struct ip_fw *
 1045 lookup_next_rule(struct ip_fw *me)
 1046 {
 1047     struct ip_fw *rule ;
 1048     int rulenum = me->fw_skipto_rule ; /* guess... */
 1049 
 1050     if ( (me->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO )
 1051         for (rule = LIST_NEXT(me,next); rule ; rule = LIST_NEXT(rule,next))
 1052             if (rule->fw_number >= rulenum)
 1053                 return rule ;
 1054     return LIST_NEXT(me,next) ; /* failure or not a skipto */
 1055 }
 1056 
 1057 /*
 1058  * Parameters:
 1059  *
 1060  *      *m      The packet; we set to NULL when/if we nuke it.
 1061  *      oif     Outgoing interface, or NULL if packet is incoming
 1062  *      *cookie Skip up to the first rule past this rule number;
 1063  *              upon return, non-zero port number for divert or tee.
 1064  *              Special case: cookie == NULL on input for bridging.
 1065  *      *flow_id pointer to the last matching rule (in/out)
 1066  *      *next_hop socket we are forwarding to (in/out).
 1067  *              For bridged packets, this is a pointer to the MAC header.
 1068  *
 1069  * Return value:
 1070  *
 1071  *      IP_FW_PORT_DENY_FLAG    the packet must be dropped.
 1072  *      0       The packet is to be accepted and routed normally OR
 1073  *              the packet was denied/rejected and has been dropped;
 1074  *              in the latter case, *m is equal to NULL upon return.
 1075  *      port    Divert the packet to port, with these caveats:
 1076  *
 1077  *              - If IP_FW_PORT_TEE_FLAG is set, tee the packet instead
 1078  *                of diverting it (ie, 'ipfw tee').
 1079  *
 1080  *              - If IP_FW_PORT_DYNT_FLAG is set, interpret the lower
 1081  *                16 bits as a dummynet pipe number instead of diverting
 1082  */
 1083 
 1084 static int 
 1085 ip_fw_chk(struct ip_fw_args *args)
 1086 #if 0 /* the old interface was this: */
 1087         struct mbuf **m, struct ifnet *oif, u_int16_t *cookie,
 1088         struct ip_fw **flow_id, struct sockaddr_in **next_hop)
 1089 #endif
 1090 {
 1091         /*
 1092          * grab things into variables to minimize diffs.
 1093          * XXX this has to be cleaned up later.
 1094          */
 1095         struct mbuf **m = &(args->m);
 1096         struct ifnet *oif = args->oif;
 1097         u_int16_t *cookie = &(args->divert_rule);
 1098         struct ip_fw **flow_id = &(args->rule);
 1099         struct sockaddr_in **next_hop = &(args->next_hop);
 1100 
 1101         struct ip_fw *f = NULL;         /* matching rule */
 1102         struct ip *ip = mtod(*m, struct ip *);
 1103         struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
 1104         struct ifnet *tif;
 1105         u_int hlen = ip->ip_hl << 2;
 1106         struct ether_header * eh = NULL;
 1107 
 1108         u_short ip_off=0, offset = 0 ;
 1109         /* local copy of addresses for faster matching */
 1110         u_short src_port = 0, dst_port = 0;
 1111         struct in_addr src_ip, dst_ip;
 1112         u_int8_t proto= 0, flags = 0;
 1113 
 1114         u_int16_t skipto;
 1115         u_int16_t ip_len=0;
 1116 
 1117         int dyn_checked = 0 ; /* set after dyn.rules have been checked. */
 1118         int direction = MATCH_FORWARD ; /* dirty trick... */
 1119         struct ipfw_dyn_rule *q = NULL ;
 1120 
 1121 #define BRIDGED (args->eh != NULL)
 1122         if (BRIDGED) {  /* this is a bridged packet */
 1123             eh = args->eh;
 1124             if ( (*m)->m_pkthdr.len >= sizeof(struct ip) &&
 1125                         ntohs(eh->ether_type) == ETHERTYPE_IP)
 1126                 hlen = ip->ip_hl << 2;
 1127         } else
 1128             hlen = ip->ip_hl << 2;
 1129 
 1130         /* Grab and reset cookie */
 1131         skipto = *cookie;
 1132         *cookie = 0;
 1133 
 1134         /*
 1135          * Collect parameters into local variables for faster matching.
 1136          */
 1137         if (hlen > 0) { /* this is an IP packet */
 1138             proto = ip->ip_p;
 1139             src_ip = ip->ip_src;
 1140             dst_ip = ip->ip_dst;
 1141             if (BRIDGED) { /* bridged packets are as on the wire */
 1142                 ip_off = ntohs(ip->ip_off);
 1143                 ip_len = ntohs(ip->ip_len);
 1144             } else {
 1145                 ip_off = ip->ip_off;
 1146                 ip_len = ip->ip_len;
 1147             }
 1148             offset = ip_off & IP_OFFMASK;
 1149             if (offset == 0) {
 1150 
 1151 #define PULLUP_TO(len)                                          \
 1152                 do {                                            \
 1153                         if ((*m)->m_len < (len)) {              \
 1154                             *m = m_pullup(*m, (len));           \
 1155                             if (*m == 0)                        \
 1156                                 goto bogusfrag;                 \
 1157                             ip = mtod(*m, struct ip *);         \
 1158                         }                                       \
 1159                 } while (0)
 1160 
 1161                 switch (proto) {
 1162                 case IPPROTO_TCP : {
 1163                     struct tcphdr *tcp;
 1164 
 1165                     PULLUP_TO(hlen + sizeof(struct tcphdr));
 1166                     tcp =(struct tcphdr *)((u_int32_t *)ip + ip->ip_hl);
 1167                     dst_port = tcp->th_dport ;
 1168                     src_port = tcp->th_sport ;
 1169                     flags = tcp->th_flags ;
 1170                     }
 1171                     break ;
 1172 
 1173                 case IPPROTO_UDP : {
 1174                     struct udphdr *udp;
 1175 
 1176                     PULLUP_TO(hlen + sizeof(struct udphdr));
 1177                     udp =(struct udphdr *)((u_int32_t *)ip + ip->ip_hl);
 1178                     dst_port = udp->uh_dport ;
 1179                     src_port = udp->uh_sport ;
 1180                     }
 1181                     break;
 1182 
 1183                 case IPPROTO_ICMP:
 1184                     PULLUP_TO(hlen + 4);        /* type, code and checksum. */
 1185                     flags = ((struct icmp *)
 1186                             ((u_int32_t *)ip + ip->ip_hl))->icmp_type ;
 1187                     break ;
 1188 
 1189                 default :
 1190                     break;
 1191                 }
 1192 #undef PULLUP_TO
 1193             }
 1194         }
 1195         args->f_id.src_ip = ntohl(src_ip.s_addr);
 1196         args->f_id.dst_ip = ntohl(dst_ip.s_addr);
 1197         args->f_id.proto = proto;
 1198         args->f_id.src_port = ntohs(src_port);
 1199         args->f_id.dst_port = ntohs(dst_port);
 1200         args->f_id.flags = flags;
 1201 
 1202         if (*flow_id) {
 1203             /*
 1204              * Packet has already been tagged. Look for the next rule
 1205              * to restart processing.
 1206              */
 1207             if (fw_one_pass) /* just accept if fw_one_pass is set */
 1208                 return 0;
 1209 
 1210             f = (*flow_id)->next_rule_ptr ;
 1211             if (f == NULL)
 1212                 f = (*flow_id)->next_rule_ptr = lookup_next_rule(*flow_id);
 1213             if (f == NULL)
 1214                 goto dropit;
 1215         } else {
 1216             /*
 1217              * Go down the list, looking for enlightment.
 1218              * If we've been asked to start at a given rule, do so.
 1219              */
 1220             f = LIST_FIRST(&ip_fw_chain_head);
 1221             if (skipto != 0) {
 1222                 if (skipto >= IPFW_DEFAULT_RULE)
 1223                     goto dropit;
 1224                 while (f && f->fw_number <= skipto)
 1225                     f = LIST_NEXT(f, next);
 1226                 if (f == NULL)
 1227                     goto dropit;
 1228             }
 1229         }
 1230 
 1231         for (; f; f = LIST_NEXT(f, next)) {
 1232 again:
 1233                 if (f->fw_number == IPFW_DEFAULT_RULE)
 1234                     goto got_match ;
 1235 
 1236                 /* Check if rule only valid for bridged packets */
 1237                 if ((f->fw_flg & IP_FW_BRIDGED) != 0 && !(BRIDGED))
 1238                     continue;
 1239 
 1240                 if (oif) {
 1241                     /* Check direction outbound */
 1242                     if (!(f->fw_flg & IP_FW_F_OUT))
 1243                         continue;
 1244                 } else {
 1245                     /* Check direction inbound */
 1246                     if (!(f->fw_flg & IP_FW_F_IN))
 1247                         continue;
 1248                 }
 1249 
 1250                 if (f->fw_flg & IP_FW_F_MAC) {
 1251                     u_int32_t *want, *mask, *hdr;
 1252 
 1253                     if (eh == NULL) /* header not available */
 1254                         continue;
 1255 
 1256                     want = (void *)&(f->fw_mac_hdr);
 1257                     mask = (void *)&(f->fw_mac_mask);
 1258                     hdr = (void *)eh;
 1259 
 1260                     if ( want[0] != (hdr[0] & mask[0]) )
 1261                         continue;
 1262                     if ( want[1] != (hdr[1] & mask[1]) )
 1263                         continue;
 1264                     if ( want[2] != (hdr[2] & mask[2]) )
 1265                         continue;
 1266                     if (f->fw_flg & IP_FW_F_SRNG) {
 1267                         u_int16_t type = ntohs(eh->ether_type);
 1268                         if (type < (u_int16_t)(f->fw_mac_type) ||
 1269                                 type > (u_int16_t)(f->fw_mac_mask_type) )
 1270                             continue;
 1271                     } else {
 1272                         if ((u_int16_t)(f->fw_mac_type) != (eh->ether_type &
 1273                                 (u_int16_t)(f->fw_mac_mask_type)) )
 1274                             continue;
 1275                     }
 1276                 }
 1277 
 1278                 /* Interface check */
 1279                 if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
 1280                         struct ifnet *const iface = oif ? oif : rif;
 1281 
 1282                         /* Backwards compatibility hack for "via" */
 1283                         if (!iface || !iface_match(iface,
 1284                             &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))
 1285                                 continue;
 1286                 } else {
 1287                         /* Check receive interface */
 1288                         if ((f->fw_flg & IP_FW_F_IIFACE)
 1289                             && (!rif || !iface_match(rif,
 1290                               &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))
 1291                                 continue;
 1292                         /* Check outgoing interface */
 1293                         if ((f->fw_flg & IP_FW_F_OIFACE)
 1294                             && (!oif || !iface_match(oif,
 1295                               &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))
 1296                                 continue;
 1297                 }
 1298 
 1299                 /*
 1300                  * For packets which matched the MAC check, we do not need
 1301                  * to continue, this is a valid match.
 1302                  * For not-ip packets, the rule does not apply.
 1303                  */
 1304                 if (f->fw_flg & IP_FW_F_MAC)
 1305                         goto rnd_then_got_match;
 1306 
 1307                 if (hlen == 0)
 1308                         continue;
 1309 
 1310                 /*
 1311                  * dynamic rules are checked at the first keep-state or
 1312                  * check-state occurrence.
 1313                  */
 1314                 if (f->fw_flg & (IP_FW_F_KEEP_S|IP_FW_F_CHECK_S) &&
 1315                          dyn_checked == 0 ) {
 1316                     dyn_checked = 1 ;
 1317                     q = lookup_dyn_rule(&args->f_id, &direction);
 1318                     if (q != NULL) {
 1319                         DEB(printf("-- dynamic match 0x%08x %d %s 0x%08x %d\n",
 1320                             (q->id.src_ip), (q->id.src_port),
 1321                             (direction == MATCH_FORWARD ? "-->" : "<--"),
 1322                             (q->id.dst_ip), (q->id.dst_port) ); )
 1323                         f = q->rule ;
 1324                         q->pcnt++ ;
 1325                         q->bcnt += ip_len;
 1326                         goto got_match ; /* random not allowed here */
 1327                     }
 1328                     /* if this was a check-only rule, continue with next */
 1329                     if (f->fw_flg & IP_FW_F_CHECK_S)
 1330                         continue ;
 1331                 }
 1332 
 1333                 /* Fragments */
 1334                 if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 )
 1335                         continue;
 1336 
 1337                 /*
 1338                  * For matching addresses, tif != NULL means we matched
 1339                  * the address we requested (either "me" or addr/mask).
 1340                  * Then the check for "xxx" or "not xxx" can be done
 1341                  * with an XOR.
 1342                  */
 1343 
 1344                 /* source address --    mandatory */
 1345                 if (f->fw_flg & IP_FW_F_SME) {
 1346                         INADDR_TO_IFP(src_ip, tif);
 1347                 } else
 1348                         (int)tif = f->fw_src.s_addr ==
 1349                             (src_ip.s_addr & f->fw_smsk.s_addr);
 1350                 if ( ((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ (tif == NULL) )
 1351                         continue;
 1352                 
 1353                 /* dst address --       mandatory */
 1354                 if (f->fw_flg & IP_FW_F_DME) {
 1355                         INADDR_TO_IFP(dst_ip, tif);
 1356                 } else
 1357                         (int)tif = f->fw_dst.s_addr ==
 1358                             (dst_ip.s_addr & f->fw_dmsk.s_addr);
 1359                 if ( ((f->fw_flg & IP_FW_F_INVDST) != 0) ^ (tif == NULL) )
 1360                         continue;
 1361                 
 1362                 /* Check IP header values */
 1363                 if (f->fw_ipflg & IP_FW_IF_IPOPT && !ipopts_match(ip, f))
 1364                         continue;
 1365                 if (f->fw_ipflg & IP_FW_IF_IPLEN && f->fw_iplen != ip_len)
 1366                         continue;
 1367                 if (f->fw_ipflg & IP_FW_IF_IPID && f->fw_ipid != ntohs(ip->ip_id))
 1368                         continue;
 1369                 if (f->fw_ipflg & IP_FW_IF_IPPRE &&
 1370                      (f->fw_iptos & 0xe0) != (ip->ip_tos & 0xe0))
 1371                         continue;
 1372                 if (f->fw_ipflg & IP_FW_IF_IPTOS && !iptos_match(ip, f))
 1373                         continue;
 1374                 if (f->fw_ipflg & IP_FW_IF_IPTTL && f->fw_ipttl != ip->ip_ttl)
 1375                         continue;
 1376                 if (f->fw_ipflg & IP_FW_IF_IPVER && f->fw_ipver != ip->ip_v)
 1377                         continue;
 1378 
 1379                 /* Check protocol; if wildcard, and no [ug]id, match */
 1380                 if (f->fw_prot == IPPROTO_IP) {
 1381                         if (!(f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)))
 1382                                 goto rnd_then_got_match;
 1383                 } else
 1384                     /* If different, don't match */
 1385                     if (proto != f->fw_prot) 
 1386                             continue;
 1387 
 1388                 /* Protocol specific checks for uid only */
 1389                 if (f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)) {
 1390                     switch (proto) {
 1391                     case IPPROTO_TCP:
 1392                         {
 1393                             struct inpcb *P;
 1394 
 1395                             if (offset == 1)    /* cf. RFC 1858 */
 1396                                     goto bogusfrag;
 1397                             if (offset != 0)
 1398                                     continue;
 1399 
 1400                             if (oif)
 1401                                 P = in_pcblookup_hash(&tcbinfo, dst_ip,
 1402                                    dst_port, src_ip, src_port, 0,
 1403                                    oif);
 1404                             else
 1405                                 P = in_pcblookup_hash(&tcbinfo, src_ip,
 1406                                    src_port, dst_ip, dst_port, 0,
 1407                                    NULL);
 1408 
 1409                             if (P && P->inp_socket) {
 1410                                 if (f->fw_flg & IP_FW_F_UID) {
 1411                                         if (socheckuid(P->inp_socket, f->fw_uid))
 1412                                                 continue;
 1413                                 } else if (!groupmember(f->fw_gid,
 1414                                             P->inp_socket->so_cred))
 1415                                                 continue;
 1416                             } else
 1417                                 continue;
 1418                             break;
 1419                         }
 1420 
 1421                     case IPPROTO_UDP:
 1422                         {
 1423                             struct inpcb *P;
 1424 
 1425                             if (offset != 0)
 1426                                 continue;
 1427 
 1428                             if (oif)
 1429                                 P = in_pcblookup_hash(&udbinfo, dst_ip,
 1430                                    dst_port, src_ip, src_port, 1,
 1431                                    oif);
 1432                             else
 1433                                 P = in_pcblookup_hash(&udbinfo, src_ip,
 1434                                    src_port, dst_ip, dst_port, 1,
 1435                                    NULL);
 1436 
 1437                             if (P && P->inp_socket) {
 1438                                 if (f->fw_flg & IP_FW_F_UID) {
 1439                                         if (socheckuid(P->inp_socket, f->fw_uid))
 1440                                                 continue;
 1441                                 } else if (!groupmember(f->fw_gid,
 1442                                             P->inp_socket->so_cred))
 1443                                                 continue;
 1444                             } else
 1445                                 continue;
 1446                             break;
 1447                         }
 1448 
 1449                     default:
 1450                             continue;
 1451                     }
 1452                 }
 1453                     
 1454                 /* Protocol specific checks */
 1455                 switch (proto) {
 1456                 case IPPROTO_TCP:
 1457                     {
 1458                         struct tcphdr *tcp;
 1459 
 1460                         if (offset == 1)        /* cf. RFC 1858 */
 1461                                 goto bogusfrag;
 1462                         if (offset != 0) {
 1463                                 /*
 1464                                  * TCP flags and ports aren't available in this
 1465                                  * packet -- if this rule specified either one,
 1466                                  * we consider the rule a non-match.
 1467                                  */
 1468                                 if (IP_FW_HAVEPORTS(f) != 0 ||
 1469                                     f->fw_ipflg & IP_FW_IF_TCPMSK)
 1470                                         continue;
 1471 
 1472                                 break;
 1473                         }
 1474                         tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
 1475 
 1476                         if (f->fw_ipflg & IP_FW_IF_TCPOPT && !tcpopts_match(tcp, f))
 1477                                 continue;
 1478                         if (((f->fw_ipflg & IP_FW_IF_TCPFLG) ||
 1479                             (f->fw_ipflg & IP_FW_IF_TCPEST)) &&
 1480                             !tcpflg_match(tcp, f))
 1481                                 continue;
 1482                         if (f->fw_ipflg & IP_FW_IF_TCPSEQ && tcp->th_seq != f->fw_tcpseq)
 1483                                 continue;
 1484                         if (f->fw_ipflg & IP_FW_IF_TCPACK && tcp->th_ack != f->fw_tcpack)
 1485                                 continue;
 1486                         if (f->fw_ipflg & IP_FW_IF_TCPWIN && tcp->th_win != f->fw_tcpwin)
 1487                                 continue;
 1488                         goto check_ports;
 1489                     }
 1490 
 1491                 case IPPROTO_UDP:
 1492                         if (offset != 0) {
 1493                                 /*
 1494                                  * Port specification is unavailable -- if this
 1495                                  * rule specifies a port, we consider the rule
 1496                                  * a non-match.
 1497                                  */
 1498                                 if (IP_FW_HAVEPORTS(f) )
 1499                                         continue;
 1500 
 1501                                 break;
 1502                         }
 1503 check_ports:
 1504                         if (!port_match(&f->fw_uar.fw_pts[0],
 1505                             IP_FW_GETNSRCP(f), ntohs(src_port),
 1506                             f->fw_flg & IP_FW_F_SRNG,
 1507                             f->fw_flg & IP_FW_F_SMSK))
 1508                                 continue;
 1509                         if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)],
 1510                             IP_FW_GETNDSTP(f), ntohs(dst_port),
 1511                             f->fw_flg & IP_FW_F_DRNG,
 1512                             f->fw_flg & IP_FW_F_DMSK)) 
 1513                                 continue;
 1514                         break;
 1515 
 1516                 case IPPROTO_ICMP:
 1517                     {
 1518                         struct icmp *icmp;
 1519 
 1520                         if (offset != 0)        /* Type isn't valid */
 1521                                 break;
 1522                         icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl);
 1523                         if (!icmptype_match(icmp, f))
 1524                                 continue;
 1525                         break;
 1526                     }
 1527 
 1528                 default:
 1529                         break;
 1530 
 1531 bogusfrag:
 1532                 if (fw_verbose) {
 1533                         if (*m != NULL)
 1534                                 ipfw_report(NULL, ip, ip_off, ip_len, rif, oif);
 1535                         else
 1536                                 printf("pullup failed\n");
 1537                 }
 1538                 goto dropit;
 1539 
 1540                 }
 1541 
 1542 rnd_then_got_match:
 1543                 if ( f->dont_match_prob && random() < f->dont_match_prob )
 1544                         continue ;
 1545 got_match:
 1546                 /*
 1547                  * If not a dynamic match (q == NULL) and keep-state, install
 1548                  * a new dynamic entry.
 1549                  */
 1550                 if (q == NULL && f->fw_flg & IP_FW_F_KEEP_S) {
 1551                     if (install_state(f, args)) /* error or limit violation */
 1552                         goto dropit;
 1553                 }
 1554                 /* Update statistics */
 1555                 f->fw_pcnt += 1;
 1556                 f->fw_bcnt += ip_len;
 1557                 f->timestamp = time_second;
 1558 
 1559                 /* Log to console if desired */
 1560                 if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose && hlen >0)
 1561                         ipfw_report(f, ip, ip_off, ip_len, rif, oif);
 1562 
 1563                 /* Take appropriate action */
 1564                 switch (f->fw_flg & IP_FW_F_COMMAND) {
 1565                 case IP_FW_F_ACCEPT:
 1566                         return(0);
 1567                 case IP_FW_F_COUNT:
 1568                         continue;
 1569 #ifdef IPDIVERT
 1570                 case IP_FW_F_DIVERT:
 1571                         *cookie = f->fw_number;
 1572                         return(f->fw_divert_port);
 1573                 case IP_FW_F_TEE:
 1574                         *cookie = f->fw_number;
 1575                         return(f->fw_divert_port | IP_FW_PORT_TEE_FLAG);
 1576 #endif
 1577                 case IP_FW_F_SKIPTO: /* XXX check */
 1578                         if (f->next_rule_ptr == NULL)
 1579                             f->next_rule_ptr = lookup_next_rule(f) ;
 1580                         f = f->next_rule_ptr;
 1581                         if (!f)
 1582                             goto dropit;
 1583                         goto again ;
 1584 
 1585                 case IP_FW_F_PIPE:
 1586                 case IP_FW_F_QUEUE:
 1587                         *flow_id = f; /* XXX set flow id */
 1588                         return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG);
 1589 
 1590                 case IP_FW_F_FWD:
 1591                         /* Change the next-hop address for this packet.
 1592                          * Initially we'll only worry about directly
 1593                          * reachable next-hop's, but ultimately
 1594                          * we will work out for next-hops that aren't
 1595                          * direct the route we would take for it. We
 1596                          * [cs]ould leave this latter problem to
 1597                          * ip_output.c. We hope to high [name the abode of
 1598                          * your favourite deity] that ip_output doesn't modify
 1599                          * the new value of next_hop (which is dst there)
 1600                          * XXX warning-- there is a dangerous reference here
 1601                          * from next_hop to a field within the rule. If the
 1602                          * rule is deleted, weird things might occur.
 1603                          */
 1604                         if (next_hop != NULL /* Make sure, first... */
 1605                             && (q == NULL || direction == MATCH_FORWARD) )
 1606                                 *next_hop = &(f->fw_fwd_ip);
 1607                         return(0); /* Allow the packet */
 1608 
 1609                 }
 1610 
 1611                 /* Deny/reject this packet using this rule */
 1612                 break;
 1613         }
 1614 
 1615         /* Rule IPFW_DEFAULT_RULE should always be there and match */
 1616         KASSERT(f != NULL, ("ip_fw: no chain"));
 1617 
 1618         /*
 1619          * At this point, we're going to drop the packet.
 1620          * Send a reject notice if all of the following are true:
 1621          *
 1622          * - The packet matched a reject rule
 1623          * - The packet is not an ICMP packet, or is an ICMP query packet
 1624          * - The packet is not a multicast or broadcast packet
 1625          */
 1626         if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
 1627             && (proto != IPPROTO_ICMP || is_icmp_query(ip))
 1628             && !((*m)->m_flags & (M_BCAST|M_MCAST))
 1629             && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
 1630                 /* Must convert to host order for icmp_error() etc. */
 1631                 if (BRIDGED) {
 1632                         ip->ip_len = ntohs(ip->ip_len);
 1633                         ip->ip_off = ntohs(ip->ip_off);
 1634                 }
 1635                 switch (f->fw_reject_code) {
 1636                 case IP_FW_REJECT_RST:
 1637                     {
 1638                         /* XXX warning, this code writes into the mbuf */
 1639                         struct tcphdr *const tcp =
 1640                                 (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
 1641                         struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;
 1642 
 1643                         if (offset != 0 || (tcp->th_flags & TH_RST))
 1644                                 break;
 1645                         ti.ti_i = *((struct ipovly *) ip);
 1646                         ti.ti_t = *tcp;
 1647                         bcopy(&ti, ip, sizeof(ti));
 1648                         tip->ti_seq = ntohl(tip->ti_seq);
 1649                         tip->ti_ack = ntohl(tip->ti_ack);
 1650                         tip->ti_len = ip_len - hlen - (tip->ti_off << 2);
 1651                         if (tcp->th_flags & TH_ACK) {
 1652                                 tcp_respond(NULL, (void *)ip, tcp, *m,
 1653                                     (tcp_seq)0, tcp->th_ack, TH_RST);
 1654                         } else {
 1655                                 if (tcp->th_flags & TH_SYN)
 1656                                         tip->ti_len++;
 1657                                 tcp_respond(NULL, (void *)ip, tcp, *m, 
 1658                                     tip->ti_seq + tip->ti_len,
 1659                                     (tcp_seq)0, TH_RST|TH_ACK);
 1660                         }
 1661                         *m = NULL;
 1662                         break;
 1663                     }
 1664                 default:        /* Send an ICMP unreachable using code */
 1665                         icmp_error(*m, ICMP_UNREACH,
 1666                             f->fw_reject_code, 0L, 0);
 1667                         *m = NULL;
 1668                         break;
 1669                 }
 1670         }
 1671 
 1672 dropit:
 1673         /*
 1674          * Finally, drop the packet.
 1675          */
 1676         return(IP_FW_PORT_DENY_FLAG);
 1677 #undef BRIDGED
 1678 }
 1679 
 1680 /*
 1681  * when a rule is added/deleted, zero the direct pointers within
 1682  * all firewall rules. These will be reconstructed on the fly
 1683  * as packets are matched.
 1684  * Must be called at splimp().
 1685  */
 1686 static void
 1687 flush_rule_ptrs()
 1688 {
 1689     struct ip_fw *fcp ;
 1690 
 1691     LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
 1692         fcp->next_rule_ptr = NULL ;
 1693     }
 1694 }
 1695 
 1696 static int
 1697 add_entry(struct ip_fw_head *head, struct ip_fw *rule)
 1698 {
 1699         struct ip_fw *ftmp, *fcp, *fcpl;
 1700         u_short nbr = 0;
 1701         int s;
 1702 
 1703         ftmp = malloc(sizeof *ftmp, M_IPFW, M_NOWAIT | M_ZERO);
 1704         if (!ftmp)
 1705                 return (ENOSPC);
 1706         bcopy(rule, ftmp, sizeof(*ftmp));
 1707 
 1708         ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
 1709         ftmp->fw_pcnt = 0L;
 1710         ftmp->fw_bcnt = 0L;
 1711         ftmp->next_rule_ptr = NULL ;
 1712         ftmp->pipe_ptr = NULL ;
 1713         
 1714         s = splimp();
 1715 
 1716         if (LIST_FIRST(head) == 0) {
 1717                 LIST_INSERT_HEAD(head, ftmp, next);
 1718                 goto done;
 1719         }
 1720 
 1721         /* If entry number is 0, find highest numbered rule and add 100 */
 1722         if (ftmp->fw_number == 0) {
 1723                 LIST_FOREACH(fcp, head, next) {
 1724                         if (fcp->fw_number != IPFW_DEFAULT_RULE)
 1725                                 nbr = fcp->fw_number;
 1726                         else
 1727                                 break;
 1728                 }
 1729                 if (nbr < IPFW_DEFAULT_RULE - 100)
 1730                         nbr += 100;
 1731                 ftmp->fw_number = rule->fw_number = nbr;
 1732         }
 1733 
 1734         /* Got a valid number; now insert it, keeping the list ordered */
 1735         fcpl = NULL ;
 1736         LIST_FOREACH(fcp, head, next) {
 1737                 if (fcp->fw_number > ftmp->fw_number) {
 1738                         if (fcpl) {
 1739                                 LIST_INSERT_AFTER(fcpl, ftmp, next);
 1740                         } else {
 1741                                 LIST_INSERT_HEAD(head, ftmp, next);
 1742                         }
 1743                         break;
 1744                 } else {
 1745                         fcpl = fcp;
 1746                 }
 1747         }
 1748         flush_rule_ptrs();
 1749 done:
 1750         static_count++;
 1751         splx(s);
 1752         DEB(printf("++ installed rule %d, static count now %d\n",
 1753                 ftmp->fw_number, static_count);)
 1754         return (0);
 1755 }
 1756 
 1757 /**
 1758  * free storage associated with a static rule entry (including
 1759  * dependent dynamic rules), and zeroes rule pointers to avoid
 1760  * dangling pointer dereferences.
 1761  * @return a pointer to the next entry.
 1762  * Must be called at splimp() and with a non-null argument.
 1763  */
 1764 static struct ip_fw *
 1765 free_chain(struct ip_fw *fcp)
 1766 {
 1767     struct ip_fw *n;
 1768 
 1769     n = LIST_NEXT(fcp, next);
 1770     DELETE_DYN_CHAIN(fcp);
 1771     LIST_REMOVE(fcp, next);
 1772     static_count--;
 1773     if (DUMMYNET_LOADED)
 1774         ip_dn_ruledel_ptr(fcp) ;
 1775     flush_rule_ptrs(); /* more efficient to do outside the loop */
 1776     free(fcp, M_IPFW);
 1777     return n;
 1778 }
 1779 
 1780 /**
 1781  * remove all rules with given number.
 1782  */
 1783 static int
 1784 del_entry(struct ip_fw_head *chainptr, u_short number)
 1785 {
 1786     struct ip_fw *rule;
 1787 
 1788     if (number != IPFW_DEFAULT_RULE) {
 1789         LIST_FOREACH(rule, chainptr, next) {
 1790             if (rule->fw_number == number) {
 1791                 int s ;
 1792 
 1793                 s = splimp(); /* prevent access to rules while removing */
 1794                 while (rule && rule->fw_number == number)
 1795                     rule = free_chain(rule);
 1796                 /* XXX could move flush_rule_ptrs() here */
 1797                 splx(s);
 1798                 return 0 ;
 1799             }
 1800         }
 1801     }
 1802     return (EINVAL);
 1803 }
 1804 
 1805 /**
 1806  * Reset some or all counters on firewall rules.
 1807  * @arg frwl is null to clear all entries, or contains a specific
 1808  * rule number.
 1809  * @arg log_only is 1 if we only want to reset logs, zero otherwise.
 1810  */
 1811 
 1812 static int
 1813 zero_entry(struct ip_fw *frwl, int log_only)
 1814 {
 1815     struct ip_fw *rule;
 1816     int s;
 1817     u_short number = 0 ;
 1818     char *msg ;
 1819 
 1820     if (frwl == 0) {
 1821         s = splimp();
 1822         LIST_FOREACH(rule, &ip_fw_chain_head, next) {
 1823             if (log_only == 0) {
 1824                 rule->fw_bcnt = rule->fw_pcnt = 0;
 1825                 rule->timestamp = 0;
 1826             }
 1827             rule->fw_loghighest = rule->fw_pcnt+rule->fw_logamount;
 1828         }
 1829         splx(s);
 1830         msg = log_only ? "ipfw: All logging counts cleared.\n" :
 1831                         "ipfw: Accounting cleared.\n";
 1832     } else {
 1833         int cleared = 0;
 1834         number = frwl->fw_number ;
 1835         /*
 1836          * It is possible to insert multiple chain entries with the
 1837          * same number, so we don't stop after finding the first
 1838          * match if zeroing a specific entry.
 1839          */
 1840         LIST_FOREACH(rule, &ip_fw_chain_head, next)
 1841             if (number == rule->fw_number) {
 1842                 s = splimp();
 1843                 while (rule && number == rule->fw_number) {
 1844                     if (log_only == 0) {
 1845                         rule->fw_bcnt = rule->fw_pcnt = 0;
 1846                         rule->timestamp = 0;
 1847                     }
 1848                     rule->fw_loghighest = rule->fw_pcnt+ rule->fw_logamount;
 1849                     rule = LIST_NEXT(rule, next);
 1850                 }
 1851                 splx(s);
 1852                 cleared = 1;
 1853                 break;
 1854             }
 1855         if (!cleared)   /* we did not find any matching rules */
 1856             return (EINVAL);
 1857         msg = log_only ? "ipfw: Entry %d logging count reset.\n" :
 1858                         "ipfw: Entry %d cleared.\n";
 1859     }
 1860     if (fw_verbose)
 1861         log(LOG_SECURITY | LOG_NOTICE, msg, number);
 1862     return (0);
 1863 }
 1864 
 1865 static int
 1866 check_ipfw_struct(struct ip_fw *frwl)
 1867 {
 1868         /* Check for invalid flag bits */
 1869         if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) {
 1870                 dprintf(("%s undefined flag bits set (flags=%x)\n",
 1871                     err_prefix, frwl->fw_flg));
 1872                 return (EINVAL);
 1873         }
 1874         if ( (frwl->fw_flg & IP_FW_F_MAC) ) {   /* match MAC address */
 1875                 return 0;
 1876         }
 1877         if (frwl->fw_flg == IP_FW_F_CHECK_S) {
 1878                 /* check-state */
 1879                 return 0 ;
 1880         }
 1881         /* Must apply to incoming or outgoing (or both) */
 1882         if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) {
 1883                 dprintf(("%s neither in nor out\n", err_prefix));
 1884                 return (EINVAL);
 1885         }
 1886         /* Empty interface name is no good */
 1887         if (((frwl->fw_flg & IP_FW_F_IIFNAME)
 1888               && !*frwl->fw_in_if.fu_via_if.name)
 1889             || ((frwl->fw_flg & IP_FW_F_OIFNAME)
 1890               && !*frwl->fw_out_if.fu_via_if.name)) {
 1891                 dprintf(("%s empty interface name\n", err_prefix));
 1892                 return (EINVAL);
 1893         }
 1894         /* Sanity check interface matching */
 1895         if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
 1896                 ;               /* allow "via" backwards compatibility */
 1897         } else if ((frwl->fw_flg & IP_FW_F_IN)
 1898             && (frwl->fw_flg & IP_FW_F_OIFACE)) {
 1899                 dprintf(("%s outgoing interface check on incoming\n",
 1900                     err_prefix));
 1901                 return (EINVAL);
 1902         }
 1903         /* Sanity check port ranges */
 1904         if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) {
 1905                 dprintf(("%s src range set but n_src_p=%d\n",
 1906                     err_prefix, IP_FW_GETNSRCP(frwl)));
 1907                 return (EINVAL);
 1908         }
 1909         if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) {
 1910                 dprintf(("%s dst range set but n_dst_p=%d\n",
 1911                     err_prefix, IP_FW_GETNDSTP(frwl)));
 1912                 return (EINVAL);
 1913         }
 1914         if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) {
 1915                 dprintf(("%s too many ports (%d+%d)\n",
 1916                     err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl)));
 1917                 return (EINVAL);
 1918         }
 1919         /*
 1920          *      Protocols other than TCP/UDP don't use port range
 1921          */
 1922         if ((frwl->fw_prot != IPPROTO_TCP) &&
 1923             (frwl->fw_prot != IPPROTO_UDP) &&
 1924             (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) {
 1925                 dprintf(("%s port(s) specified for non TCP/UDP rule\n",
 1926                     err_prefix));
 1927                 return (EINVAL);
 1928         }
 1929 
 1930         /*
 1931          *      Rather than modify the entry to make such entries work, 
 1932          *      we reject this rule and require user level utilities
 1933          *      to enforce whatever policy they deem appropriate.
 1934          */
 1935         if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || 
 1936                 (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
 1937                 dprintf(("%s rule never matches\n", err_prefix));
 1938                 return (EINVAL);
 1939         }
 1940 
 1941         if ((frwl->fw_flg & IP_FW_F_FRAG) &&
 1942                 (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
 1943                 if (IP_FW_HAVEPORTS(frwl)) {
 1944                         dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
 1945                         return (EINVAL);
 1946                 }
 1947                 if (frwl->fw_prot == IPPROTO_TCP &&
 1948                         frwl->fw_tcpf != frwl->fw_tcpnf) {
 1949                         dprintf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
 1950                         return (EINVAL);
 1951                 }
 1952         }
 1953 
 1954         if (frwl->fw_flg & (IP_FW_F_UID | IP_FW_F_GID)) {
 1955                 if ((frwl->fw_prot != IPPROTO_TCP) &&
 1956                    (frwl->fw_prot != IPPROTO_UDP) &&
 1957                    (frwl->fw_prot != IPPROTO_IP)) {
 1958                         dprintf(("%s cannot use uid/gid logic on non-TCP/UDP\n", err_prefix));
 1959                         return (EINVAL);
 1960                 }
 1961         }
 1962 
 1963         /* Check command specific stuff */
 1964         switch (frwl->fw_flg & IP_FW_F_COMMAND) {
 1965         case IP_FW_F_REJECT:
 1966                 if (frwl->fw_reject_code >= 0x100
 1967                     && !(frwl->fw_prot == IPPROTO_TCP
 1968                       && frwl->fw_reject_code == IP_FW_REJECT_RST)) {
 1969                         dprintf(("%s unknown reject code\n", err_prefix));
 1970                         return (EINVAL);
 1971                 }
 1972                 break;
 1973 #ifdef IPDIVERT
 1974         case IP_FW_F_DIVERT:            /* Diverting to port zero is invalid */
 1975         case IP_FW_F_TEE:
 1976 #endif
 1977         case IP_FW_F_PIPE:              /* pipe 0 is invalid */
 1978         case IP_FW_F_QUEUE:             /* queue 0 is invalid */
 1979                 if (frwl->fw_divert_port == 0) {
 1980                         dprintf(("%s 0 is an invalid argument\n", err_prefix));
 1981                         return (EINVAL);
 1982                 }
 1983                 break;
 1984         case IP_FW_F_DENY:
 1985         case IP_FW_F_ACCEPT:
 1986         case IP_FW_F_COUNT:
 1987         case IP_FW_F_SKIPTO:
 1988         case IP_FW_F_FWD:
 1989                 break;
 1990         default:
 1991                 dprintf(("%s invalid command\n", err_prefix));
 1992                 return (EINVAL);
 1993         }
 1994 
 1995         return 0;
 1996 }
 1997 
 1998 static int
 1999 ip_fw_ctl(struct sockopt *sopt)
 2000 {
 2001         int error, s;
 2002         size_t size;
 2003         struct ip_fw *fcp;
 2004         struct ip_fw frwl, *bp , *buf;
 2005 
 2006         /*
 2007          * Disallow modifications in really-really secure mode, but still allow
 2008          * the logging counters to be reset.
 2009          */
 2010         if (sopt->sopt_name == IP_FW_ADD ||
 2011             (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) {
 2012                 error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
 2013                 if (error)
 2014                         return (error);
 2015         }
 2016 
 2017         error = 0;
 2018 
 2019         switch (sopt->sopt_name) {
 2020         case IP_FW_GET:
 2021                 /*
 2022                  * pass up a copy of the current rules. Static rules
 2023                  * come first (the last of which has number 65535),
 2024                  * followed by a possibly empty list of dynamic rule.
 2025                  * The last dynamic rule has NULL in the "next" field.
 2026                  */
 2027                 s = splimp();
 2028                 /* size of static rules */
 2029                 size = static_count * sizeof(struct ip_fw) ;
 2030                 if (ipfw_dyn_v)         /* add size of dyn.rules */
 2031                     size += (dyn_count * sizeof(struct ipfw_dyn_rule));
 2032 
 2033                 /*
 2034                  * XXX todo: if the user passes a short length to know how
 2035                  * much room is needed, do not
 2036                  * bother filling up the buffer, just jump to the
 2037                  * sooptcopyout.
 2038                  */
 2039                 buf = malloc(size, M_TEMP, M_WAITOK);
 2040                 if (buf == 0) {
 2041                     splx(s);
 2042                     error = ENOBUFS;
 2043                     break;
 2044                 }
 2045 
 2046                 bp = buf ;
 2047                 LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
 2048                     bcopy(fcp, bp, sizeof *fcp);
 2049                     bp++;
 2050                 }
 2051                 if (ipfw_dyn_v) {
 2052                     int i ;
 2053                     struct ipfw_dyn_rule *p, *dst, *last = NULL ;
 2054 
 2055                     dst = (struct ipfw_dyn_rule *)bp ;
 2056                     for (i = 0 ; i < curr_dyn_buckets ; i++ )
 2057                         for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next, dst++ ) {
 2058                             bcopy(p, dst, sizeof *p);
 2059                             (int)dst->rule = p->rule->fw_number ;
 2060                             /*
 2061                              * store a non-null value in "next". The userland
 2062                              * code will interpret a NULL here as a marker
 2063                              * for the last dynamic rule.
 2064                              */
 2065                             dst->next = dst ;
 2066                             last = dst ;
 2067                             if (TIME_LEQ(dst->expire, time_second) )
 2068                                 dst->expire = 0 ;
 2069                             else
 2070                                 dst->expire -= time_second ;
 2071                             }
 2072                     if (last != NULL)
 2073                         last->next = NULL ;     /* mark last dynamic rule */
 2074                 }
 2075                 splx(s);
 2076 
 2077                 error = sooptcopyout(sopt, buf, size);
 2078                 free(buf, M_TEMP);
 2079                 break;
 2080 
 2081         case IP_FW_FLUSH:
 2082                 /*
 2083                  * Normally we cannot release the lock on each iteration.
 2084                  * We could do it here only because we start from the head all
 2085                  * the times so there is no risk of missing some entries.
 2086                  * On the other hand, the risk is that we end up with
 2087                  * a very inconsistent ruleset, so better keep the lock
 2088                  * around the whole cycle.
 2089                  * 
 2090                  * XXX this code can be improved by resetting the head of
 2091                  * the list to point to the default rule, and then freeing
 2092                  * the old list without the need for a lock.
 2093                  */
 2094 
 2095                 s = splimp();
 2096                 while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) &&
 2097                         fcp->fw_number != IPFW_DEFAULT_RULE )
 2098                     free_chain(fcp);
 2099                 splx(s);
 2100                 break;
 2101 
 2102         case IP_FW_ADD:
 2103                 error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
 2104                 if (error || (error = check_ipfw_struct(&frwl)))
 2105                         break;
 2106 
 2107                 if (frwl.fw_number == IPFW_DEFAULT_RULE) {
 2108                         dprintf(("%s can't add rule %u\n", err_prefix,
 2109                                  (unsigned)IPFW_DEFAULT_RULE));
 2110                         error = EINVAL;
 2111                 } else {
 2112                         error = add_entry(&ip_fw_chain_head, &frwl);
 2113                         if (!error && sopt->sopt_dir == SOPT_GET)
 2114                                 error = sooptcopyout(sopt, &frwl, sizeof frwl);
 2115                 }
 2116                 break;
 2117 
 2118         case IP_FW_DEL:
 2119                 error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
 2120                 if (error)
 2121                         break;
 2122 
 2123                 if (frwl.fw_number == IPFW_DEFAULT_RULE) {
 2124                         dprintf(("%s can't delete rule %u\n", err_prefix,
 2125                                  (unsigned)IPFW_DEFAULT_RULE));
 2126                         error = EINVAL;
 2127                 } else {
 2128                         error = del_entry(&ip_fw_chain_head, frwl.fw_number);
 2129                 }
 2130                 break;
 2131 
 2132         case IP_FW_ZERO:
 2133         case IP_FW_RESETLOG:
 2134             {
 2135                 int cmd = (sopt->sopt_name == IP_FW_RESETLOG );
 2136                 void *arg = NULL ;
 2137 
 2138                 if (sopt->sopt_val != 0) {
 2139                     error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
 2140                     if (error)
 2141                         break;
 2142                     arg = &frwl ;
 2143                 }
 2144                 error = zero_entry(arg, cmd);
 2145             }
 2146             break;
 2147 
 2148         default:
 2149                 printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name);
 2150                 error = EINVAL ;
 2151         }
 2152 
 2153         return (error);
 2154 }
 2155 
 2156 /**
 2157  * dummynet needs a reference to the default rule, because rules can
 2158  * be deleted while packets hold a reference to them (e.g. to resume
 2159  * processing at the next rule). When this happens, dummynet changes
 2160  * the reference to the default rule (probably it could well be a
 2161  * NULL pointer, but this way we do not need to check for the special
 2162  * case, plus here he have info on the default behaviour.
 2163  */
 2164 struct ip_fw *ip_fw_default_rule ;
 2165 
 2166 void
 2167 ip_fw_init(void)
 2168 {
 2169         struct ip_fw default_rule;
 2170 
 2171         ip_fw_chk_ptr = ip_fw_chk;
 2172         ip_fw_ctl_ptr = ip_fw_ctl;
 2173         LIST_INIT(&ip_fw_chain_head);
 2174 
 2175         bzero(&default_rule, sizeof default_rule);
 2176         default_rule.fw_prot = IPPROTO_IP;
 2177         default_rule.fw_number = IPFW_DEFAULT_RULE;
 2178 #ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
 2179         default_rule.fw_flg |= IP_FW_F_ACCEPT;
 2180 #else
 2181         default_rule.fw_flg |= IP_FW_F_DENY;
 2182 #endif
 2183         default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT;
 2184         if (check_ipfw_struct(&default_rule) != 0 ||
 2185             add_entry(&ip_fw_chain_head, &default_rule))
 2186                 panic("ip_fw_init");
 2187 
 2188         ip_fw_default_rule = LIST_FIRST(&ip_fw_chain_head) ;
 2189         printf("IP packet filtering initialized, "
 2190 #ifdef IPDIVERT
 2191                 "divert enabled, "
 2192 #else
 2193                 "divert disabled, "
 2194 #endif
 2195                 "rule-based forwarding enabled, "
 2196 #ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
 2197                 "default to accept, ");
 2198 #else
 2199                 "default to deny, " );
 2200 #endif
 2201 #ifndef IPFIREWALL_VERBOSE
 2202         printf("logging disabled\n");
 2203 #else
 2204         if (fw_verbose_limit == 0)
 2205                 printf("unlimited logging\n");
 2206         else
 2207                 printf("logging limited to %d packets/entry by default\n",
 2208                     fw_verbose_limit);
 2209 #endif
 2210 }
 2211 
 2212 static int
 2213 ipfw_modevent(module_t mod, int type, void *unused)
 2214 {
 2215         int s;
 2216         int err = 0 ;
 2217 #if defined(KLD_MODULE)
 2218         struct ip_fw *fcp;
 2219 #endif
 2220         
 2221         switch (type) {
 2222         case MOD_LOAD:
 2223                 s = splimp();
 2224                 if (IPFW_LOADED) {
 2225                         splx(s);
 2226                         printf("IP firewall already loaded\n");
 2227                         err = EEXIST ;
 2228                 } else {
 2229                         ip_fw_init();
 2230                         splx(s);
 2231                 }
 2232                 break ;
 2233         case MOD_UNLOAD:
 2234 #if !defined(KLD_MODULE)
 2235                 printf("ipfw statically compiled, cannot unload\n");
 2236                 err = EBUSY;
 2237 #else
 2238                 s = splimp();
 2239                 ip_fw_chk_ptr = NULL ;
 2240                 ip_fw_ctl_ptr = NULL ;
 2241                 while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) != NULL)
 2242                     free_chain(fcp);
 2243                 splx(s);
 2244                 printf("IP firewall unloaded\n");
 2245 #endif
 2246                 break;
 2247         default:
 2248                 break;
 2249         }
 2250         return err;
 2251 }
 2252 
 2253 static moduledata_t ipfwmod = {
 2254         "ipfw",
 2255         ipfw_modevent,
 2256         0
 2257 };
 2258 DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
 2259 MODULE_VERSION(ipfw, 1);

Cache object: a5f7cf9ec4f1a6fd297f9bf18b9eab9f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.