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/pf/pf_ruleset.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
    3  *
    4  * Copyright (c) 2001 Daniel Hartmeier
    5  * Copyright (c) 2002,2003 Henning Brauer
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  *
   12  *    - Redistributions of source code must retain the above copyright
   13  *      notice, this list of conditions and the following disclaimer.
   14  *    - Redistributions in binary form must reproduce the above
   15  *      copyright notice, this list of conditions and the following
   16  *      disclaimer in the documentation and/or other materials provided
   17  *      with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  *
   32  * Effort sponsored in part by the Defense Advanced Research Projects
   33  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   34  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
   35  *
   36  *      $OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __FBSDID("$FreeBSD$");
   41 
   42 #include <sys/param.h>
   43 #include <sys/socket.h>
   44 #include <sys/systm.h>
   45 #include <sys/refcount.h>
   46 #include <sys/mbuf.h>
   47 
   48 #include <netinet/in.h>
   49 #include <netinet/in_systm.h>
   50 #include <netinet/ip.h>
   51 #include <netinet/tcp.h>
   52 
   53 #include <net/if.h>
   54 #include <net/vnet.h>
   55 #include <net/pfvar.h>
   56 
   57 #ifdef INET6
   58 #include <netinet/ip6.h>
   59 #endif /* INET6 */
   60 
   61 #ifndef _KERNEL
   62 #error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead."
   63 #endif
   64 
   65 #define DPFPRINTF(format, x...)                         \
   66         if (V_pf_status.debug >= PF_DEBUG_NOISY)        \
   67                 printf(format , ##x)
   68 #define rs_malloc(x)            malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
   69 #define rs_free(x)              free(x, M_TEMP)
   70 
   71 VNET_DEFINE(struct pf_kanchor_global,   pf_anchors);
   72 VNET_DEFINE(struct pf_kanchor,          pf_main_anchor);
   73 
   74 static __inline int             pf_kanchor_compare(struct pf_kanchor *,
   75                                     struct pf_kanchor *);
   76 static struct pf_kanchor        *pf_find_kanchor(const char *);
   77 
   78 RB_GENERATE(pf_kanchor_global, pf_kanchor, entry_global, pf_kanchor_compare);
   79 RB_GENERATE(pf_kanchor_node, pf_kanchor, entry_node, pf_kanchor_compare);
   80 
   81 static __inline int
   82 pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
   83 {
   84         int c = strcmp(a->path, b->path);
   85 
   86         return (c ? (c < 0 ? -1 : 1) : 0);
   87 }
   88 
   89 int
   90 pf_get_ruleset_number(u_int8_t action)
   91 {
   92         switch (action) {
   93         case PF_SCRUB:
   94         case PF_NOSCRUB:
   95                 return (PF_RULESET_SCRUB);
   96                 break;
   97         case PF_PASS:
   98         case PF_MATCH:
   99         case PF_DROP:
  100                 return (PF_RULESET_FILTER);
  101                 break;
  102         case PF_NAT:
  103         case PF_NONAT:
  104                 return (PF_RULESET_NAT);
  105                 break;
  106         case PF_BINAT:
  107         case PF_NOBINAT:
  108                 return (PF_RULESET_BINAT);
  109                 break;
  110         case PF_RDR:
  111         case PF_NORDR:
  112                 return (PF_RULESET_RDR);
  113                 break;
  114         default:
  115                 return (PF_RULESET_MAX);
  116                 break;
  117         }
  118 }
  119 
  120 static struct pf_kanchor *
  121 pf_find_kanchor(const char *path)
  122 {
  123         struct pf_kanchor       *key, *found;
  124 
  125         key = (struct pf_kanchor *)rs_malloc(sizeof(*key));
  126         if (key == NULL)
  127                 return (NULL);
  128         strlcpy(key->path, path, sizeof(key->path));
  129         found = RB_FIND(pf_kanchor_global, &V_pf_anchors, key);
  130         rs_free(key);
  131         return (found);
  132 }
  133 
  134 void
  135 pf_init_kruleset(struct pf_kruleset *ruleset)
  136 {
  137         int     i;
  138 
  139         memset(ruleset, 0, sizeof(struct pf_kruleset));
  140         for (i = 0; i < PF_RULESET_MAX; i++) {
  141                 TAILQ_INIT(&ruleset->rules[i].queues[0]);
  142                 TAILQ_INIT(&ruleset->rules[i].queues[1]);
  143                 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
  144                 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
  145         }
  146 }
  147 
  148 struct pf_kruleset *
  149 pf_find_kruleset(const char *path)
  150 {
  151         struct pf_kanchor       *anchor;
  152 
  153         while (*path == '/')
  154                 path++;
  155         if (!*path)
  156                 return (&pf_main_ruleset);
  157         anchor = pf_find_kanchor(path);
  158         if (anchor == NULL)
  159                 return (NULL);
  160         else
  161                 return (&anchor->ruleset);
  162 }
  163 
  164 struct pf_kruleset *
  165 pf_find_or_create_kruleset(const char *path)
  166 {
  167         char                    *p, *q, *r;
  168         struct pf_kruleset      *ruleset;
  169         struct pf_kanchor       *anchor = NULL, *dup, *parent = NULL;
  170 
  171         if (path[0] == 0)
  172                 return (&pf_main_ruleset);
  173         while (*path == '/')
  174                 path++;
  175         ruleset = pf_find_kruleset(path);
  176         if (ruleset != NULL)
  177                 return (ruleset);
  178         p = (char *)rs_malloc(MAXPATHLEN);
  179         if (p == NULL)
  180                 return (NULL);
  181         strlcpy(p, path, MAXPATHLEN);
  182         while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
  183                 *q = 0;
  184                 if ((ruleset = pf_find_kruleset(p)) != NULL) {
  185                         parent = ruleset->anchor;
  186                         break;
  187                 }
  188         }
  189         if (q == NULL)
  190                 q = p;
  191         else
  192                 q++;
  193         strlcpy(p, path, MAXPATHLEN);
  194         if (!*q) {
  195                 rs_free(p);
  196                 return (NULL);
  197         }
  198         while ((r = strchr(q, '/')) != NULL || *q) {
  199                 if (r != NULL)
  200                         *r = 0;
  201                 if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
  202                     (parent != NULL && strlen(parent->path) >=
  203                     MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
  204                         rs_free(p);
  205                         return (NULL);
  206                 }
  207                 anchor = (struct pf_kanchor *)rs_malloc(sizeof(*anchor));
  208                 if (anchor == NULL) {
  209                         rs_free(p);
  210                         return (NULL);
  211                 }
  212                 RB_INIT(&anchor->children);
  213                 strlcpy(anchor->name, q, sizeof(anchor->name));
  214                 if (parent != NULL) {
  215                         strlcpy(anchor->path, parent->path,
  216                             sizeof(anchor->path));
  217                         strlcat(anchor->path, "/", sizeof(anchor->path));
  218                 }
  219                 strlcat(anchor->path, anchor->name, sizeof(anchor->path));
  220                 if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
  221                     NULL) {
  222                         printf("pf_find_or_create_ruleset: RB_INSERT1 "
  223                             "'%s' '%s' collides with '%s' '%s'\n",
  224                             anchor->path, anchor->name, dup->path, dup->name);
  225                         rs_free(anchor);
  226                         rs_free(p);
  227                         return (NULL);
  228                 }
  229                 if (parent != NULL) {
  230                         anchor->parent = parent;
  231                         if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
  232                             anchor)) != NULL) {
  233                                 printf("pf_find_or_create_ruleset: "
  234                                     "RB_INSERT2 '%s' '%s' collides with "
  235                                     "'%s' '%s'\n", anchor->path, anchor->name,
  236                                     dup->path, dup->name);
  237                                 RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
  238                                     anchor);
  239                                 rs_free(anchor);
  240                                 rs_free(p);
  241                                 return (NULL);
  242                         }
  243                 }
  244                 pf_init_kruleset(&anchor->ruleset);
  245                 anchor->ruleset.anchor = anchor;
  246                 parent = anchor;
  247                 if (r != NULL)
  248                         q = r + 1;
  249                 else
  250                         *q = 0;
  251         }
  252         rs_free(p);
  253         return (&anchor->ruleset);
  254 }
  255 
  256 void
  257 pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
  258 {
  259         struct pf_kanchor       *parent;
  260         int                      i;
  261 
  262         while (ruleset != NULL) {
  263                 if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
  264                     !RB_EMPTY(&ruleset->anchor->children) ||
  265                     ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
  266                     ruleset->topen)
  267                         return;
  268                 for (i = 0; i < PF_RULESET_MAX; ++i)
  269                         if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
  270                             !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
  271                             ruleset->rules[i].inactive.open)
  272                                 return;
  273                 RB_REMOVE(pf_kanchor_global, &V_pf_anchors, ruleset->anchor);
  274                 if ((parent = ruleset->anchor->parent) != NULL)
  275                         RB_REMOVE(pf_kanchor_node, &parent->children,
  276                             ruleset->anchor);
  277                 rs_free(ruleset->anchor);
  278                 if (parent == NULL)
  279                         return;
  280                 ruleset = &parent->ruleset;
  281         }
  282 }
  283 
  284 int
  285 pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
  286     const char *name)
  287 {
  288         char                    *p, *path;
  289         struct pf_kruleset      *ruleset;
  290 
  291         r->anchor = NULL;
  292         r->anchor_relative = 0;
  293         r->anchor_wildcard = 0;
  294         if (!name[0])
  295                 return (0);
  296         path = (char *)rs_malloc(MAXPATHLEN);
  297         if (path == NULL)
  298                 return (1);
  299         if (name[0] == '/')
  300                 strlcpy(path, name + 1, MAXPATHLEN);
  301         else {
  302                 /* relative path */
  303                 r->anchor_relative = 1;
  304                 if (s->anchor == NULL || !s->anchor->path[0])
  305                         path[0] = 0;
  306                 else
  307                         strlcpy(path, s->anchor->path, MAXPATHLEN);
  308                 while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
  309                         if (!path[0]) {
  310                                 DPFPRINTF("pf_anchor_setup: .. beyond root\n");
  311                                 rs_free(path);
  312                                 return (1);
  313                         }
  314                         if ((p = strrchr(path, '/')) != NULL)
  315                                 *p = 0;
  316                         else
  317                                 path[0] = 0;
  318                         r->anchor_relative++;
  319                         name += 3;
  320                 }
  321                 if (path[0])
  322                         strlcat(path, "/", MAXPATHLEN);
  323                 strlcat(path, name, MAXPATHLEN);
  324         }
  325         if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
  326                 r->anchor_wildcard = 1;
  327                 *p = 0;
  328         }
  329         ruleset = pf_find_or_create_kruleset(path);
  330         rs_free(path);
  331         if (ruleset == NULL || ruleset->anchor == NULL) {
  332                 DPFPRINTF("pf_anchor_setup: ruleset\n");
  333                 return (1);
  334         }
  335         r->anchor = ruleset->anchor;
  336         r->anchor->refcnt++;
  337         return (0);
  338 }
  339 
  340 int
  341 pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
  342     nvlist_t *nvl)
  343 {
  344         char anchor_call[MAXPATHLEN] = { 0 };
  345 
  346         if (r->anchor == NULL)
  347                 goto done;
  348         if (!r->anchor_relative) {
  349                 strlcpy(anchor_call, "/", sizeof(anchor_call));
  350                 strlcat(anchor_call, r->anchor->path,
  351                     sizeof(anchor_call));
  352         } else {
  353                 char     a[MAXPATHLEN];
  354                 char    *p;
  355                 int      i;
  356                 if (rs->anchor == NULL)
  357                         a[0] = 0;
  358                 else
  359                         strlcpy(a, rs->anchor->path, MAXPATHLEN);
  360                 for (i = 1; i < r->anchor_relative; ++i) {
  361                         if ((p = strrchr(a, '/')) == NULL)
  362                                 p = a;
  363                         *p = 0;
  364                         strlcat(anchor_call, "../",
  365                             sizeof(anchor_call));
  366                 }
  367                 if (strncmp(a, r->anchor->path, strlen(a))) {
  368                         printf("pf_anchor_copyout: '%s' '%s'\n", a,
  369                             r->anchor->path);
  370                         return (1);
  371                 }
  372                 if (strlen(r->anchor->path) > strlen(a))
  373                         strlcat(anchor_call, r->anchor->path + (a[0] ?
  374                             strlen(a) + 1 : 0), sizeof(anchor_call));
  375 
  376         }
  377         if (r->anchor_wildcard)
  378                 strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
  379                     sizeof(anchor_call));
  380 
  381 done:
  382         nvlist_add_string(nvl, "anchor_call", anchor_call);
  383 
  384         return (0);
  385 }
  386 
  387 int
  388 pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
  389     struct pfioc_rule *pr)
  390 {
  391         pr->anchor_call[0] = 0;
  392         if (r->anchor == NULL)
  393                 return (0);
  394         if (!r->anchor_relative) {
  395                 strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
  396                 strlcat(pr->anchor_call, r->anchor->path,
  397                     sizeof(pr->anchor_call));
  398         } else {
  399                 char    *a, *p;
  400                 int      i;
  401 
  402                 a = (char *)rs_malloc(MAXPATHLEN);
  403                 if (a == NULL)
  404                         return (1);
  405                 if (rs->anchor == NULL)
  406                         a[0] = 0;
  407                 else
  408                         strlcpy(a, rs->anchor->path, MAXPATHLEN);
  409                 for (i = 1; i < r->anchor_relative; ++i) {
  410                         if ((p = strrchr(a, '/')) == NULL)
  411                                 p = a;
  412                         *p = 0;
  413                         strlcat(pr->anchor_call, "../",
  414                             sizeof(pr->anchor_call));
  415                 }
  416                 if (strncmp(a, r->anchor->path, strlen(a))) {
  417                         printf("pf_anchor_copyout: '%s' '%s'\n", a,
  418                             r->anchor->path);
  419                         rs_free(a);
  420                         return (1);
  421                 }
  422                 if (strlen(r->anchor->path) > strlen(a))
  423                         strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
  424                             strlen(a) + 1 : 0), sizeof(pr->anchor_call));
  425                 rs_free(a);
  426         }
  427         if (r->anchor_wildcard)
  428                 strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
  429                     sizeof(pr->anchor_call));
  430         return (0);
  431 }
  432 
  433 void
  434 pf_kanchor_remove(struct pf_krule *r)
  435 {
  436         if (r->anchor == NULL)
  437                 return;
  438         if (r->anchor->refcnt <= 0) {
  439                 printf("pf_anchor_remove: broken refcount\n");
  440                 r->anchor = NULL;
  441                 return;
  442         }
  443         if (!--r->anchor->refcnt)
  444                 pf_remove_if_empty_kruleset(&r->anchor->ruleset);
  445         r->anchor = NULL;
  446 }

Cache object: 32d79fdbf59951a382de05dbd5c15e7f


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