LCOV - code coverage report
Current view: top level - net - pf_ruleset.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 211 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: pf_ruleset.c,v 1.16 2017/09/05 22:15:32 sashan Exp $ */
       2             : 
       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             :  */
      37             : 
      38             : #include <sys/param.h>
      39             : #include <sys/socket.h>
      40             : #ifdef _KERNEL
      41             : #include <sys/systm.h>
      42             : #include <sys/mbuf.h>
      43             : #endif /* _KERNEL */
      44             : #include <sys/syslog.h>
      45             : 
      46             : #include <netinet/in.h>
      47             : #include <netinet/ip.h>
      48             : #include <netinet/tcp.h>
      49             : 
      50             : #include <net/if.h>
      51             : #include <net/pfvar.h>
      52             : 
      53             : #ifdef INET6
      54             : #include <netinet/ip6.h>
      55             : #endif /* INET6 */
      56             : 
      57             : 
      58             : #ifdef _KERNEL
      59             : #define rs_malloc(x)            malloc(x, M_TEMP, M_WAITOK|M_CANFAIL|M_ZERO)
      60             : #define rs_free(x, siz)         free(x, M_TEMP, siz)
      61             : 
      62             : #else   /* !_KERNEL */
      63             : /* Userland equivalents so we can lend code to pfctl et al. */
      64             : 
      65             : #include <arpa/inet.h>
      66             : #include <errno.h>
      67             : #include <stdio.h>
      68             : #include <stdlib.h>
      69             : #include <string.h>
      70             : #define rs_malloc(x)             calloc(1, x)
      71             : #define rs_free(x, siz)          freezero(x, siz)
      72             : 
      73             : #ifdef PFDEBUG
      74             : #include <sys/stdarg.h>   /* for DPFPRINTF() */
      75             : #endif  /* PFDEBUG */
      76             : #endif /* _KERNEL */
      77             : 
      78             : 
      79             : struct pf_anchor_global  pf_anchors;
      80             : struct pf_anchor         pf_main_anchor;
      81             : 
      82             : static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
      83             : 
      84           0 : RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
      85           0 : RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
      86             : 
      87             : static __inline int
      88           0 : pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
      89             : {
      90           0 :         int c = strcmp(a->path, b->path);
      91             : 
      92           0 :         return (c ? (c < 0 ? -1 : 1) : 0);
      93             : }
      94             : 
      95             : void
      96           0 : pf_init_ruleset(struct pf_ruleset *ruleset)
      97             : {
      98           0 :         memset(ruleset, 0, sizeof(struct pf_ruleset));
      99           0 :         TAILQ_INIT(&ruleset->rules.queues[0]);
     100           0 :         TAILQ_INIT(&ruleset->rules.queues[1]);
     101           0 :         ruleset->rules.active.ptr = &ruleset->rules.queues[0];
     102           0 :         ruleset->rules.inactive.ptr = &ruleset->rules.queues[1];
     103           0 : }
     104             : 
     105             : struct pf_anchor *
     106           0 : pf_find_anchor(const char *path)
     107             : {
     108             :         struct pf_anchor        *key, *found;
     109             : 
     110           0 :         key = rs_malloc(sizeof(*key));
     111           0 :         if (key == NULL)
     112           0 :                 return (NULL);
     113           0 :         strlcpy(key->path, path, sizeof(key->path));
     114           0 :         found = RB_FIND(pf_anchor_global, &pf_anchors, key);
     115           0 :         rs_free(key, sizeof(*key));
     116           0 :         return (found);
     117           0 : }
     118             : 
     119             : struct pf_ruleset *
     120           0 : pf_find_ruleset(const char *path)
     121             : {
     122             :         struct pf_anchor        *anchor;
     123             : 
     124           0 :         while (*path == '/')
     125           0 :                 path++;
     126           0 :         if (!*path)
     127           0 :                 return (&pf_main_ruleset);
     128           0 :         anchor = pf_find_anchor(path);
     129           0 :         if (anchor == NULL)
     130           0 :                 return (NULL);
     131             :         else
     132           0 :                 return (&anchor->ruleset);
     133           0 : }
     134             : 
     135             : struct pf_ruleset *
     136           0 : pf_get_leaf_ruleset(char *path, char **path_remainder)
     137             : {
     138             :         struct pf_ruleset       *ruleset;
     139             :         char                    *leaf, *p;
     140             :         int                      i = 0;
     141             : 
     142             :         p = path;
     143           0 :         while (*p == '/')
     144           0 :                 p++;
     145             : 
     146           0 :         ruleset = pf_find_ruleset(p);
     147             :         leaf = p;
     148           0 :         while (ruleset == NULL) {
     149           0 :                 leaf = strrchr(p, '/');
     150           0 :                 if (leaf != NULL) {
     151           0 :                         *leaf = '\0';
     152           0 :                         i++;
     153           0 :                         ruleset = pf_find_ruleset(p);
     154           0 :                 } else {
     155             :                         leaf = path;
     156             :                         /*
     157             :                          * if no path component exists, then main ruleset is
     158             :                          * our parent.
     159             :                          */
     160             :                         ruleset = &pf_main_ruleset;
     161             :                 }
     162             :         }
     163             : 
     164           0 :         if (path_remainder != NULL)
     165           0 :                 *path_remainder = leaf;
     166             : 
     167             :         /* restore slashes in path.  */
     168           0 :         while (i != 0) {
     169           0 :                 while (*leaf != '\0')
     170           0 :                         leaf++;
     171           0 :                 *leaf = '/';
     172           0 :                 i--;
     173             :         }
     174             : 
     175           0 :         return (ruleset);
     176             : }
     177             : 
     178             : struct pf_anchor *
     179           0 : pf_create_anchor(struct pf_anchor *parent, const char *aname)
     180             : {
     181             :         struct pf_anchor        *anchor, *dup;
     182             : 
     183           0 :         if (!*aname || (strlen(aname) >= PF_ANCHOR_NAME_SIZE) ||
     184           0 :             ((parent != NULL) && (strlen(parent->path) >= PF_ANCHOR_MAXPATH)))
     185           0 :                 return (NULL);
     186             : 
     187           0 :         anchor = rs_malloc(sizeof(*anchor));
     188           0 :         if (anchor == NULL)
     189           0 :                 return (NULL);
     190             : 
     191           0 :         RB_INIT(&anchor->children);
     192           0 :         strlcpy(anchor->name, aname, sizeof(anchor->name));
     193           0 :         if (parent != NULL) {
     194             :                 /*
     195             :                  * Make sure path for levels 2, 3, ... is terminated by '/':
     196             :                  *      1/2/3/...
     197             :                  */
     198           0 :                 strlcpy(anchor->path, parent->path, sizeof(anchor->path));
     199           0 :                 strlcat(anchor->path, "/", sizeof(anchor->path));
     200           0 :         }
     201           0 :         strlcat(anchor->path, anchor->name, sizeof(anchor->path));
     202             : 
     203           0 :         if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) != NULL) {
     204           0 :                 DPFPRINTF(LOG_NOTICE,
     205             :                     "%s: RB_INSERT to global '%s' '%s' collides with '%s' '%s'",
     206             :                     __func__, anchor->path, anchor->name, dup->path, dup->name);
     207           0 :                 rs_free(anchor, sizeof(*anchor));
     208           0 :                 return (NULL);
     209             :         }
     210             : 
     211           0 :         if (parent != NULL) {
     212           0 :                 anchor->parent = parent;
     213           0 :                 dup = RB_INSERT(pf_anchor_node, &parent->children, anchor);
     214           0 :                 if (dup != NULL) {
     215           0 :                         DPFPRINTF(LOG_NOTICE,
     216             :                             "%s: RB_INSERT to parent '%s' '%s' collides with "
     217             :                             "'%s' '%s'", __func__, anchor->path, anchor->name,
     218             :                             dup->path, dup->name);
     219           0 :                         RB_REMOVE(pf_anchor_global, &pf_anchors,
     220             :                             anchor);
     221           0 :                         rs_free(anchor, sizeof(*anchor));
     222           0 :                         return (NULL);
     223             :                 }
     224             :         }
     225             : 
     226           0 :         pf_init_ruleset(&anchor->ruleset);
     227           0 :         anchor->ruleset.anchor = anchor;
     228             : 
     229           0 :         return (anchor);
     230           0 : }
     231             : 
     232             : struct pf_ruleset *
     233           0 : pf_find_or_create_ruleset(const char *path)
     234             : {
     235           0 :         char                    *p, *aname, *r;
     236             :         struct pf_ruleset       *ruleset;
     237             :         struct pf_anchor        *anchor;
     238             : 
     239           0 :         if (path[0] == 0)
     240           0 :                 return (&pf_main_ruleset);
     241             : 
     242           0 :         while (*path == '/')
     243           0 :                 path++;
     244             : 
     245           0 :         ruleset = pf_find_ruleset(path);
     246           0 :         if (ruleset != NULL)
     247           0 :                 return (ruleset);
     248             : 
     249           0 :         p = rs_malloc(MAXPATHLEN);
     250           0 :         if (p == NULL)
     251           0 :                 return (NULL);
     252           0 :         strlcpy(p, path, MAXPATHLEN);
     253             : 
     254           0 :         ruleset = pf_get_leaf_ruleset(p, &aname);
     255           0 :         anchor = ruleset->anchor;
     256             : 
     257           0 :         while (*aname == '/')
     258           0 :                 aname++;
     259             :         /*
     260             :          * aname is a path remainder, which contains nodes we must create.  We
     261             :          * process the aname path from left to right, effectively descending
     262             :          * from parents to children.
     263             :          */
     264           0 :         while ((r = strchr(aname, '/')) != NULL || *aname) {
     265           0 :                 if (r != NULL)
     266           0 :                         *r = 0;
     267             : 
     268           0 :                 anchor = pf_create_anchor(anchor, aname);
     269           0 :                 if (anchor == NULL) {
     270           0 :                         rs_free(p, MAXPATHLEN);
     271           0 :                         return (NULL);
     272             :                 }
     273             : 
     274           0 :                 if (r == NULL)
     275             :                         break;
     276             :                 else
     277           0 :                         aname = r + 1;
     278             :         }
     279             : 
     280           0 :         rs_free(p, MAXPATHLEN);
     281           0 :         return (&anchor->ruleset);
     282           0 : }
     283             : 
     284             : void
     285           0 : pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
     286             : {
     287             :         struct pf_anchor        *parent;
     288             : 
     289           0 :         while (ruleset != NULL) {
     290           0 :                 if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
     291           0 :                     !RB_EMPTY(&ruleset->anchor->children) ||
     292           0 :                     ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
     293           0 :                     ruleset->topen)
     294           0 :                         return;
     295           0 :                 if (!TAILQ_EMPTY(ruleset->rules.active.ptr) ||
     296           0 :                     !TAILQ_EMPTY(ruleset->rules.inactive.ptr) ||
     297           0 :                     ruleset->rules.inactive.open)
     298           0 :                         return;
     299           0 :                 RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
     300           0 :                 if ((parent = ruleset->anchor->parent) != NULL)
     301           0 :                         RB_REMOVE(pf_anchor_node, &parent->children,
     302             :                             ruleset->anchor);
     303           0 :                 rs_free(ruleset->anchor, sizeof(*(ruleset->anchor)));
     304           0 :                 if (parent == NULL)
     305           0 :                         return;
     306           0 :                 ruleset = &parent->ruleset;
     307             :         }
     308           0 : }
     309             : 
     310             : int
     311           0 : pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
     312             :     const char *name)
     313             : {
     314             :         char                    *p, *path;
     315             :         struct pf_ruleset       *ruleset;
     316             : 
     317           0 :         r->anchor = NULL;
     318           0 :         r->anchor_relative = 0;
     319           0 :         r->anchor_wildcard = 0;
     320           0 :         if (!name[0])
     321           0 :                 return (0);
     322           0 :         path = rs_malloc(MAXPATHLEN);
     323           0 :         if (path == NULL)
     324           0 :                 return (1);
     325           0 :         if (name[0] == '/')
     326           0 :                 strlcpy(path, name + 1, MAXPATHLEN);
     327             :         else {
     328             :                 /* relative path */
     329           0 :                 r->anchor_relative = 1;
     330           0 :                 if (s->anchor == NULL || !s->anchor->path[0])
     331           0 :                         path[0] = 0;
     332             :                 else
     333           0 :                         strlcpy(path, s->anchor->path, MAXPATHLEN);
     334           0 :                 while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
     335           0 :                         if (!path[0]) {
     336           0 :                                 DPFPRINTF(LOG_NOTICE,
     337             :                                     "pf_anchor_setup: .. beyond root");
     338           0 :                                 rs_free(path, MAXPATHLEN);
     339           0 :                                 return (1);
     340             :                         }
     341           0 :                         if ((p = strrchr(path, '/')) != NULL)
     342           0 :                                 *p = 0;
     343             :                         else
     344           0 :                                 path[0] = 0;
     345           0 :                         r->anchor_relative++;
     346           0 :                         name += 3;
     347             :                 }
     348           0 :                 if (path[0])
     349           0 :                         strlcat(path, "/", MAXPATHLEN);
     350           0 :                 strlcat(path, name, MAXPATHLEN);
     351             :         }
     352           0 :         if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
     353           0 :                 r->anchor_wildcard = 1;
     354           0 :                 *p = 0;
     355           0 :         }
     356           0 :         ruleset = pf_find_or_create_ruleset(path);
     357           0 :         rs_free(path, MAXPATHLEN);
     358           0 :         if (ruleset == NULL || ruleset->anchor == NULL) {
     359           0 :                 DPFPRINTF(LOG_NOTICE,
     360             :                     "pf_anchor_setup: ruleset");
     361           0 :                 return (1);
     362             :         }
     363           0 :         r->anchor = ruleset->anchor;
     364           0 :         r->anchor->refcnt++;
     365           0 :         return (0);
     366           0 : }
     367             : 
     368             : int
     369           0 : pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
     370             :     struct pfioc_rule *pr)
     371             : {
     372           0 :         pr->anchor_call[0] = 0;
     373           0 :         if (r->anchor == NULL)
     374           0 :                 return (0);
     375           0 :         if (!r->anchor_relative) {
     376           0 :                 strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
     377           0 :                 strlcat(pr->anchor_call, r->anchor->path,
     378             :                     sizeof(pr->anchor_call));
     379           0 :         } else {
     380             :                 char    *a, *p;
     381             :                 int      i;
     382             : 
     383           0 :                 a = rs_malloc(MAXPATHLEN);
     384           0 :                 if (a == NULL)
     385           0 :                         return (1);
     386           0 :                 if (rs->anchor == NULL)
     387           0 :                         a[0] = 0;
     388             :                 else
     389           0 :                         strlcpy(a, rs->anchor->path, MAXPATHLEN);
     390           0 :                 for (i = 1; i < r->anchor_relative; ++i) {
     391           0 :                         if ((p = strrchr(a, '/')) == NULL)
     392           0 :                                 p = a;
     393           0 :                         *p = 0;
     394           0 :                         strlcat(pr->anchor_call, "../",
     395             :                             sizeof(pr->anchor_call));
     396             :                 }
     397           0 :                 if (strncmp(a, r->anchor->path, strlen(a))) {
     398           0 :                         DPFPRINTF(LOG_NOTICE,
     399             :                             "pf_anchor_copyout: '%s' '%s'", a,
     400             :                             r->anchor->path);
     401           0 :                         rs_free(a, MAXPATHLEN);
     402           0 :                         return (1);
     403             :                 }
     404           0 :                 if (strlen(r->anchor->path) > strlen(a))
     405           0 :                         strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
     406           0 :                             strlen(a) + 1 : 0), sizeof(pr->anchor_call));
     407           0 :                 rs_free(a, MAXPATHLEN);
     408           0 :         }
     409           0 :         if (r->anchor_wildcard)
     410           0 :                 strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
     411             :                     sizeof(pr->anchor_call));
     412           0 :         return (0);
     413           0 : }
     414             : 
     415             : void
     416           0 : pf_anchor_remove(struct pf_rule *r)
     417             : {
     418           0 :         if (r->anchor == NULL)
     419             :                 return;
     420           0 :         if (r->anchor->refcnt <= 0) {
     421           0 :                 DPFPRINTF(LOG_NOTICE,
     422             :                     "pf_anchor_remove: broken refcount");
     423           0 :                 r->anchor = NULL;
     424           0 :                 return;
     425             :         }
     426           0 :         if (!--r->anchor->refcnt)
     427           0 :                 pf_remove_if_empty_ruleset(&r->anchor->ruleset);
     428           0 :         r->anchor = NULL;
     429           0 : }

Generated by: LCOV version 1.13