1*062cda8bSmvs /* $OpenBSD: pf_ruleset.c,v 1.21 2023/06/30 09:58:30 mvs Exp $ */
26a21d20bSmcbride
36a21d20bSmcbride /*
46a21d20bSmcbride * Copyright (c) 2001 Daniel Hartmeier
56a21d20bSmcbride * Copyright (c) 2002,2003 Henning Brauer
66a21d20bSmcbride * All rights reserved.
76a21d20bSmcbride *
86a21d20bSmcbride * Redistribution and use in source and binary forms, with or without
96a21d20bSmcbride * modification, are permitted provided that the following conditions
106a21d20bSmcbride * are met:
116a21d20bSmcbride *
126a21d20bSmcbride * - Redistributions of source code must retain the above copyright
136a21d20bSmcbride * notice, this list of conditions and the following disclaimer.
146a21d20bSmcbride * - Redistributions in binary form must reproduce the above
156a21d20bSmcbride * copyright notice, this list of conditions and the following
166a21d20bSmcbride * disclaimer in the documentation and/or other materials provided
176a21d20bSmcbride * with the distribution.
186a21d20bSmcbride *
196a21d20bSmcbride * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
206a21d20bSmcbride * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
216a21d20bSmcbride * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
226a21d20bSmcbride * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
236a21d20bSmcbride * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
246a21d20bSmcbride * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
256a21d20bSmcbride * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
266a21d20bSmcbride * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
276a21d20bSmcbride * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286a21d20bSmcbride * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
296a21d20bSmcbride * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
306a21d20bSmcbride * POSSIBILITY OF SUCH DAMAGE.
316a21d20bSmcbride *
326a21d20bSmcbride * Effort sponsored in part by the Defense Advanced Research Projects
336a21d20bSmcbride * Agency (DARPA) and Air Force Research Laboratory, Air Force
346a21d20bSmcbride * Materiel Command, USAF, under agreement number F30602-01-2-0537.
356a21d20bSmcbride *
366a21d20bSmcbride */
376a21d20bSmcbride
386a21d20bSmcbride #include <sys/param.h>
396a21d20bSmcbride #include <sys/socket.h>
406a21d20bSmcbride #ifdef _KERNEL
416a21d20bSmcbride #include <sys/systm.h>
426a21d20bSmcbride #include <sys/mbuf.h>
43fa90ac5cSmbuhl #include <sys/pool.h>
448d0493f3Sderaadt #endif /* _KERNEL */
45a2fdc13dSmcbride #include <sys/syslog.h>
466a21d20bSmcbride
476a21d20bSmcbride #include <netinet/in.h>
486a21d20bSmcbride #include <netinet/ip.h>
496a21d20bSmcbride #include <netinet/tcp.h>
506a21d20bSmcbride
516a21d20bSmcbride #include <net/if.h>
526a21d20bSmcbride #include <net/pfvar.h>
536a21d20bSmcbride
546a21d20bSmcbride #ifdef INET6
556a21d20bSmcbride #include <netinet/ip6.h>
566a21d20bSmcbride #endif /* INET6 */
576a21d20bSmcbride
586a21d20bSmcbride
596a21d20bSmcbride #ifdef _KERNEL
60*062cda8bSmvs #define rs_malloc(x) malloc(x, M_PF, M_WAITOK|M_CANFAIL|M_ZERO)
61*062cda8bSmvs #define rs_free(x, siz) free(x, M_PF, siz)
62fa90ac5cSmbuhl #define rs_pool_get_anchor() pool_get(&pf_anchor_pl, \
63fa90ac5cSmbuhl PR_WAITOK|PR_LIMITFAIL|PR_ZERO)
64fa90ac5cSmbuhl #define rs_pool_put_anchor(x) pool_put(&pf_anchor_pl, x)
65fa90ac5cSmbuhl
66fa90ac5cSmbuhl struct pool pf_anchor_pl;
676a21d20bSmcbride
68ecaa3a52Ssashan #else /* !_KERNEL */
696a21d20bSmcbride /* Userland equivalents so we can lend code to pfctl et al. */
706a21d20bSmcbride
716a21d20bSmcbride #include <arpa/inet.h>
726a21d20bSmcbride #include <errno.h>
736a21d20bSmcbride #include <stdio.h>
746a21d20bSmcbride #include <stdlib.h>
756a21d20bSmcbride #include <string.h>
766a95758eSthib #define rs_malloc(x) calloc(1, x)
776338263fSderaadt #define rs_free(x, siz) freezero(x, siz)
78fa90ac5cSmbuhl #define rs_pool_get_anchor() calloc(1, sizeof(struct pf_anchor))
79fa90ac5cSmbuhl #define rs_pool_put_anchor(x) freezero(x, sizeof(struct pf_anchor))
806a21d20bSmcbride
816a21d20bSmcbride #ifdef PFDEBUG
82a2fdc13dSmcbride #include <sys/stdarg.h> /* for DPFPRINTF() */
83ecaa3a52Ssashan #endif /* PFDEBUG */
846a21d20bSmcbride #endif /* _KERNEL */
856a21d20bSmcbride
866a21d20bSmcbride
876a21d20bSmcbride struct pf_anchor_global pf_anchors;
886a21d20bSmcbride struct pf_anchor pf_main_anchor;
896a21d20bSmcbride
90342c264fSdlg static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
916a21d20bSmcbride
92342c264fSdlg RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
93342c264fSdlg RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
946a21d20bSmcbride
956a21d20bSmcbride static __inline int
pf_anchor_compare(struct pf_anchor * a,struct pf_anchor * b)96342c264fSdlg pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
976a21d20bSmcbride {
986a21d20bSmcbride int c = strcmp(a->path, b->path);
996a21d20bSmcbride
1006a21d20bSmcbride return (c ? (c < 0 ? -1 : 1) : 0);
1016a21d20bSmcbride }
1026a21d20bSmcbride
1036a21d20bSmcbride void
pf_init_ruleset(struct pf_ruleset * ruleset)1046a21d20bSmcbride pf_init_ruleset(struct pf_ruleset *ruleset)
1056a21d20bSmcbride {
1066a21d20bSmcbride memset(ruleset, 0, sizeof(struct pf_ruleset));
1079f66a89aShenning TAILQ_INIT(&ruleset->rules.queues[0]);
1089f66a89aShenning TAILQ_INIT(&ruleset->rules.queues[1]);
1099f66a89aShenning ruleset->rules.active.ptr = &ruleset->rules.queues[0];
1109f66a89aShenning ruleset->rules.inactive.ptr = &ruleset->rules.queues[1];
1116a21d20bSmcbride }
1126a21d20bSmcbride
1136a21d20bSmcbride struct pf_anchor *
pf_find_anchor(const char * path)1146a21d20bSmcbride pf_find_anchor(const char *path)
1156a21d20bSmcbride {
1166a21d20bSmcbride struct pf_anchor *key, *found;
1176a21d20bSmcbride
118eacdf23bSmmcc key = rs_malloc(sizeof(*key));
1196a95758eSthib if (key == NULL)
1206a95758eSthib return (NULL);
1216a21d20bSmcbride strlcpy(key->path, path, sizeof(key->path));
122342c264fSdlg found = RB_FIND(pf_anchor_global, &pf_anchors, key);
1236338263fSderaadt rs_free(key, sizeof(*key));
1246a21d20bSmcbride return (found);
1256a21d20bSmcbride }
1266a21d20bSmcbride
1276a21d20bSmcbride struct pf_ruleset *
pf_find_ruleset(const char * path)1286a21d20bSmcbride pf_find_ruleset(const char *path)
1296a21d20bSmcbride {
1306a21d20bSmcbride struct pf_anchor *anchor;
1316a21d20bSmcbride
1326a21d20bSmcbride while (*path == '/')
1336a21d20bSmcbride path++;
1346a21d20bSmcbride if (!*path)
1356a21d20bSmcbride return (&pf_main_ruleset);
1366a21d20bSmcbride anchor = pf_find_anchor(path);
1376a21d20bSmcbride if (anchor == NULL)
1386a21d20bSmcbride return (NULL);
1396a21d20bSmcbride else
1406a21d20bSmcbride return (&anchor->ruleset);
1416a21d20bSmcbride }
1426a21d20bSmcbride
1436a21d20bSmcbride struct pf_ruleset *
pf_get_leaf_ruleset(char * path,char ** path_remainder)1440d5abfc5Ssashan pf_get_leaf_ruleset(char *path, char **path_remainder)
1456a21d20bSmcbride {
1466a21d20bSmcbride struct pf_ruleset *ruleset;
1470d5abfc5Ssashan char *leaf, *p;
1480d5abfc5Ssashan int i = 0;
1496a21d20bSmcbride
1500d5abfc5Ssashan p = path;
1510d5abfc5Ssashan while (*p == '/')
1520d5abfc5Ssashan p++;
1530d5abfc5Ssashan
1540d5abfc5Ssashan ruleset = pf_find_ruleset(p);
1550d5abfc5Ssashan leaf = p;
1560d5abfc5Ssashan while (ruleset == NULL) {
1570d5abfc5Ssashan leaf = strrchr(p, '/');
1580d5abfc5Ssashan if (leaf != NULL) {
1590d5abfc5Ssashan *leaf = '\0';
1600d5abfc5Ssashan i++;
1610d5abfc5Ssashan ruleset = pf_find_ruleset(p);
1620d5abfc5Ssashan } else {
1630d5abfc5Ssashan leaf = path;
1640d5abfc5Ssashan /*
1650d5abfc5Ssashan * if no path component exists, then main ruleset is
1660d5abfc5Ssashan * our parent.
1670d5abfc5Ssashan */
1680d5abfc5Ssashan ruleset = &pf_main_ruleset;
1690d5abfc5Ssashan }
1700d5abfc5Ssashan }
1710d5abfc5Ssashan
1720d5abfc5Ssashan if (path_remainder != NULL)
1730d5abfc5Ssashan *path_remainder = leaf;
1740d5abfc5Ssashan
1750d5abfc5Ssashan /* restore slashes in path. */
1760d5abfc5Ssashan while (i != 0) {
1770d5abfc5Ssashan while (*leaf != '\0')
1780d5abfc5Ssashan leaf++;
1790d5abfc5Ssashan *leaf = '/';
1800d5abfc5Ssashan i--;
1810d5abfc5Ssashan }
1820d5abfc5Ssashan
1836a21d20bSmcbride return (ruleset);
1840d5abfc5Ssashan }
1850d5abfc5Ssashan
1860d5abfc5Ssashan struct pf_anchor *
pf_create_anchor(struct pf_anchor * parent,const char * aname)1870d5abfc5Ssashan pf_create_anchor(struct pf_anchor *parent, const char *aname)
1880d5abfc5Ssashan {
1890d5abfc5Ssashan struct pf_anchor *anchor, *dup;
1900d5abfc5Ssashan
1910d5abfc5Ssashan if (!*aname || (strlen(aname) >= PF_ANCHOR_NAME_SIZE) ||
1920d5abfc5Ssashan ((parent != NULL) && (strlen(parent->path) >= PF_ANCHOR_MAXPATH)))
1936a95758eSthib return (NULL);
1940d5abfc5Ssashan
195fa90ac5cSmbuhl anchor = rs_pool_get_anchor();
1960d5abfc5Ssashan if (anchor == NULL)
1976a21d20bSmcbride return (NULL);
1980d5abfc5Ssashan
199342c264fSdlg RB_INIT(&anchor->children);
2000d5abfc5Ssashan strlcpy(anchor->name, aname, sizeof(anchor->name));
2016a21d20bSmcbride if (parent != NULL) {
2020d5abfc5Ssashan /*
2030d5abfc5Ssashan * Make sure path for levels 2, 3, ... is terminated by '/':
2040d5abfc5Ssashan * 1/2/3/...
2050d5abfc5Ssashan */
2060d5abfc5Ssashan strlcpy(anchor->path, parent->path, sizeof(anchor->path));
2076a21d20bSmcbride strlcat(anchor->path, "/", sizeof(anchor->path));
2086a21d20bSmcbride }
2096a21d20bSmcbride strlcat(anchor->path, anchor->name, sizeof(anchor->path));
2100d5abfc5Ssashan
2110d5abfc5Ssashan if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) != NULL) {
212a2fdc13dSmcbride DPFPRINTF(LOG_NOTICE,
2130d5abfc5Ssashan "%s: RB_INSERT to global '%s' '%s' collides with '%s' '%s'",
2140d5abfc5Ssashan __func__, anchor->path, anchor->name, dup->path, dup->name);
215fa90ac5cSmbuhl rs_pool_put_anchor(anchor);
2166a21d20bSmcbride return (NULL);
2176a21d20bSmcbride }
2180d5abfc5Ssashan
2196a21d20bSmcbride if (parent != NULL) {
2206a21d20bSmcbride anchor->parent = parent;
2210d5abfc5Ssashan dup = RB_INSERT(pf_anchor_node, &parent->children, anchor);
2220d5abfc5Ssashan if (dup != NULL) {
223a2fdc13dSmcbride DPFPRINTF(LOG_NOTICE,
2240d5abfc5Ssashan "%s: RB_INSERT to parent '%s' '%s' collides with "
2250d5abfc5Ssashan "'%s' '%s'", __func__, anchor->path, anchor->name,
2266a21d20bSmcbride dup->path, dup->name);
227342c264fSdlg RB_REMOVE(pf_anchor_global, &pf_anchors,
2286a21d20bSmcbride anchor);
229fa90ac5cSmbuhl rs_pool_put_anchor(anchor);
2306a21d20bSmcbride return (NULL);
2316a21d20bSmcbride }
2326a21d20bSmcbride }
2330d5abfc5Ssashan
2346a21d20bSmcbride pf_init_ruleset(&anchor->ruleset);
2356a21d20bSmcbride anchor->ruleset.anchor = anchor;
236072583c9Ssashan #ifdef _KERNEL
237072583c9Ssashan refcnt_init(&anchor->ref);
238072583c9Ssashan #endif
2390d5abfc5Ssashan
2400d5abfc5Ssashan return (anchor);
2416a21d20bSmcbride }
2420d5abfc5Ssashan
2430d5abfc5Ssashan struct pf_ruleset *
pf_find_or_create_ruleset(const char * path)2440d5abfc5Ssashan pf_find_or_create_ruleset(const char *path)
2450d5abfc5Ssashan {
2460d5abfc5Ssashan char *p, *aname, *r;
2470d5abfc5Ssashan struct pf_ruleset *ruleset;
2480d5abfc5Ssashan struct pf_anchor *anchor;
2490d5abfc5Ssashan
2500d5abfc5Ssashan if (path[0] == 0)
2510d5abfc5Ssashan return (&pf_main_ruleset);
2520d5abfc5Ssashan
2530d5abfc5Ssashan while (*path == '/')
2540d5abfc5Ssashan path++;
2550d5abfc5Ssashan
2560d5abfc5Ssashan ruleset = pf_find_ruleset(path);
2570d5abfc5Ssashan if (ruleset != NULL)
2580d5abfc5Ssashan return (ruleset);
2590d5abfc5Ssashan
2600d5abfc5Ssashan p = rs_malloc(MAXPATHLEN);
2610d5abfc5Ssashan if (p == NULL)
2620d5abfc5Ssashan return (NULL);
2630d5abfc5Ssashan strlcpy(p, path, MAXPATHLEN);
2640d5abfc5Ssashan
2650d5abfc5Ssashan ruleset = pf_get_leaf_ruleset(p, &aname);
2660d5abfc5Ssashan anchor = ruleset->anchor;
2670d5abfc5Ssashan
2680d5abfc5Ssashan while (*aname == '/')
2690d5abfc5Ssashan aname++;
2700d5abfc5Ssashan /*
2710d5abfc5Ssashan * aname is a path remainder, which contains nodes we must create. We
2720d5abfc5Ssashan * process the aname path from left to right, effectively descending
2730d5abfc5Ssashan * from parents to children.
2740d5abfc5Ssashan */
2750d5abfc5Ssashan while ((r = strchr(aname, '/')) != NULL || *aname) {
2760d5abfc5Ssashan if (r != NULL)
2770d5abfc5Ssashan *r = 0;
2780d5abfc5Ssashan
2790d5abfc5Ssashan anchor = pf_create_anchor(anchor, aname);
2800d5abfc5Ssashan if (anchor == NULL) {
2810d5abfc5Ssashan rs_free(p, MAXPATHLEN);
2820d5abfc5Ssashan return (NULL);
2830d5abfc5Ssashan }
2840d5abfc5Ssashan
2850d5abfc5Ssashan if (r == NULL)
2860d5abfc5Ssashan break;
2870d5abfc5Ssashan else
2880d5abfc5Ssashan aname = r + 1;
2890d5abfc5Ssashan }
2900d5abfc5Ssashan
2916338263fSderaadt rs_free(p, MAXPATHLEN);
2926a21d20bSmcbride return (&anchor->ruleset);
2936a21d20bSmcbride }
2946a21d20bSmcbride
2956a21d20bSmcbride void
pf_remove_if_empty_ruleset(struct pf_ruleset * ruleset)2966a21d20bSmcbride pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
2976a21d20bSmcbride {
2986a21d20bSmcbride struct pf_anchor *parent;
2996a21d20bSmcbride
3006a21d20bSmcbride while (ruleset != NULL) {
30155038654Skn if (ruleset == &pf_main_ruleset ||
302342c264fSdlg !RB_EMPTY(&ruleset->anchor->children) ||
3036a21d20bSmcbride ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
3046a21d20bSmcbride ruleset->topen)
3056a21d20bSmcbride return;
3069f66a89aShenning if (!TAILQ_EMPTY(ruleset->rules.active.ptr) ||
3079f66a89aShenning !TAILQ_EMPTY(ruleset->rules.inactive.ptr) ||
3089f66a89aShenning ruleset->rules.inactive.open)
3096a21d20bSmcbride return;
310342c264fSdlg RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
3116a21d20bSmcbride if ((parent = ruleset->anchor->parent) != NULL)
312342c264fSdlg RB_REMOVE(pf_anchor_node, &parent->children,
3136a21d20bSmcbride ruleset->anchor);
314072583c9Ssashan pf_anchor_rele(ruleset->anchor);
3156a21d20bSmcbride if (parent == NULL)
3166a21d20bSmcbride return;
3176a21d20bSmcbride ruleset = &parent->ruleset;
3186a21d20bSmcbride }
3196a21d20bSmcbride }
3206a21d20bSmcbride
3216a21d20bSmcbride int
pf_anchor_setup(struct pf_rule * r,const struct pf_ruleset * s,const char * name)3226a21d20bSmcbride pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
3236a21d20bSmcbride const char *name)
3246a21d20bSmcbride {
3256a21d20bSmcbride char *p, *path;
3266a21d20bSmcbride struct pf_ruleset *ruleset;
3276a21d20bSmcbride
3286a21d20bSmcbride r->anchor = NULL;
3296a21d20bSmcbride r->anchor_relative = 0;
3306a21d20bSmcbride r->anchor_wildcard = 0;
3316a21d20bSmcbride if (!name[0])
3326a21d20bSmcbride return (0);
333eacdf23bSmmcc path = rs_malloc(MAXPATHLEN);
3346a95758eSthib if (path == NULL)
3356a95758eSthib return (1);
3366a21d20bSmcbride if (name[0] == '/')
3376a21d20bSmcbride strlcpy(path, name + 1, MAXPATHLEN);
3386a21d20bSmcbride else {
3396a21d20bSmcbride /* relative path */
3406a21d20bSmcbride r->anchor_relative = 1;
3416a21d20bSmcbride if (s->anchor == NULL || !s->anchor->path[0])
3426a21d20bSmcbride path[0] = 0;
3436a21d20bSmcbride else
3446a21d20bSmcbride strlcpy(path, s->anchor->path, MAXPATHLEN);
3456a21d20bSmcbride while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
3466a21d20bSmcbride if (!path[0]) {
347a2fdc13dSmcbride DPFPRINTF(LOG_NOTICE,
348a2fdc13dSmcbride "pf_anchor_setup: .. beyond root");
3496338263fSderaadt rs_free(path, MAXPATHLEN);
3506a21d20bSmcbride return (1);
3516a21d20bSmcbride }
3526a21d20bSmcbride if ((p = strrchr(path, '/')) != NULL)
3536a21d20bSmcbride *p = 0;
3546a21d20bSmcbride else
3556a21d20bSmcbride path[0] = 0;
3566a21d20bSmcbride r->anchor_relative++;
3576a21d20bSmcbride name += 3;
3586a21d20bSmcbride }
3596a21d20bSmcbride if (path[0])
3606a21d20bSmcbride strlcat(path, "/", MAXPATHLEN);
3616a21d20bSmcbride strlcat(path, name, MAXPATHLEN);
3626a21d20bSmcbride }
3636a21d20bSmcbride if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
3646a21d20bSmcbride r->anchor_wildcard = 1;
3656a21d20bSmcbride *p = 0;
3666a21d20bSmcbride }
3676a21d20bSmcbride ruleset = pf_find_or_create_ruleset(path);
3686338263fSderaadt rs_free(path, MAXPATHLEN);
36955038654Skn if (ruleset == NULL || ruleset == &pf_main_ruleset) {
370a2fdc13dSmcbride DPFPRINTF(LOG_NOTICE,
371a2fdc13dSmcbride "pf_anchor_setup: ruleset");
3726a21d20bSmcbride return (1);
3736a21d20bSmcbride }
3746a21d20bSmcbride r->anchor = ruleset->anchor;
3756a21d20bSmcbride r->anchor->refcnt++;
3766a21d20bSmcbride return (0);
3776a21d20bSmcbride }
3786a21d20bSmcbride
3796a21d20bSmcbride int
pf_anchor_copyout(const struct pf_ruleset * rs,const struct pf_rule * r,struct pfioc_rule * pr)3806a21d20bSmcbride pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
3816a21d20bSmcbride struct pfioc_rule *pr)
3826a21d20bSmcbride {
3836a21d20bSmcbride pr->anchor_call[0] = 0;
3846a21d20bSmcbride if (r->anchor == NULL)
3856a21d20bSmcbride return (0);
3866a21d20bSmcbride if (!r->anchor_relative) {
3876a21d20bSmcbride strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
3886a21d20bSmcbride strlcat(pr->anchor_call, r->anchor->path,
3896a21d20bSmcbride sizeof(pr->anchor_call));
3906a21d20bSmcbride } else {
3916a21d20bSmcbride char *a, *p;
3926a21d20bSmcbride int i;
3936a21d20bSmcbride
394eacdf23bSmmcc a = rs_malloc(MAXPATHLEN);
3956a95758eSthib if (a == NULL)
3966a95758eSthib return (1);
39755038654Skn if (rs == &pf_main_ruleset)
3986a21d20bSmcbride a[0] = 0;
3996a21d20bSmcbride else
4006a21d20bSmcbride strlcpy(a, rs->anchor->path, MAXPATHLEN);
4016a21d20bSmcbride for (i = 1; i < r->anchor_relative; ++i) {
4026a21d20bSmcbride if ((p = strrchr(a, '/')) == NULL)
4036a21d20bSmcbride p = a;
4046a21d20bSmcbride *p = 0;
4056a21d20bSmcbride strlcat(pr->anchor_call, "../",
4066a21d20bSmcbride sizeof(pr->anchor_call));
4076a21d20bSmcbride }
4086a21d20bSmcbride if (strncmp(a, r->anchor->path, strlen(a))) {
409a2fdc13dSmcbride DPFPRINTF(LOG_NOTICE,
410a2fdc13dSmcbride "pf_anchor_copyout: '%s' '%s'", a,
4116a21d20bSmcbride r->anchor->path);
4126338263fSderaadt rs_free(a, MAXPATHLEN);
4136a21d20bSmcbride return (1);
4146a21d20bSmcbride }
4156a21d20bSmcbride if (strlen(r->anchor->path) > strlen(a))
4166a21d20bSmcbride strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
4176a21d20bSmcbride strlen(a) + 1 : 0), sizeof(pr->anchor_call));
4186338263fSderaadt rs_free(a, MAXPATHLEN);
4196a21d20bSmcbride }
4206a21d20bSmcbride if (r->anchor_wildcard)
4216a21d20bSmcbride strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
4226a21d20bSmcbride sizeof(pr->anchor_call));
4236a21d20bSmcbride return (0);
4246a21d20bSmcbride }
4256a21d20bSmcbride
4266a21d20bSmcbride void
pf_remove_anchor(struct pf_rule * r)427f6275afaSkn pf_remove_anchor(struct pf_rule *r)
4286a21d20bSmcbride {
4296a21d20bSmcbride if (r->anchor == NULL)
4306a21d20bSmcbride return;
431f6275afaSkn if (r->anchor->refcnt <= 0)
432f6275afaSkn DPFPRINTF(LOG_NOTICE, "pf_remove_anchor: broken refcount");
433f6275afaSkn else if (!--r->anchor->refcnt)
4346a21d20bSmcbride pf_remove_if_empty_ruleset(&r->anchor->ruleset);
4356a21d20bSmcbride r->anchor = NULL;
4366a21d20bSmcbride }
437072583c9Ssashan
438072583c9Ssashan void
pf_anchor_rele(struct pf_anchor * anchor)439072583c9Ssashan pf_anchor_rele(struct pf_anchor *anchor)
440072583c9Ssashan {
441072583c9Ssashan if ((anchor == NULL) || (anchor == &pf_main_anchor))
442072583c9Ssashan return;
443072583c9Ssashan
444072583c9Ssashan #ifdef _KERNEL
445072583c9Ssashan if (refcnt_rele(&anchor->ref))
446072583c9Ssashan rs_pool_put_anchor(anchor);
447072583c9Ssashan #else
448072583c9Ssashan rs_pool_put_anchor(anchor);
449072583c9Ssashan #endif
450072583c9Ssashan }
451072583c9Ssashan
452072583c9Ssashan struct pf_anchor *
pf_anchor_take(struct pf_anchor * anchor)453072583c9Ssashan pf_anchor_take(struct pf_anchor *anchor)
454072583c9Ssashan {
455072583c9Ssashan #ifdef _KERNEL
456072583c9Ssashan if (anchor != NULL && anchor != &pf_main_anchor)
457072583c9Ssashan refcnt_take(&anchor->ref);
458072583c9Ssashan #endif
459072583c9Ssashan return (anchor);
460072583c9Ssashan }
461