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/netpfil/ipfw/ip_fw_pfil.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include "opt_ipfw.h"
   33 #include "opt_inet.h"
   34 #include "opt_inet6.h"
   35 #ifndef INET
   36 #error IPFIREWALL requires INET.
   37 #endif /* INET */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mbuf.h>
   43 #include <sys/module.h>
   44 #include <sys/kernel.h>
   45 #include <sys/lock.h>
   46 #include <sys/rwlock.h>
   47 #include <sys/socket.h>
   48 #include <sys/sysctl.h>
   49 
   50 #include <net/if.h>
   51 #include <net/if_var.h>
   52 #include <net/route.h>
   53 #include <net/ethernet.h>
   54 #include <net/pfil.h>
   55 #include <net/vnet.h>
   56 
   57 #include <netinet/in.h>
   58 #include <netinet/in_systm.h>
   59 #include <netinet/ip.h>
   60 #include <netinet/ip_var.h>
   61 #include <netinet/ip_fw.h>
   62 #ifdef INET6
   63 #include <netinet/ip6.h>
   64 #include <netinet6/ip6_var.h>
   65 #include <netinet6/scope6_var.h>
   66 #endif
   67 
   68 #include <netgraph/ng_ipfw.h>
   69 
   70 #include <netpfil/ipfw/ip_fw_private.h>
   71 
   72 #include <machine/in_cksum.h>
   73 
   74 VNET_DEFINE_STATIC(int, fw_enable) = 1;
   75 #define V_fw_enable     VNET(fw_enable)
   76 
   77 #ifdef INET6
   78 VNET_DEFINE_STATIC(int, fw6_enable) = 1;
   79 #define V_fw6_enable    VNET(fw6_enable)
   80 #endif
   81 
   82 VNET_DEFINE_STATIC(int, fwlink_enable) = 0;
   83 #define V_fwlink_enable VNET(fwlink_enable)
   84 
   85 int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
   86 
   87 /* Forward declarations. */
   88 static int ipfw_divert(struct mbuf **, struct ip_fw_args *, bool);
   89 
   90 #ifdef SYSCTL_NODE
   91 
   92 SYSBEGIN(f1)
   93 
   94 SYSCTL_DECL(_net_inet_ip_fw);
   95 SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, enable,
   96     CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3 |
   97     CTLFLAG_NEEDGIANT, &VNET_NAME(fw_enable), 0, ipfw_chg_hook, "I",
   98     "Enable ipfw");
   99 #ifdef INET6
  100 SYSCTL_DECL(_net_inet6_ip6_fw);
  101 SYSCTL_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
  102     CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3 |
  103     CTLFLAG_NEEDGIANT, &VNET_NAME(fw6_enable), 0, ipfw_chg_hook, "I",
  104     "Enable ipfw+6");
  105 #endif /* INET6 */
  106 
  107 SYSCTL_DECL(_net_link_ether);
  108 SYSCTL_PROC(_net_link_ether, OID_AUTO, ipfw,
  109     CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3 |
  110     CTLFLAG_NEEDGIANT, &VNET_NAME(fwlink_enable), 0, ipfw_chg_hook, "I",
  111     "Pass ether pkts through firewall");
  112 
  113 SYSEND
  114 
  115 #endif /* SYSCTL_NODE */
  116 
  117 /*
  118  * The pfilter hook to pass packets to ipfw_chk and then to
  119  * dummynet, divert, netgraph or other modules.
  120  * The packet may be consumed.
  121  */
  122 static pfil_return_t
  123 ipfw_check_packet(struct mbuf **m0, struct ifnet *ifp, int flags,
  124     void *ruleset __unused, struct inpcb *inp)
  125 {
  126         struct ip_fw_args args;
  127         struct m_tag *tag;
  128         pfil_return_t ret;
  129         int ipfw;
  130 
  131         args.flags = (flags & PFIL_IN) ? IPFW_ARGS_IN : IPFW_ARGS_OUT;
  132 again:
  133         /*
  134          * extract and remove the tag if present. If we are left
  135          * with onepass, optimize the outgoing path.
  136          */
  137         tag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
  138         if (tag != NULL) {
  139                 args.rule = *((struct ipfw_rule_ref *)(tag+1));
  140                 m_tag_delete(*m0, tag);
  141                 if (args.rule.info & IPFW_ONEPASS)
  142                         return (PFIL_PASS);
  143                 args.flags |= IPFW_ARGS_REF;
  144         }
  145 
  146         args.m = *m0;
  147         args.ifp = ifp;
  148         args.inp = inp;
  149 
  150         ipfw = ipfw_chk(&args);
  151         *m0 = args.m;
  152 
  153         KASSERT(*m0 != NULL || ipfw == IP_FW_DENY ||
  154             ipfw == IP_FW_NAT64, ("%s: m0 is NULL", __func__));
  155 
  156         ret = PFIL_PASS;
  157         switch (ipfw) {
  158         case IP_FW_PASS:
  159                 /* next_hop may be set by ipfw_chk */
  160                 if ((args.flags & (IPFW_ARGS_NH4 | IPFW_ARGS_NH4PTR |
  161                     IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) == 0)
  162                         break;
  163 #if (!defined(INET6) && !defined(INET))
  164                 ret = PFIL_DROPPED;
  165 #else
  166             {
  167                 void *psa;
  168                 size_t len;
  169 #ifdef INET
  170                 if (args.flags & (IPFW_ARGS_NH4 | IPFW_ARGS_NH4PTR)) {
  171                         MPASS((args.flags & (IPFW_ARGS_NH4 |
  172                             IPFW_ARGS_NH4PTR)) != (IPFW_ARGS_NH4 |
  173                             IPFW_ARGS_NH4PTR));
  174                         MPASS((args.flags & (IPFW_ARGS_NH6 |
  175                             IPFW_ARGS_NH6PTR)) == 0);
  176                         len = sizeof(struct sockaddr_in);
  177                         psa = (args.flags & IPFW_ARGS_NH4) ?
  178                             &args.hopstore : args.next_hop;
  179                         if (in_localip(satosin(psa)->sin_addr))
  180                                 (*m0)->m_flags |= M_FASTFWD_OURS;
  181                         (*m0)->m_flags |= M_IP_NEXTHOP;
  182                 }
  183 #endif /* INET */
  184 #ifdef INET6
  185                 if (args.flags & (IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) {
  186                         MPASS((args.flags & (IPFW_ARGS_NH6 |
  187                             IPFW_ARGS_NH6PTR)) != (IPFW_ARGS_NH6 |
  188                             IPFW_ARGS_NH6PTR));
  189                         MPASS((args.flags & (IPFW_ARGS_NH4 |
  190                             IPFW_ARGS_NH4PTR)) == 0);
  191                         len = sizeof(struct sockaddr_in6);
  192                         psa = args.next_hop6;
  193                         (*m0)->m_flags |= M_IP6_NEXTHOP;
  194                 }
  195 #endif /* INET6 */
  196                 /*
  197                  * Incoming packets should not be tagged so we do not
  198                  * m_tag_find. Outgoing packets may be tagged, so we
  199                  * reuse the tag if present.
  200                  */
  201                 tag = (flags & PFIL_IN) ? NULL :
  202                         m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
  203                 if (tag != NULL) {
  204                         m_tag_unlink(*m0, tag);
  205                 } else {
  206                         tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
  207                             M_NOWAIT);
  208                         if (tag == NULL) {
  209                                 ret = PFIL_DROPPED;
  210                                 break;
  211                         }
  212                 }
  213                 if ((args.flags & IPFW_ARGS_NH6) == 0)
  214                         bcopy(psa, tag + 1, len);
  215                 m_tag_prepend(*m0, tag);
  216                 ret = PFIL_PASS;
  217 #ifdef INET6
  218                 /* IPv6 next hop needs additional handling */
  219                 if (args.flags & (IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) {
  220                         struct sockaddr_in6 *sa6;
  221 
  222                         sa6 = satosin6(tag + 1);
  223                         if (args.flags & IPFW_ARGS_NH6) {
  224                                 sa6->sin6_family = AF_INET6;
  225                                 sa6->sin6_len = sizeof(*sa6);
  226                                 sa6->sin6_addr = args.hopstore6.sin6_addr;
  227                                 sa6->sin6_port = args.hopstore6.sin6_port;
  228                                 sa6->sin6_scope_id =
  229                                     args.hopstore6.sin6_scope_id;
  230                         }
  231                         /*
  232                          * If nh6 address is link-local we should convert
  233                          * it to kernel internal form before doing any
  234                          * comparisons.
  235                          */
  236                         if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) {
  237                                 ret = PFIL_DROPPED;
  238                                 break;
  239                         }
  240                         if (in6_localip(&sa6->sin6_addr))
  241                                 (*m0)->m_flags |= M_FASTFWD_OURS;
  242                 }
  243 #endif /* INET6 */
  244             }
  245 #endif /* INET || INET6 */
  246                 break;
  247 
  248         case IP_FW_DENY:
  249                 ret = PFIL_DROPPED;
  250                 break;
  251 
  252         case IP_FW_DUMMYNET:
  253                 if (ip_dn_io_ptr == NULL) {
  254                         ret = PFIL_DROPPED;
  255                         break;
  256                 }
  257                 MPASS(args.flags & IPFW_ARGS_REF);
  258                 if (args.flags & (IPFW_ARGS_IP4 | IPFW_ARGS_IP6))
  259                         (void )ip_dn_io_ptr(m0, &args);
  260                 else {
  261                         ret = PFIL_DROPPED;
  262                         break;
  263                 }
  264                 /*
  265                  * XXX should read the return value.
  266                  * dummynet normally eats the packet and sets *m0=NULL
  267                  * unless the packet can be sent immediately. In this
  268                  * case args is updated and we should re-run the
  269                  * check without clearing args.
  270                  */
  271                 if (*m0 != NULL)
  272                         goto again;
  273                 ret = PFIL_CONSUMED;
  274                 break;
  275 
  276         case IP_FW_TEE:
  277         case IP_FW_DIVERT:
  278                 if (ip_divert_ptr == NULL) {
  279                         ret = PFIL_DROPPED;
  280                         break;
  281                 }
  282                 MPASS(args.flags & IPFW_ARGS_REF);
  283                 (void )ipfw_divert(m0, &args, ipfw == IP_FW_TEE);
  284                 /* continue processing for the original packet (tee). */
  285                 if (*m0)
  286                         goto again;
  287                 ret = PFIL_CONSUMED;
  288                 break;
  289 
  290         case IP_FW_NGTEE:
  291         case IP_FW_NETGRAPH:
  292                 if (ng_ipfw_input_p == NULL) {
  293                         ret = PFIL_DROPPED;
  294                         break;
  295                 }
  296                 MPASS(args.flags & IPFW_ARGS_REF);
  297                 (void )ng_ipfw_input_p(m0, &args, ipfw == IP_FW_NGTEE);
  298                 if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
  299                         goto again;     /* continue with packet */
  300                 ret = PFIL_CONSUMED;
  301                 break;
  302 
  303         case IP_FW_NAT:
  304                 /* honor one-pass in case of successful nat */
  305                 if (V_fw_one_pass)
  306                         break;
  307                 goto again;
  308 
  309         case IP_FW_REASS:
  310                 goto again;             /* continue with packet */
  311 
  312         case IP_FW_NAT64:
  313                 ret = PFIL_CONSUMED;
  314                 break;
  315 
  316         default:
  317                 KASSERT(0, ("%s: unknown retval", __func__));
  318         }
  319 
  320         if (ret != PFIL_PASS) {
  321                 if (*m0)
  322                         FREE_PKT(*m0);
  323                 *m0 = NULL;
  324         }
  325 
  326         return (ret);
  327 }
  328 
  329 /*
  330  * ipfw processing for ethernet packets (in and out).
  331  */
  332 static pfil_return_t
  333 ipfw_check_frame(pfil_packet_t p, struct ifnet *ifp, int flags,
  334     void *ruleset __unused, struct inpcb *inp)
  335 {
  336         struct ip_fw_args args;
  337         pfil_return_t ret;
  338         bool mem, realloc;
  339         int ipfw;
  340 
  341         if (flags & PFIL_MEMPTR) {
  342                 mem = true;
  343                 realloc = false;
  344                 args.flags = PFIL_LENGTH(flags) | IPFW_ARGS_ETHER;
  345                 args.mem = p.mem;
  346         } else {
  347                 mem = realloc = false;
  348                 args.flags = IPFW_ARGS_ETHER;
  349         }
  350         args.flags |= (flags & PFIL_IN) ? IPFW_ARGS_IN : IPFW_ARGS_OUT;
  351         args.ifp = ifp;
  352         args.inp = inp;
  353 
  354 again:
  355         if (!mem) {
  356                 /*
  357                  * Fetch start point from rule, if any.
  358                  * Remove the tag if present.
  359                  */
  360                 struct m_tag *mtag;
  361 
  362                 mtag = m_tag_locate(*p.m, MTAG_IPFW_RULE, 0, NULL);
  363                 if (mtag != NULL) {
  364                         args.rule = *((struct ipfw_rule_ref *)(mtag+1));
  365                         m_tag_delete(*p.m, mtag);
  366                         if (args.rule.info & IPFW_ONEPASS)
  367                                 return (PFIL_PASS);
  368                         args.flags |= IPFW_ARGS_REF;
  369                 }
  370                 args.m = *p.m;
  371         }
  372 
  373         ipfw = ipfw_chk(&args);
  374         if (!mem)
  375                 *p.m = args.m;
  376 
  377         ret = PFIL_PASS;
  378         switch (ipfw) {
  379         case IP_FW_PASS:
  380                 break;
  381 
  382         case IP_FW_DENY:
  383                 ret = PFIL_DROPPED;
  384                 break;
  385 
  386         case IP_FW_DUMMYNET:
  387                 if (ip_dn_io_ptr == NULL) {
  388                         ret = PFIL_DROPPED;
  389                         break;
  390                 }
  391                 if (mem) {
  392                         if (pfil_realloc(&p, flags, ifp) != 0) {
  393                                 ret = PFIL_DROPPED;
  394                                 break;
  395                         }
  396                         mem = false;
  397                         realloc = true;
  398                 }
  399                 MPASS(args.flags & IPFW_ARGS_REF);
  400                 ip_dn_io_ptr(p.m, &args);
  401                 return (PFIL_CONSUMED);
  402 
  403         case IP_FW_NGTEE:
  404         case IP_FW_NETGRAPH:
  405                 if (ng_ipfw_input_p == NULL) {
  406                         ret = PFIL_DROPPED;
  407                         break;
  408                 }
  409                 if (mem) {
  410                         if (pfil_realloc(&p, flags, ifp) != 0) {
  411                                 ret = PFIL_DROPPED;
  412                                 break;
  413                         }
  414                         mem = false;
  415                         realloc = true;
  416                 }
  417                 MPASS(args.flags & IPFW_ARGS_REF);
  418                 (void )ng_ipfw_input_p(p.m, &args, ipfw == IP_FW_NGTEE);
  419                 if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
  420                         goto again;     /* continue with packet */
  421                 ret = PFIL_CONSUMED;
  422                 break;
  423 
  424         default:
  425                 KASSERT(0, ("%s: unknown retval", __func__));
  426         }
  427 
  428         if (!mem && ret != PFIL_PASS) {
  429                 if (*p.m)
  430                         FREE_PKT(*p.m);
  431                 *p.m = NULL;
  432         }
  433 
  434         if (realloc && ret == PFIL_PASS)
  435                 ret = PFIL_REALLOCED;
  436 
  437         return (ret);
  438 }
  439 
  440 /* do the divert, return 1 on error 0 on success */
  441 static int
  442 ipfw_divert(struct mbuf **m0, struct ip_fw_args *args, bool tee)
  443 {
  444         /*
  445          * ipfw_chk() has already tagged the packet with the divert tag.
  446          * If tee is set, copy packet and return original.
  447          * If not tee, consume packet and send it to divert socket.
  448          */
  449         struct mbuf *clone;
  450         struct ip *ip = mtod(*m0, struct ip *);
  451         struct m_tag *tag;
  452 
  453         /* Cloning needed for tee? */
  454         if (tee == false) {
  455                 clone = *m0;    /* use the original mbuf */
  456                 *m0 = NULL;
  457         } else {
  458                 clone = m_dup(*m0, M_NOWAIT);
  459                 /* If we cannot duplicate the mbuf, we sacrifice the divert
  460                  * chain and continue with the tee-ed packet.
  461                  */
  462                 if (clone == NULL)
  463                         return 1;
  464         }
  465 
  466         /*
  467          * Divert listeners can normally handle non-fragmented packets,
  468          * but we can only reass in the non-tee case.
  469          * This means that listeners on a tee rule may get fragments,
  470          * and have to live with that.
  471          * Note that we now have the 'reass' ipfw option so if we care
  472          * we can do it before a 'tee'.
  473          */
  474         if (tee == false) switch (ip->ip_v) {
  475         case IPVERSION:
  476             if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {
  477                 int hlen;
  478                 struct mbuf *reass;
  479 
  480                 reass = ip_reass(clone); /* Reassemble packet. */
  481                 if (reass == NULL)
  482                         return 0; /* not an error */
  483                 /* if reass = NULL then it was consumed by ip_reass */
  484                 /*
  485                  * IP header checksum fixup after reassembly and leave header
  486                  * in network byte order.
  487                  */
  488                 ip = mtod(reass, struct ip *);
  489                 hlen = ip->ip_hl << 2;
  490                 ip->ip_sum = 0;
  491                 if (hlen == sizeof(struct ip))
  492                         ip->ip_sum = in_cksum_hdr(ip);
  493                 else
  494                         ip->ip_sum = in_cksum(reass, hlen);
  495                 clone = reass;
  496             }
  497             break;
  498 #ifdef INET6
  499         case IPV6_VERSION >> 4:
  500             {
  501             struct ip6_hdr *const ip6 = mtod(clone, struct ip6_hdr *);
  502 
  503                 if (ip6->ip6_nxt == IPPROTO_FRAGMENT) {
  504                         int nxt, off;
  505 
  506                         off = sizeof(struct ip6_hdr);
  507                         nxt = frag6_input(&clone, &off, 0);
  508                         if (nxt == IPPROTO_DONE)
  509                                 return (0);
  510                 }
  511                 break;
  512             }
  513 #endif
  514         }
  515 
  516         /* attach a tag to the packet with the reinject info */
  517         tag = m_tag_alloc(MTAG_IPFW_RULE, 0,
  518                     sizeof(struct ipfw_rule_ref), M_NOWAIT);
  519         if (tag == NULL) {
  520                 FREE_PKT(clone);
  521                 return 1;
  522         }
  523         *((struct ipfw_rule_ref *)(tag+1)) = args->rule;
  524         m_tag_prepend(clone, tag);
  525 
  526         /* Do the dirty job... */
  527         ip_divert_ptr(clone, args->flags & IPFW_ARGS_IN);
  528         return 0;
  529 }
  530 
  531 /*
  532  * attach or detach hooks for a given protocol family
  533  */
  534 VNET_DEFINE_STATIC(pfil_hook_t, ipfw_inet_hook);
  535 #define V_ipfw_inet_hook        VNET(ipfw_inet_hook)
  536 #ifdef INET6
  537 VNET_DEFINE_STATIC(pfil_hook_t, ipfw_inet6_hook);
  538 #define V_ipfw_inet6_hook       VNET(ipfw_inet6_hook)
  539 #endif
  540 VNET_DEFINE_STATIC(pfil_hook_t, ipfw_link_hook);
  541 #define V_ipfw_link_hook        VNET(ipfw_link_hook)
  542 
  543 static void
  544 ipfw_hook(int pf)
  545 {
  546         struct pfil_hook_args pha;
  547         pfil_hook_t *h;
  548 
  549         pha.pa_version = PFIL_VERSION;
  550         pha.pa_flags = PFIL_IN | PFIL_OUT;
  551         pha.pa_modname = "ipfw";
  552         pha.pa_ruleset = NULL;
  553 
  554         switch (pf) {
  555         case AF_INET:
  556                 pha.pa_func = ipfw_check_packet;
  557                 pha.pa_type = PFIL_TYPE_IP4;
  558                 pha.pa_rulname = "default";
  559                 h = &V_ipfw_inet_hook;
  560                 break;
  561 #ifdef INET6
  562         case AF_INET6:
  563                 pha.pa_func = ipfw_check_packet;
  564                 pha.pa_type = PFIL_TYPE_IP6;
  565                 pha.pa_rulname = "default6";
  566                 h = &V_ipfw_inet6_hook;
  567                 break;
  568 #endif
  569         case AF_LINK:
  570                 pha.pa_func = ipfw_check_frame;
  571                 pha.pa_type = PFIL_TYPE_ETHERNET;
  572                 pha.pa_rulname = "default-link";
  573                 pha.pa_flags |= PFIL_MEMPTR;
  574                 h = &V_ipfw_link_hook;
  575                 break;
  576         }
  577 
  578         *h = pfil_add_hook(&pha);
  579 }
  580 
  581 static void
  582 ipfw_unhook(int pf)
  583 {
  584 
  585         switch (pf) {
  586         case AF_INET:
  587                 pfil_remove_hook(V_ipfw_inet_hook);
  588                 break;
  589 #ifdef INET6
  590         case AF_INET6:
  591                 pfil_remove_hook(V_ipfw_inet6_hook);
  592                 break;
  593 #endif
  594         case AF_LINK:
  595                 pfil_remove_hook(V_ipfw_link_hook);
  596                 break;
  597         }
  598 }
  599 
  600 static int
  601 ipfw_link(int pf, bool unlink)
  602 {
  603         struct pfil_link_args pla;
  604 
  605         pla.pa_version = PFIL_VERSION;
  606         pla.pa_flags = PFIL_IN | PFIL_OUT | PFIL_HEADPTR | PFIL_HOOKPTR;
  607         if (unlink)
  608                 pla.pa_flags |= PFIL_UNLINK;
  609 
  610         switch (pf) {
  611         case AF_INET:
  612                 pla.pa_head = V_inet_pfil_head;
  613                 pla.pa_hook = V_ipfw_inet_hook;
  614                 break;
  615 #ifdef INET6
  616         case AF_INET6:
  617                 pla.pa_head = V_inet6_pfil_head;
  618                 pla.pa_hook = V_ipfw_inet6_hook;
  619                 break;
  620 #endif
  621         case AF_LINK:
  622                 pla.pa_head = V_link_pfil_head;
  623                 pla.pa_hook = V_ipfw_link_hook;
  624                 break;
  625         }
  626 
  627         return (pfil_link(&pla));
  628 }
  629 
  630 int
  631 ipfw_attach_hooks(void)
  632 {
  633         int error = 0;
  634 
  635         ipfw_hook(AF_INET);
  636         TUNABLE_INT_FETCH("net.inet.ip.fw.enable", &V_fw_enable);
  637         if (V_fw_enable && (error = ipfw_link(AF_INET, false)) != 0)
  638                 printf("ipfw_hook() error\n");
  639 #ifdef INET6
  640         ipfw_hook(AF_INET6);
  641         TUNABLE_INT_FETCH("net.inet6.ip6.fw.enable", &V_fw6_enable);
  642         if (V_fw6_enable && (error = ipfw_link(AF_INET6, false)) != 0)
  643                 printf("ipfw6_hook() error\n");
  644 #endif
  645         ipfw_hook(AF_LINK);
  646         TUNABLE_INT_FETCH("net.link.ether.ipfw", &V_fwlink_enable);
  647         if (V_fwlink_enable && (error = ipfw_link(AF_LINK, false)) != 0)
  648                 printf("ipfw_link_hook() error\n");
  649 
  650         return (error);
  651 }
  652 
  653 void
  654 ipfw_detach_hooks(void)
  655 {
  656 
  657         ipfw_unhook(AF_INET);
  658 #ifdef INET6
  659         ipfw_unhook(AF_INET6);
  660 #endif
  661         ipfw_unhook(AF_LINK);
  662 }
  663 
  664 int
  665 ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
  666 {
  667         int newval;
  668         int error;
  669         int af;
  670 
  671         if (arg1 == &V_fw_enable)
  672                 af = AF_INET;
  673 #ifdef INET6
  674         else if (arg1 == &V_fw6_enable)
  675                 af = AF_INET6;
  676 #endif
  677         else if (arg1 == &V_fwlink_enable)
  678                 af = AF_LINK;
  679         else 
  680                 return (EINVAL);
  681 
  682         newval = *(int *)arg1;
  683         /* Handle sysctl change */
  684         error = sysctl_handle_int(oidp, &newval, 0, req);
  685 
  686         if (error)
  687                 return (error);
  688 
  689         /* Formalize new value */
  690         newval = (newval) ? 1 : 0;
  691 
  692         if (*(int *)arg1 == newval)
  693                 return (0);
  694 
  695         error = ipfw_link(af, newval == 0 ? true : false);
  696         if (error)
  697                 return (error);
  698         *(int *)arg1 = newval;
  699 
  700         return (0);
  701 }
  702 /* end of file */

Cache object: 8e93903ec943721777eb35de7287d1b7


[ 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.