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_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  * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: releng/6.0/sys/netinet/ip_fw_pfil.c 145246 2005-04-18 18:35:05Z brooks $
   27  */
   28 
   29 #if !defined(KLD_MODULE)
   30 #include "opt_ipfw.h"
   31 #include "opt_ipdn.h"
   32 #include "opt_inet.h"
   33 #include "opt_inet6.h"
   34 #ifndef INET
   35 #error IPFIREWALL requires INET.
   36 #endif /* INET */
   37 #endif /* KLD_MODULE */
   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/socket.h>
   46 #include <sys/socketvar.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/ucred.h>
   49 
   50 #include <net/if.h>
   51 #include <net/route.h>
   52 #include <net/pfil.h>
   53 
   54 #include <netinet/in.h>
   55 #include <netinet/in_systm.h>
   56 #include <netinet/in_var.h>
   57 #include <netinet/ip.h>
   58 #include <netinet/ip_var.h>
   59 #include <netinet/ip_fw.h>
   60 #include <netinet/ip_divert.h>
   61 #include <netinet/ip_dummynet.h>
   62 
   63 #include <netgraph/ng_ipfw.h>
   64 
   65 #include <machine/in_cksum.h>
   66 
   67 static  int ipfw_pfil_hooked = 0;
   68 
   69 /* Dummynet hooks. */
   70 ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;
   71 
   72 /* Divert hooks. */
   73 ip_divert_packet_t *ip_divert_ptr = NULL;
   74 
   75 /* ng_ipfw hooks. */
   76 ng_ipfw_input_t *ng_ipfw_input_p = NULL;
   77 
   78 /* Forward declarations. */
   79 static int      ipfw_divert(struct mbuf **, int, int);
   80 #define DIV_DIR_IN      1
   81 #define DIV_DIR_OUT     0
   82 
   83 int
   84 ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
   85     struct inpcb *inp)
   86 {
   87         struct ip_fw_args args;
   88         struct ng_ipfw_tag *ng_tag;
   89         struct m_tag *dn_tag;
   90         int ipfw = 0;
   91         int divert;
   92         int tee;
   93 #ifdef IPFIREWALL_FORWARD
   94         struct m_tag *fwd_tag;
   95 #endif
   96 
   97         KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
   98 
   99         if (!fw_enable)
  100                 goto pass;
  101 
  102         bzero(&args, sizeof(args));
  103 
  104         dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
  105         if (dn_tag != NULL){
  106                 struct dn_pkt_tag *dt;
  107 
  108                 dt = (struct dn_pkt_tag *)(dn_tag+1);
  109                 args.rule = dt->rule;
  110 
  111                 m_tag_delete(*m0, dn_tag);
  112         }
  113 
  114         ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
  115             NULL);
  116         if (ng_tag != NULL) {
  117                 KASSERT(ng_tag->dir == NG_IPFW_IN,
  118                     ("ng_ipfw tag with wrong direction"));
  119                 args.rule = ng_tag->rule;
  120                 m_tag_delete(*m0, (struct m_tag *)ng_tag);
  121         }
  122 
  123 again:
  124         args.m = *m0;
  125         args.inp = inp;
  126         ipfw = ipfw_chk(&args);
  127         *m0 = args.m;
  128         tee = 0;
  129 
  130         KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
  131             __func__));
  132 
  133         switch (ipfw) {
  134         case IP_FW_PASS:
  135                 if (args.next_hop == NULL)
  136                         goto pass;
  137 
  138 #ifdef IPFIREWALL_FORWARD
  139                 fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
  140                                 sizeof(struct sockaddr_in), M_NOWAIT);
  141                 if (fwd_tag == NULL)
  142                         goto drop;
  143                 bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
  144                 m_tag_prepend(*m0, fwd_tag);
  145 
  146                 if (in_localip(args.next_hop->sin_addr))
  147                         (*m0)->m_flags |= M_FASTFWD_OURS;
  148                 goto pass;
  149 #endif
  150                 break;                  /* not reached */
  151 
  152         case IP_FW_DENY:
  153                 goto drop;
  154                 break;                  /* not reached */
  155 
  156         case IP_FW_DUMMYNET:
  157                 if (!DUMMYNET_LOADED)
  158                         goto drop;
  159                 if (mtod(*m0, struct ip *)->ip_v == 4)
  160                         ip_dn_io_ptr(*m0, DN_TO_IP_IN, &args);
  161                 else if (mtod(*m0, struct ip *)->ip_v == 6)
  162                         ip_dn_io_ptr(*m0, DN_TO_IP6_IN, &args);
  163                 *m0 = NULL;
  164                 return 0;               /* packet consumed */
  165 
  166         case IP_FW_TEE:
  167                 tee = 1;
  168                 /* fall through */
  169 
  170         case IP_FW_DIVERT:
  171                 divert = ipfw_divert(m0, DIV_DIR_IN, tee);
  172                 if (divert) {
  173                         *m0 = NULL;
  174                         return 0;       /* packet consumed */
  175                 } else {
  176                         args.rule = NULL;
  177                         goto again;     /* continue with packet */
  178                 }
  179 
  180         case IP_FW_NGTEE:
  181                 if (!NG_IPFW_LOADED)
  182                         goto drop;
  183                 (void)ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 1);
  184                 goto again;             /* continue with packet */
  185 
  186         case IP_FW_NETGRAPH:
  187                 if (!NG_IPFW_LOADED)
  188                         goto drop;
  189                 return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0);
  190 
  191         default:
  192                 KASSERT(0, ("%s: unknown retval", __func__));
  193         }
  194 
  195 drop:
  196         if (*m0)
  197                 m_freem(*m0);
  198         *m0 = NULL;
  199         return (EACCES);
  200 pass:
  201         return 0;       /* not filtered */
  202 }
  203 
  204 int
  205 ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
  206     struct inpcb *inp)
  207 {
  208         struct ip_fw_args args;
  209         struct ng_ipfw_tag *ng_tag;
  210         struct m_tag *dn_tag;
  211         int ipfw = 0;
  212         int divert;
  213         int tee;
  214 #ifdef IPFIREWALL_FORWARD
  215         struct m_tag *fwd_tag;
  216 #endif
  217 
  218         KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
  219 
  220         if (!fw_enable)
  221                 goto pass;
  222 
  223         bzero(&args, sizeof(args));
  224 
  225         dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
  226         if (dn_tag != NULL) {
  227                 struct dn_pkt_tag *dt;
  228 
  229                 dt = (struct dn_pkt_tag *)(dn_tag+1);
  230                 args.rule = dt->rule;
  231 
  232                 m_tag_delete(*m0, dn_tag);
  233         }
  234 
  235         ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
  236             NULL);
  237         if (ng_tag != NULL) {
  238                 KASSERT(ng_tag->dir == NG_IPFW_OUT,
  239                     ("ng_ipfw tag with wrong direction"));
  240                 args.rule = ng_tag->rule;
  241                 m_tag_delete(*m0, (struct m_tag *)ng_tag);
  242         }
  243 
  244 again:
  245         args.m = *m0;
  246         args.oif = ifp;
  247         args.inp = inp;
  248         ipfw = ipfw_chk(&args);
  249         *m0 = args.m;
  250         tee = 0;
  251 
  252         KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
  253             __func__));
  254 
  255         switch (ipfw) {
  256         case IP_FW_PASS:
  257                 if (args.next_hop == NULL)
  258                         goto pass;
  259 #ifdef IPFIREWALL_FORWARD
  260                 /* Overwrite existing tag. */
  261                 fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
  262                 if (fwd_tag == NULL) {
  263                         fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
  264                                 sizeof(struct sockaddr_in), M_NOWAIT);
  265                         if (fwd_tag == NULL)
  266                                 goto drop;
  267                 } else
  268                         m_tag_unlink(*m0, fwd_tag);
  269                 bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
  270                 m_tag_prepend(*m0, fwd_tag);
  271 
  272                 if (in_localip(args.next_hop->sin_addr))
  273                         (*m0)->m_flags |= M_FASTFWD_OURS;
  274                 goto pass;
  275 #endif
  276                 break;                  /* not reached */
  277 
  278         case IP_FW_DENY:
  279                 goto drop;
  280                 break;                  /* not reached */
  281 
  282         case IP_FW_DUMMYNET:
  283                 if (!DUMMYNET_LOADED)
  284                         break;
  285                 if (mtod(*m0, struct ip *)->ip_v == 4)
  286                         ip_dn_io_ptr(*m0, DN_TO_IP_OUT, &args);
  287                 else if (mtod(*m0, struct ip *)->ip_v == 6)
  288                         ip_dn_io_ptr(*m0, DN_TO_IP6_OUT, &args);
  289                 *m0 = NULL;
  290                 return 0;               /* packet consumed */
  291 
  292                 break;
  293 
  294         case IP_FW_TEE:
  295                 tee = 1;
  296                 /* fall through */
  297 
  298         case IP_FW_DIVERT:
  299                 divert = ipfw_divert(m0, DIV_DIR_OUT, tee);
  300                 if (divert) {
  301                         *m0 = NULL;
  302                         return 0;       /* packet consumed */
  303                 } else {
  304                         args.rule = NULL;
  305                         goto again;     /* continue with packet */
  306                 }
  307 
  308         case IP_FW_NGTEE:
  309                 if (!NG_IPFW_LOADED)
  310                         goto drop;
  311                 (void)ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 1);
  312                 goto again;             /* continue with packet */
  313 
  314         case IP_FW_NETGRAPH:
  315                 if (!NG_IPFW_LOADED)
  316                         goto drop;
  317                 return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0);
  318 
  319         default:
  320                 KASSERT(0, ("%s: unknown retval", __func__));
  321         }
  322 
  323 drop:
  324         if (*m0)
  325                 m_freem(*m0);
  326         *m0 = NULL;
  327         return (EACCES);
  328 pass:
  329         return 0;       /* not filtered */
  330 }
  331 
  332 static int
  333 ipfw_divert(struct mbuf **m, int incoming, int tee)
  334 {
  335         /*
  336          * ipfw_chk() has already tagged the packet with the divert tag.
  337          * If tee is set, copy packet and return original.
  338          * If not tee, consume packet and send it to divert socket.
  339          */
  340         struct mbuf *clone, *reass;
  341         struct ip *ip;
  342         int hlen;
  343 
  344         reass = NULL;
  345 
  346         /* Is divert module loaded? */
  347         if (ip_divert_ptr == NULL)
  348                 goto nodivert;
  349 
  350         /* Cloning needed for tee? */
  351         if (tee)
  352                 clone = m_dup(*m, M_DONTWAIT);
  353         else
  354                 clone = *m;
  355 
  356         /* In case m_dup was unable to allocate mbufs. */
  357         if (clone == NULL)
  358                 goto teeout;
  359 
  360         /*
  361          * Divert listeners can only handle non-fragmented packets.
  362          * However when tee is set we will *not* de-fragment the packets;
  363          * Doing do would put the reassembly into double-jeopardy.  On top
  364          * of that someone doing a tee will probably want to get the packet
  365          * in its original form.
  366          */
  367         ip = mtod(clone, struct ip *);
  368         if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
  369 
  370                 /* Reassemble packet. */
  371                 reass = ip_reass(clone);
  372 
  373                 /*
  374                  * IP header checksum fixup after reassembly and leave header
  375                  * in network byte order.
  376                  */
  377                 if (reass != NULL) {
  378                         ip = mtod(reass, struct ip *);
  379                         hlen = ip->ip_hl << 2;
  380                         ip->ip_len = htons(ip->ip_len);
  381                         ip->ip_off = htons(ip->ip_off);
  382                         ip->ip_sum = 0;
  383                         if (hlen == sizeof(struct ip))
  384                                 ip->ip_sum = in_cksum_hdr(ip);
  385                         else
  386                                 ip->ip_sum = in_cksum(reass, hlen);
  387                         clone = reass;
  388                 } else
  389                         clone = NULL;
  390         } else {
  391                 /* Convert header to network byte order. */
  392                 ip->ip_len = htons(ip->ip_len);
  393                 ip->ip_off = htons(ip->ip_off);
  394         }
  395 
  396         /* Do the dirty job... */
  397         if (clone && ip_divert_ptr != NULL)
  398                 ip_divert_ptr(clone, incoming);
  399 
  400 teeout:
  401         /*
  402          * For tee we leave the divert tag attached to original packet.
  403          * It will then continue rule evaluation after the tee rule.
  404          */
  405         if (tee)
  406                 return 0;
  407 
  408         /* Packet diverted and consumed */
  409         return 1;
  410 
  411 nodivert:
  412         m_freem(*m);
  413         return 1;
  414 }
  415 
  416 static int
  417 ipfw_hook(void)
  418 {
  419         struct pfil_head *pfh_inet;
  420 #ifdef INET6
  421         struct pfil_head *pfh_inet6;
  422 #endif
  423 
  424         if (ipfw_pfil_hooked)
  425                 return EEXIST;
  426 
  427         pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
  428         if (pfh_inet == NULL)
  429                 return ENOENT;
  430 #ifdef INET6
  431         pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
  432         if (pfh_inet6 == NULL)
  433                 return ENOENT;
  434 #endif
  435 
  436         pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
  437         pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
  438 #ifdef INET6
  439         pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
  440         pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
  441 #endif
  442 
  443         return 0;
  444 }
  445 
  446 static int
  447 ipfw_unhook(void)
  448 {
  449         struct pfil_head *pfh_inet;
  450 #ifdef INET6
  451         struct pfil_head *pfh_inet6;
  452 #endif
  453 
  454         if (!ipfw_pfil_hooked)
  455                 return ENOENT;
  456 
  457         pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
  458         if (pfh_inet == NULL)
  459                 return ENOENT;
  460 #ifdef INET6
  461         pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
  462         if (pfh_inet6 == NULL)
  463                 return ENOENT;
  464 #endif
  465 
  466         pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
  467         pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
  468 #ifdef INET6
  469         pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
  470         pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
  471 #endif
  472 
  473         return 0;
  474 }
  475 
  476 static int
  477 ipfw_modevent(module_t mod, int type, void *unused)
  478 {
  479         int err = 0;
  480 
  481         switch (type) {
  482         case MOD_LOAD:
  483                 if (ipfw_pfil_hooked) {
  484                         printf("IP firewall already loaded\n");
  485                         err = EEXIST;
  486                 } else {
  487                         if ((err = ipfw_init()) != 0) {
  488                                 printf("ipfw_init() error\n");
  489                                 break;
  490                         }
  491                         if ((err = ipfw_hook()) != 0) {
  492                                 printf("ipfw_hook() error\n");
  493                                 break;
  494                         }
  495                         ipfw_pfil_hooked = 1;
  496                 }
  497                 break;
  498 
  499         case MOD_UNLOAD:
  500                 if (ipfw_pfil_hooked) {
  501                         if ((err = ipfw_unhook()) > 0)
  502                                 break;
  503                         ipfw_destroy();
  504                         ipfw_pfil_hooked = 0;
  505                 } else {
  506                         printf("IP firewall already unloaded\n");
  507                 }
  508                 break;
  509 
  510         default:
  511                 return EOPNOTSUPP;
  512                 break;
  513         }
  514         return err;
  515 }
  516 
  517 static moduledata_t ipfwmod = {
  518         "ipfw",
  519         ipfw_modevent,
  520         0
  521 };
  522 DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
  523 MODULE_VERSION(ipfw, 2);

Cache object: 2251e257ee215dcc26ea65895824b8e7


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