xref: /openbsd-src/sys/net/pf_ruleset.c (revision 062cda8b8dbd75d269fa4d5242973909ddd5e38c)
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