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/net/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 /*      $FreeBSD$ */
    2 /*      $NetBSD: pfil.c,v 1.20 2001/11/12 23:49:46 lukem Exp $  */
    3 
    4 /*-
    5  * SPDX-License-Identifier: BSD-3-Clause
    6  *
    7  * Copyright (c) 2019 Gleb Smirnoff <glebius@FreeBSD.org>
    8  * Copyright (c) 1996 Matthew R. Green
    9  * All rights reserved.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. The name of the author may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/conf.h>
   37 #include <sys/kernel.h>
   38 #include <sys/epoch.h>
   39 #include <sys/errno.h>
   40 #include <sys/lock.h>
   41 #include <sys/malloc.h>
   42 #include <sys/socket.h>
   43 #include <sys/socketvar.h>
   44 #include <sys/systm.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/proc.h>
   48 #include <sys/queue.h>
   49 #include <sys/ucred.h>
   50 #include <sys/jail.h>
   51 
   52 #include <net/if.h>
   53 #include <net/if_var.h>
   54 #include <net/pfil.h>
   55 
   56 static MALLOC_DEFINE(M_PFIL, "pfil", "pfil(9) packet filter hooks");
   57 
   58 static int pfil_ioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
   59 static struct cdevsw pfil_cdevsw = {
   60         .d_ioctl =      pfil_ioctl,
   61         .d_name =       PFILDEV,
   62         .d_version =    D_VERSION,
   63 };
   64 static struct cdev *pfil_dev;
   65 
   66 static struct mtx pfil_lock;
   67 MTX_SYSINIT(pfil_mtxinit, &pfil_lock, "pfil(9) lock", MTX_DEF);
   68 #define PFIL_LOCK()     mtx_lock(&pfil_lock)
   69 #define PFIL_UNLOCK()   mtx_unlock(&pfil_lock)
   70 #define PFIL_LOCK_ASSERT()      mtx_assert(&pfil_lock, MA_OWNED)
   71 
   72 struct pfil_hook {
   73         pfil_func_t      hook_func;
   74         void            *hook_ruleset;
   75         int              hook_flags;
   76         int              hook_links;
   77         enum pfil_types  hook_type;
   78         const char      *hook_modname;
   79         const char      *hook_rulname;
   80         LIST_ENTRY(pfil_hook) hook_list;
   81 };
   82 
   83 struct pfil_link {
   84         CK_STAILQ_ENTRY(pfil_link) link_chain;
   85         pfil_func_t              link_func;
   86         void                    *link_ruleset;
   87         int                      link_flags;
   88         struct pfil_hook        *link_hook;
   89         struct epoch_context     link_epoch_ctx;
   90 };
   91 
   92 typedef CK_STAILQ_HEAD(pfil_chain, pfil_link)   pfil_chain_t;
   93 struct pfil_head {
   94         int              head_nhooksin;
   95         int              head_nhooksout;
   96         pfil_chain_t     head_in;
   97         pfil_chain_t     head_out;
   98         int              head_flags;
   99         enum pfil_types  head_type;
  100         LIST_ENTRY(pfil_head) head_list;
  101         const char      *head_name;
  102 };
  103 
  104 LIST_HEAD(pfilheadhead, pfil_head);
  105 VNET_DEFINE_STATIC(struct pfilheadhead, pfil_head_list) =
  106     LIST_HEAD_INITIALIZER(pfil_head_list);
  107 #define V_pfil_head_list        VNET(pfil_head_list)
  108 
  109 LIST_HEAD(pfilhookhead, pfil_hook);
  110 VNET_DEFINE_STATIC(struct pfilhookhead, pfil_hook_list) =
  111     LIST_HEAD_INITIALIZER(pfil_hook_list);
  112 #define V_pfil_hook_list        VNET(pfil_hook_list)
  113 
  114 static struct pfil_link *pfil_link_remove(pfil_chain_t *, pfil_hook_t );
  115 static void pfil_link_free(epoch_context_t);
  116 
  117 int
  118 pfil_realloc(pfil_packet_t *p, int flags, struct ifnet *ifp)
  119 {
  120         struct mbuf *m;
  121 
  122         MPASS(flags & PFIL_MEMPTR);
  123 
  124         if ((m = m_devget(p->mem, PFIL_LENGTH(flags), 0, ifp, NULL)) == NULL)
  125                 return (ENOMEM);
  126         *p = pfil_packet_align(*p);
  127         *p->m = m;
  128 
  129         return (0);
  130 }
  131 
  132 static __noinline int
  133 pfil_fake_mbuf(pfil_func_t func, pfil_packet_t *p, struct ifnet *ifp, int flags,
  134     void *ruleset, struct inpcb *inp)
  135 {
  136         struct mbuf m, *mp;
  137         pfil_return_t rv;
  138 
  139         (void)m_init(&m, M_NOWAIT, MT_DATA, M_NOFREE | M_PKTHDR);
  140         m_extadd(&m, p->mem, PFIL_LENGTH(flags), NULL, NULL, NULL, 0,
  141             EXT_RXRING);
  142         m.m_len = m.m_pkthdr.len = PFIL_LENGTH(flags);
  143         mp = &m;
  144         flags &= ~(PFIL_MEMPTR | PFIL_LENMASK);
  145 
  146         rv = func(&mp, ifp, flags, ruleset, inp);
  147         if (rv == PFIL_PASS && mp != &m) {
  148                 /*
  149                  * Firewalls that need pfil_fake_mbuf() most likely don't
  150                  * know they need return PFIL_REALLOCED.
  151                  */
  152                 rv = PFIL_REALLOCED;
  153                 *p = pfil_packet_align(*p);
  154                 *p->m = mp;
  155         }
  156 
  157         return (rv);
  158 }
  159 
  160 /*
  161  * pfil_run_hooks() runs the specified packet filter hook chain.
  162  */
  163 int
  164 pfil_run_hooks(struct pfil_head *head, pfil_packet_t p, struct ifnet *ifp,
  165     int flags, struct inpcb *inp)
  166 {
  167         pfil_chain_t *pch;
  168         struct pfil_link *link;
  169         pfil_return_t rv;
  170         bool realloc = false;
  171 
  172         NET_EPOCH_ASSERT();
  173 
  174         if (PFIL_DIR(flags) == PFIL_IN)
  175                 pch = &head->head_in;
  176         else if (__predict_true(PFIL_DIR(flags) == PFIL_OUT))
  177                 pch = &head->head_out;
  178         else
  179                 panic("%s: bogus flags %d", __func__, flags);
  180 
  181         rv = PFIL_PASS;
  182         CK_STAILQ_FOREACH(link, pch, link_chain) {
  183                 if ((flags & PFIL_MEMPTR) && !(link->link_flags & PFIL_MEMPTR))
  184                         rv = pfil_fake_mbuf(link->link_func, &p, ifp, flags,
  185                             link->link_ruleset, inp);
  186                 else
  187                         rv = (*link->link_func)(p, ifp, flags,
  188                             link->link_ruleset, inp);
  189                 if (rv == PFIL_DROPPED || rv == PFIL_CONSUMED)
  190                         break;
  191                 else if (rv == PFIL_REALLOCED) {
  192                         flags &= ~(PFIL_MEMPTR | PFIL_LENMASK);
  193                         realloc = true;
  194                 }
  195         }
  196         if (realloc && rv == PFIL_PASS)
  197                 rv = PFIL_REALLOCED;
  198         return (rv);
  199 }
  200 
  201 static __always_inline int
  202 pfil_mbuf_common(pfil_chain_t *pch, pfil_packet_t p, struct ifnet *ifp,
  203     int flags, struct inpcb *inp)
  204 {
  205         struct pfil_link *link;
  206         pfil_return_t rv;
  207 
  208         NET_EPOCH_ASSERT();
  209         KASSERT(flags == PFIL_IN || flags == PFIL_OUT,
  210             ("%s: unsupported flags %d", __func__, flags));
  211 
  212         rv = PFIL_PASS;
  213         CK_STAILQ_FOREACH(link, pch, link_chain) {
  214                 rv = (*link->link_func)(p, ifp, flags, link->link_ruleset, inp);
  215                 if (rv == PFIL_DROPPED || rv == PFIL_CONSUMED)
  216                         break;
  217         }
  218         return (rv);
  219 }
  220 
  221 int
  222 pfil_mbuf_in(struct pfil_head *head, pfil_packet_t p, struct ifnet *ifp,
  223    struct inpcb *inp)
  224 {
  225 
  226         return (pfil_mbuf_common(&head->head_in, p, ifp, PFIL_IN, inp));
  227 }
  228 
  229 int
  230 pfil_mbuf_out(struct pfil_head *head, pfil_packet_t p, struct ifnet *ifp,
  231     struct inpcb *inp)
  232 {
  233 
  234         return (pfil_mbuf_common(&head->head_out, p, ifp, PFIL_OUT, inp));
  235 }
  236 
  237 /*
  238  * pfil_head_register() registers a pfil_head with the packet filter hook
  239  * mechanism.
  240  */
  241 pfil_head_t
  242 pfil_head_register(struct pfil_head_args *pa)
  243 {
  244         struct pfil_head *head, *list;
  245 
  246         MPASS(pa->pa_version == PFIL_VERSION);
  247 
  248         head = malloc(sizeof(struct pfil_head), M_PFIL, M_WAITOK);
  249 
  250         head->head_nhooksin = head->head_nhooksout = 0;
  251         head->head_flags = pa->pa_flags;
  252         head->head_type = pa->pa_type;
  253         head->head_name = pa->pa_headname;
  254         CK_STAILQ_INIT(&head->head_in);
  255         CK_STAILQ_INIT(&head->head_out);
  256 
  257         PFIL_LOCK();
  258         LIST_FOREACH(list, &V_pfil_head_list, head_list)
  259                 if (strcmp(pa->pa_headname, list->head_name) == 0) {
  260                         printf("pfil: duplicate head \"%s\"\n",
  261                             pa->pa_headname);
  262                 }
  263         LIST_INSERT_HEAD(&V_pfil_head_list, head, head_list);
  264         PFIL_UNLOCK();
  265 
  266         return (head);
  267 }
  268 
  269 /*
  270  * pfil_head_unregister() removes a pfil_head from the packet filter hook
  271  * mechanism.  The producer of the hook promises that all outstanding
  272  * invocations of the hook have completed before it unregisters the hook.
  273  */
  274 void
  275 pfil_head_unregister(pfil_head_t ph)
  276 {
  277         struct pfil_link *link, *next;
  278 
  279         PFIL_LOCK();
  280         LIST_REMOVE(ph, head_list);
  281 
  282         CK_STAILQ_FOREACH_SAFE(link, &ph->head_in, link_chain, next) {
  283                 link->link_hook->hook_links--;
  284                 free(link, M_PFIL);
  285         }
  286         CK_STAILQ_FOREACH_SAFE(link, &ph->head_out, link_chain, next) {
  287                 link->link_hook->hook_links--;
  288                 free(link, M_PFIL);
  289         }
  290         PFIL_UNLOCK();
  291 }
  292 
  293 pfil_hook_t
  294 pfil_add_hook(struct pfil_hook_args *pa)
  295 {
  296         struct pfil_hook *hook, *list;
  297 
  298         MPASS(pa->pa_version == PFIL_VERSION);
  299 
  300         hook = malloc(sizeof(struct pfil_hook), M_PFIL, M_WAITOK | M_ZERO);
  301         hook->hook_func = pa->pa_func;
  302         hook->hook_ruleset = pa->pa_ruleset;
  303         hook->hook_flags = pa->pa_flags;
  304         hook->hook_type = pa->pa_type;
  305         hook->hook_modname = pa->pa_modname;
  306         hook->hook_rulname = pa->pa_rulname;
  307 
  308         PFIL_LOCK();
  309         LIST_FOREACH(list, &V_pfil_hook_list, hook_list)
  310                 if (strcmp(pa->pa_modname, list->hook_modname) == 0 &&
  311                     strcmp(pa->pa_rulname, list->hook_rulname) == 0) {
  312                         printf("pfil: duplicate hook \"%s:%s\"\n",
  313                             pa->pa_modname, pa->pa_rulname);
  314                 }
  315         LIST_INSERT_HEAD(&V_pfil_hook_list, hook, hook_list);
  316         PFIL_UNLOCK();
  317 
  318         return (hook);
  319 }
  320 
  321 static int
  322 pfil_unlink(struct pfil_link_args *pa, pfil_head_t head, pfil_hook_t hook)
  323 {
  324         struct pfil_link *in, *out;
  325 
  326         PFIL_LOCK_ASSERT();
  327 
  328         if (pa->pa_flags & PFIL_IN) {
  329                 in = pfil_link_remove(&head->head_in, hook);
  330                 if (in != NULL) {
  331                         head->head_nhooksin--;
  332                         hook->hook_links--;
  333                 }
  334         } else
  335                 in = NULL;
  336         if (pa->pa_flags & PFIL_OUT) {
  337                 out = pfil_link_remove(&head->head_out, hook);
  338                 if (out != NULL) {
  339                         head->head_nhooksout--;
  340                         hook->hook_links--;
  341                 }
  342         } else
  343                 out = NULL;
  344         PFIL_UNLOCK();
  345 
  346         if (in != NULL)
  347                 NET_EPOCH_CALL(pfil_link_free, &in->link_epoch_ctx);
  348         if (out != NULL)
  349                 NET_EPOCH_CALL(pfil_link_free, &out->link_epoch_ctx);
  350 
  351         if (in == NULL && out == NULL)
  352                 return (ENOENT);
  353         else
  354                 return (0);
  355 }
  356 
  357 int
  358 pfil_link(struct pfil_link_args *pa)
  359 {
  360         struct pfil_link *in, *out, *link;
  361         struct pfil_head *head;
  362         struct pfil_hook *hook;
  363         int error;
  364 
  365         MPASS(pa->pa_version == PFIL_VERSION);
  366 
  367         if ((pa->pa_flags & (PFIL_IN | PFIL_UNLINK)) == PFIL_IN)
  368                 in = malloc(sizeof(*in), M_PFIL, M_WAITOK | M_ZERO);
  369         else
  370                 in = NULL;
  371         if ((pa->pa_flags & (PFIL_OUT | PFIL_UNLINK)) == PFIL_OUT)
  372                 out = malloc(sizeof(*out), M_PFIL, M_WAITOK | M_ZERO);
  373         else
  374                 out = NULL;
  375 
  376         PFIL_LOCK();
  377         if (pa->pa_flags & PFIL_HEADPTR)
  378                 head = pa->pa_head;
  379         else
  380                 LIST_FOREACH(head, &V_pfil_head_list, head_list)
  381                         if (strcmp(pa->pa_headname, head->head_name) == 0)
  382                                 break;
  383         if (pa->pa_flags & PFIL_HOOKPTR)
  384                 hook = pa->pa_hook;
  385         else
  386                 LIST_FOREACH(hook, &V_pfil_hook_list, hook_list)
  387                         if (strcmp(pa->pa_modname, hook->hook_modname) == 0 &&
  388                             strcmp(pa->pa_rulname, hook->hook_rulname) == 0)
  389                                 break;
  390         if (head == NULL || hook == NULL) {
  391                 error = ENOENT;
  392                 goto fail;
  393         }
  394 
  395         if (pa->pa_flags & PFIL_UNLINK)
  396                 return (pfil_unlink(pa, head, hook));
  397 
  398         if (head->head_type != hook->hook_type ||
  399             ((hook->hook_flags & pa->pa_flags) & ~head->head_flags)) {
  400                 error = EINVAL;
  401                 goto fail;
  402         }
  403 
  404         if (pa->pa_flags & PFIL_IN)
  405                 CK_STAILQ_FOREACH(link, &head->head_in, link_chain)
  406                         if (link->link_hook == hook) {
  407                                 error = EEXIST;
  408                                 goto fail;
  409                         }
  410         if (pa->pa_flags & PFIL_OUT)
  411                 CK_STAILQ_FOREACH(link, &head->head_out, link_chain)
  412                         if (link->link_hook == hook) {
  413                                 error = EEXIST;
  414                                 goto fail;
  415                         }
  416 
  417         if (pa->pa_flags & PFIL_IN) {
  418                 in->link_hook = hook;
  419                 in->link_func = hook->hook_func;
  420                 in->link_flags = hook->hook_flags;
  421                 in->link_ruleset = hook->hook_ruleset;
  422                 if (pa->pa_flags & PFIL_APPEND)
  423                         CK_STAILQ_INSERT_TAIL(&head->head_in, in, link_chain);
  424                 else
  425                         CK_STAILQ_INSERT_HEAD(&head->head_in, in, link_chain);
  426                 hook->hook_links++;
  427                 head->head_nhooksin++;
  428         }
  429         if (pa->pa_flags & PFIL_OUT) {
  430                 out->link_hook = hook;
  431                 out->link_func = hook->hook_func;
  432                 out->link_flags = hook->hook_flags;
  433                 out->link_ruleset = hook->hook_ruleset;
  434                 if (pa->pa_flags & PFIL_APPEND)
  435                         CK_STAILQ_INSERT_HEAD(&head->head_out, out, link_chain);
  436                 else
  437                         CK_STAILQ_INSERT_TAIL(&head->head_out, out, link_chain);
  438                 hook->hook_links++;
  439                 head->head_nhooksout++;
  440         }
  441         PFIL_UNLOCK();
  442 
  443         return (0);
  444 
  445 fail:
  446         PFIL_UNLOCK();
  447         free(in, M_PFIL);
  448         free(out, M_PFIL);
  449         return (error);
  450 }
  451 
  452 static void
  453 pfil_link_free(epoch_context_t ctx)
  454 {
  455         struct pfil_link *link;
  456 
  457         link = __containerof(ctx, struct pfil_link, link_epoch_ctx);
  458         free(link, M_PFIL);
  459 }
  460 
  461 /*
  462  * pfil_remove_hook removes a filter from all filtering points.
  463  */
  464 void
  465 pfil_remove_hook(pfil_hook_t hook)
  466 {
  467         struct pfil_head *head;
  468         struct pfil_link *in, *out;
  469 
  470         PFIL_LOCK();
  471         LIST_FOREACH(head, &V_pfil_head_list, head_list) {
  472 retry:
  473                 in = pfil_link_remove(&head->head_in, hook);
  474                 if (in != NULL) {
  475                         head->head_nhooksin--;
  476                         hook->hook_links--;
  477                         NET_EPOCH_CALL(pfil_link_free, &in->link_epoch_ctx);
  478                 }
  479                 out = pfil_link_remove(&head->head_out, hook);
  480                 if (out != NULL) {
  481                         head->head_nhooksout--;
  482                         hook->hook_links--;
  483                         NET_EPOCH_CALL(pfil_link_free, &out->link_epoch_ctx);
  484                 }
  485                 if (in != NULL || out != NULL)
  486                         /* What if some stupid admin put same filter twice? */
  487                         goto retry;
  488         }
  489         LIST_REMOVE(hook, hook_list);
  490         PFIL_UNLOCK();
  491         MPASS(hook->hook_links == 0);
  492         free(hook, M_PFIL);
  493 }
  494 
  495 /*
  496  * Internal: Remove a pfil hook from a hook chain.
  497  */
  498 static struct pfil_link *
  499 pfil_link_remove(pfil_chain_t *chain, pfil_hook_t hook)
  500 {
  501         struct pfil_link *link;
  502 
  503         PFIL_LOCK_ASSERT();
  504 
  505         CK_STAILQ_FOREACH(link, chain, link_chain)
  506                 if (link->link_hook == hook) {
  507                         CK_STAILQ_REMOVE(chain, link, pfil_link, link_chain);
  508                         return (link);
  509                 }
  510 
  511         return (NULL);
  512 }
  513 
  514 static void
  515 pfil_init(const void *unused __unused)
  516 {
  517         struct make_dev_args args;
  518         int error __diagused;
  519 
  520         make_dev_args_init(&args);
  521         args.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
  522         args.mda_devsw = &pfil_cdevsw;
  523         args.mda_uid = UID_ROOT;
  524         args.mda_gid = GID_WHEEL;
  525         args.mda_mode = 0600;
  526         error = make_dev_s(&args, &pfil_dev, PFILDEV);
  527         KASSERT(error == 0, ("%s: failed to create dev: %d", __func__, error));
  528 }
  529 /*
  530  * Make sure the pfil bits are first before any possible subsystem which
  531  * might piggyback on the SI_SUB_PROTO_PFIL.
  532  */
  533 SYSINIT(pfil_init, SI_SUB_PROTO_PFIL, SI_ORDER_FIRST, pfil_init, NULL);
  534 
  535 /*
  536  * User control interface.
  537  */
  538 static int pfilioc_listheads(struct pfilioc_list *);
  539 static int pfilioc_listhooks(struct pfilioc_list *);
  540 static int pfilioc_link(struct pfilioc_link *);
  541 
  542 static int
  543 pfil_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
  544     struct thread *td)
  545 {
  546         int error;
  547 
  548         CURVNET_SET(TD_TO_VNET(td));
  549         error = 0;
  550         switch (cmd) {
  551         case PFILIOC_LISTHEADS:
  552                 error = pfilioc_listheads((struct pfilioc_list *)addr);
  553                 break;
  554         case PFILIOC_LISTHOOKS:
  555                 error = pfilioc_listhooks((struct pfilioc_list *)addr);
  556                 break;
  557         case PFILIOC_LINK:
  558                 error = pfilioc_link((struct pfilioc_link *)addr);
  559                 break;
  560         default:
  561                 error = EINVAL;
  562                 break;
  563         }
  564         CURVNET_RESTORE();
  565         return (error);
  566 }
  567 
  568 static int
  569 pfilioc_listheads(struct pfilioc_list *req)
  570 {
  571         struct pfil_head *head;
  572         struct pfil_link *link;
  573         struct pfilioc_head *iohead;
  574         struct pfilioc_hook *iohook;
  575         u_int nheads, nhooks, hd, hk;
  576         int error;
  577 
  578         PFIL_LOCK();
  579 restart:
  580         nheads = nhooks = 0;
  581         LIST_FOREACH(head, &V_pfil_head_list, head_list) {
  582                 nheads++;
  583                 nhooks += head->head_nhooksin + head->head_nhooksout;
  584         }
  585         PFIL_UNLOCK();
  586 
  587         if (req->pio_nheads < nheads || req->pio_nhooks < nhooks) {
  588                 req->pio_nheads = nheads;
  589                 req->pio_nhooks = nhooks;
  590                 return (0);
  591         }
  592 
  593         iohead = malloc(sizeof(*iohead) * nheads, M_TEMP, M_WAITOK);
  594         iohook = malloc(sizeof(*iohook) * nhooks, M_TEMP, M_WAITOK);
  595 
  596         hd = hk = 0;
  597         PFIL_LOCK();
  598         LIST_FOREACH(head, &V_pfil_head_list, head_list) {
  599                 if (hd + 1 > nheads ||
  600                     hk + head->head_nhooksin + head->head_nhooksout > nhooks) {
  601                         /* Configuration changed during malloc(). */
  602                         free(iohead, M_TEMP);
  603                         free(iohook, M_TEMP);
  604                         goto restart;
  605                 }
  606                 strlcpy(iohead[hd].pio_name, head->head_name,
  607                         sizeof(iohead[0].pio_name));
  608                 iohead[hd].pio_nhooksin = head->head_nhooksin;
  609                 iohead[hd].pio_nhooksout = head->head_nhooksout;
  610                 iohead[hd].pio_type = head->head_type;
  611                 CK_STAILQ_FOREACH(link, &head->head_in, link_chain) {
  612                         strlcpy(iohook[hk].pio_module,
  613                             link->link_hook->hook_modname,
  614                             sizeof(iohook[0].pio_module));
  615                         strlcpy(iohook[hk].pio_ruleset,
  616                             link->link_hook->hook_rulname,
  617                             sizeof(iohook[0].pio_ruleset));
  618                         hk++;
  619                 }
  620                 CK_STAILQ_FOREACH(link, &head->head_out, link_chain) {
  621                         strlcpy(iohook[hk].pio_module,
  622                             link->link_hook->hook_modname,
  623                             sizeof(iohook[0].pio_module));
  624                         strlcpy(iohook[hk].pio_ruleset,
  625                             link->link_hook->hook_rulname,
  626                             sizeof(iohook[0].pio_ruleset));
  627                         hk++;
  628                 }
  629                 hd++;
  630         }
  631         PFIL_UNLOCK();
  632 
  633         error = copyout(iohead, req->pio_heads,
  634             sizeof(*iohead) * min(hd, req->pio_nheads));
  635         if (error == 0)
  636                 error = copyout(iohook, req->pio_hooks,
  637                     sizeof(*iohook) * min(req->pio_nhooks, hk));
  638 
  639         req->pio_nheads = hd;
  640         req->pio_nhooks = hk;
  641 
  642         free(iohead, M_TEMP);
  643         free(iohook, M_TEMP);
  644 
  645         return (error);
  646 }
  647 
  648 static int
  649 pfilioc_listhooks(struct pfilioc_list *req)
  650 {
  651         struct pfil_hook *hook;
  652         struct pfilioc_hook *iohook;
  653         u_int nhooks, hk;
  654         int error;
  655 
  656         PFIL_LOCK();
  657 restart:
  658         nhooks = 0;
  659         LIST_FOREACH(hook, &V_pfil_hook_list, hook_list)
  660                 nhooks++;
  661         PFIL_UNLOCK();
  662 
  663         if (req->pio_nhooks < nhooks) {
  664                 req->pio_nhooks = nhooks;
  665                 return (0);
  666         }
  667 
  668         iohook = malloc(sizeof(*iohook) * nhooks, M_TEMP, M_WAITOK);
  669 
  670         hk = 0;
  671         PFIL_LOCK();
  672         LIST_FOREACH(hook, &V_pfil_hook_list, hook_list) {
  673                 if (hk + 1 > nhooks) {
  674                         /* Configuration changed during malloc(). */
  675                         free(iohook, M_TEMP);
  676                         goto restart;
  677                 }
  678                 strlcpy(iohook[hk].pio_module, hook->hook_modname,
  679                     sizeof(iohook[0].pio_module));
  680                 strlcpy(iohook[hk].pio_ruleset, hook->hook_rulname,
  681                     sizeof(iohook[0].pio_ruleset));
  682                 iohook[hk].pio_type = hook->hook_type;
  683                 iohook[hk].pio_flags = hook->hook_flags;
  684                 hk++;
  685         }
  686         PFIL_UNLOCK();
  687 
  688         error = copyout(iohook, req->pio_hooks,
  689             sizeof(*iohook) * min(req->pio_nhooks, hk));
  690         req->pio_nhooks = hk;
  691         free(iohook, M_TEMP);
  692 
  693         return (error);
  694 }
  695 
  696 static int
  697 pfilioc_link(struct pfilioc_link *req)
  698 {
  699         struct pfil_link_args args;
  700 
  701         if (req->pio_flags & ~(PFIL_IN | PFIL_OUT | PFIL_UNLINK | PFIL_APPEND))
  702                 return (EINVAL);
  703 
  704         args.pa_version = PFIL_VERSION;
  705         args.pa_flags = req->pio_flags;
  706         args.pa_headname = req->pio_name;
  707         args.pa_modname = req->pio_module;
  708         args.pa_rulname = req->pio_ruleset;
  709 
  710         return (pfil_link(&args));
  711 }

Cache object: 828239f8663bfd521c5f1a5e6f3ee1c3


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