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

Cache object: d8867f72553bb75b048384520629f01a


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