xref: /freebsd/sys/netpfil/pf/pf_ruleset.c (revision e732e742b37f66746b7556b990c54869845b72fc)
1d8aa10ccSGleb Smirnoff /*-
2fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
43b3a8eb9SGleb Smirnoff  * Copyright (c) 2001 Daniel Hartmeier
53b3a8eb9SGleb Smirnoff  * Copyright (c) 2002,2003 Henning Brauer
63b3a8eb9SGleb Smirnoff  * All rights reserved.
73b3a8eb9SGleb Smirnoff  *
83b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
93b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
103b3a8eb9SGleb Smirnoff  * are met:
113b3a8eb9SGleb Smirnoff  *
123b3a8eb9SGleb Smirnoff  *    - Redistributions of source code must retain the above copyright
133b3a8eb9SGleb Smirnoff  *      notice, this list of conditions and the following disclaimer.
143b3a8eb9SGleb Smirnoff  *    - Redistributions in binary form must reproduce the above
153b3a8eb9SGleb Smirnoff  *      copyright notice, this list of conditions and the following
163b3a8eb9SGleb Smirnoff  *      disclaimer in the documentation and/or other materials provided
173b3a8eb9SGleb Smirnoff  *      with the distribution.
183b3a8eb9SGleb Smirnoff  *
193b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
203b3a8eb9SGleb Smirnoff  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
213b3a8eb9SGleb Smirnoff  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
223b3a8eb9SGleb Smirnoff  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
233b3a8eb9SGleb Smirnoff  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
243b3a8eb9SGleb Smirnoff  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
253b3a8eb9SGleb Smirnoff  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
263b3a8eb9SGleb Smirnoff  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
273b3a8eb9SGleb Smirnoff  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
283b3a8eb9SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
293b3a8eb9SGleb Smirnoff  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
303b3a8eb9SGleb Smirnoff  * POSSIBILITY OF SUCH DAMAGE.
313b3a8eb9SGleb Smirnoff  *
323b3a8eb9SGleb Smirnoff  * Effort sponsored in part by the Defense Advanced Research Projects
333b3a8eb9SGleb Smirnoff  * Agency (DARPA) and Air Force Research Laboratory, Air Force
343b3a8eb9SGleb Smirnoff  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
353b3a8eb9SGleb Smirnoff  *
36d8aa10ccSGleb Smirnoff  *	$OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $
373b3a8eb9SGleb Smirnoff  */
383b3a8eb9SGleb Smirnoff 
393b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
403b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$");
413b3a8eb9SGleb Smirnoff 
423b3a8eb9SGleb Smirnoff #include <sys/param.h>
433b3a8eb9SGleb Smirnoff #include <sys/socket.h>
443b3a8eb9SGleb Smirnoff #include <sys/systm.h>
453b3a8eb9SGleb Smirnoff #include <sys/refcount.h>
463b3a8eb9SGleb Smirnoff #include <sys/mbuf.h>
473b3a8eb9SGleb Smirnoff 
483b3a8eb9SGleb Smirnoff #include <netinet/in.h>
493b3a8eb9SGleb Smirnoff #include <netinet/in_systm.h>
503b3a8eb9SGleb Smirnoff #include <netinet/ip.h>
513b3a8eb9SGleb Smirnoff #include <netinet/tcp.h>
523b3a8eb9SGleb Smirnoff 
533b3a8eb9SGleb Smirnoff #include <net/if.h>
54eedc7fd9SGleb Smirnoff #include <net/vnet.h>
553b3a8eb9SGleb Smirnoff #include <net/pfvar.h>
563b3a8eb9SGleb Smirnoff 
573b3a8eb9SGleb Smirnoff #ifdef INET6
583b3a8eb9SGleb Smirnoff #include <netinet/ip6.h>
593b3a8eb9SGleb Smirnoff #endif /* INET6 */
603b3a8eb9SGleb Smirnoff 
61fda7daf0SKristof Provost #ifndef _KERNEL
62fda7daf0SKristof Provost #error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead."
63fda7daf0SKristof Provost #endif
64fda7daf0SKristof Provost 
653b3a8eb9SGleb Smirnoff #define DPFPRINTF(format, x...)				\
663b3a8eb9SGleb Smirnoff 	if (V_pf_status.debug >= PF_DEBUG_NOISY)	\
673b3a8eb9SGleb Smirnoff 		printf(format , ##x)
683b3a8eb9SGleb Smirnoff #define rs_malloc(x)		malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
693b3a8eb9SGleb Smirnoff #define rs_free(x)		free(x, M_TEMP)
703b3a8eb9SGleb Smirnoff 
71e86bddeaSKristof Provost VNET_DEFINE(struct pf_kanchor_global,	pf_anchors);
72e86bddeaSKristof Provost VNET_DEFINE(struct pf_kanchor,		pf_main_anchor);
73*e732e742SKristof Provost VNET_DEFINE(struct pf_keth_settings*,	pf_keth);
74*e732e742SKristof Provost VNET_DEFINE(struct pf_keth_settings*,	pf_keth_inactive);
753b3a8eb9SGleb Smirnoff 
76e86bddeaSKristof Provost static __inline int		pf_kanchor_compare(struct pf_kanchor *,
77e86bddeaSKristof Provost 				    struct pf_kanchor *);
78e86bddeaSKristof Provost static struct pf_kanchor	*pf_find_kanchor(const char *);
79e86bddeaSKristof Provost 
80e86bddeaSKristof Provost RB_GENERATE(pf_kanchor_global, pf_kanchor, entry_global, pf_kanchor_compare);
81e86bddeaSKristof Provost RB_GENERATE(pf_kanchor_node, pf_kanchor, entry_node, pf_kanchor_compare);
823b3a8eb9SGleb Smirnoff 
83e86bddeaSKristof Provost static __inline int
84e86bddeaSKristof Provost pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
85e86bddeaSKristof Provost {
86e86bddeaSKristof Provost 	int c = strcmp(a->path, b->path);
87e86bddeaSKristof Provost 
88e86bddeaSKristof Provost 	return (c ? (c < 0 ? -1 : 1) : 0);
89e86bddeaSKristof Provost }
903b3a8eb9SGleb Smirnoff 
913b3a8eb9SGleb Smirnoff int
923b3a8eb9SGleb Smirnoff pf_get_ruleset_number(u_int8_t action)
933b3a8eb9SGleb Smirnoff {
943b3a8eb9SGleb Smirnoff 	switch (action) {
953b3a8eb9SGleb Smirnoff 	case PF_SCRUB:
963b3a8eb9SGleb Smirnoff 	case PF_NOSCRUB:
973b3a8eb9SGleb Smirnoff 		return (PF_RULESET_SCRUB);
983b3a8eb9SGleb Smirnoff 		break;
993b3a8eb9SGleb Smirnoff 	case PF_PASS:
100ef950daaSKristof Provost 	case PF_MATCH:
1013b3a8eb9SGleb Smirnoff 	case PF_DROP:
1023b3a8eb9SGleb Smirnoff 		return (PF_RULESET_FILTER);
1033b3a8eb9SGleb Smirnoff 		break;
1043b3a8eb9SGleb Smirnoff 	case PF_NAT:
1053b3a8eb9SGleb Smirnoff 	case PF_NONAT:
1063b3a8eb9SGleb Smirnoff 		return (PF_RULESET_NAT);
1073b3a8eb9SGleb Smirnoff 		break;
1083b3a8eb9SGleb Smirnoff 	case PF_BINAT:
1093b3a8eb9SGleb Smirnoff 	case PF_NOBINAT:
1103b3a8eb9SGleb Smirnoff 		return (PF_RULESET_BINAT);
1113b3a8eb9SGleb Smirnoff 		break;
1123b3a8eb9SGleb Smirnoff 	case PF_RDR:
1133b3a8eb9SGleb Smirnoff 	case PF_NORDR:
1143b3a8eb9SGleb Smirnoff 		return (PF_RULESET_RDR);
1153b3a8eb9SGleb Smirnoff 		break;
1163b3a8eb9SGleb Smirnoff 	default:
1173b3a8eb9SGleb Smirnoff 		return (PF_RULESET_MAX);
1183b3a8eb9SGleb Smirnoff 		break;
1193b3a8eb9SGleb Smirnoff 	}
1203b3a8eb9SGleb Smirnoff }
1213b3a8eb9SGleb Smirnoff 
122e86bddeaSKristof Provost static struct pf_kanchor *
123e86bddeaSKristof Provost pf_find_kanchor(const char *path)
124e86bddeaSKristof Provost {
125e86bddeaSKristof Provost 	struct pf_kanchor	*key, *found;
126e86bddeaSKristof Provost 
127e86bddeaSKristof Provost 	key = (struct pf_kanchor *)rs_malloc(sizeof(*key));
128e86bddeaSKristof Provost 	if (key == NULL)
129e86bddeaSKristof Provost 		return (NULL);
130e86bddeaSKristof Provost 	strlcpy(key->path, path, sizeof(key->path));
131e86bddeaSKristof Provost 	found = RB_FIND(pf_kanchor_global, &V_pf_anchors, key);
132e86bddeaSKristof Provost 	rs_free(key);
133e86bddeaSKristof Provost 	return (found);
134e86bddeaSKristof Provost }
135e86bddeaSKristof Provost 
136e86bddeaSKristof Provost void
137e86bddeaSKristof Provost pf_init_kruleset(struct pf_kruleset *ruleset)
138e86bddeaSKristof Provost {
139e86bddeaSKristof Provost 	int	i;
140e86bddeaSKristof Provost 
141e86bddeaSKristof Provost 	memset(ruleset, 0, sizeof(struct pf_kruleset));
142e86bddeaSKristof Provost 	for (i = 0; i < PF_RULESET_MAX; i++) {
143e86bddeaSKristof Provost 		TAILQ_INIT(&ruleset->rules[i].queues[0]);
144e86bddeaSKristof Provost 		TAILQ_INIT(&ruleset->rules[i].queues[1]);
145e86bddeaSKristof Provost 		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
146e86bddeaSKristof Provost 		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
147e86bddeaSKristof Provost 	}
148e86bddeaSKristof Provost }
149e86bddeaSKristof Provost 
150*e732e742SKristof Provost void
151*e732e742SKristof Provost pf_init_keth(struct pf_keth_settings *settings)
152*e732e742SKristof Provost {
153*e732e742SKristof Provost 
154*e732e742SKristof Provost 	TAILQ_INIT(&settings->rules);
155*e732e742SKristof Provost 	settings->ticket = 0;
156*e732e742SKristof Provost 	settings->open = 0;
157*e732e742SKristof Provost }
158*e732e742SKristof Provost 
159e86bddeaSKristof Provost struct pf_kruleset *
160e86bddeaSKristof Provost pf_find_kruleset(const char *path)
161e86bddeaSKristof Provost {
162e86bddeaSKristof Provost 	struct pf_kanchor	*anchor;
163e86bddeaSKristof Provost 
164e86bddeaSKristof Provost 	while (*path == '/')
165e86bddeaSKristof Provost 		path++;
166e86bddeaSKristof Provost 	if (!*path)
167e86bddeaSKristof Provost 		return (&pf_main_ruleset);
168e86bddeaSKristof Provost 	anchor = pf_find_kanchor(path);
169e86bddeaSKristof Provost 	if (anchor == NULL)
170e86bddeaSKristof Provost 		return (NULL);
171e86bddeaSKristof Provost 	else
172e86bddeaSKristof Provost 		return (&anchor->ruleset);
173e86bddeaSKristof Provost }
174e86bddeaSKristof Provost 
175e86bddeaSKristof Provost struct pf_kruleset *
176e86bddeaSKristof Provost pf_find_or_create_kruleset(const char *path)
177e86bddeaSKristof Provost {
178e86bddeaSKristof Provost 	char			*p, *q, *r;
179e86bddeaSKristof Provost 	struct pf_kruleset	*ruleset;
180e86bddeaSKristof Provost 	struct pf_kanchor	*anchor = NULL, *dup, *parent = NULL;
181e86bddeaSKristof Provost 
182e86bddeaSKristof Provost 	if (path[0] == 0)
183e86bddeaSKristof Provost 		return (&pf_main_ruleset);
184e86bddeaSKristof Provost 	while (*path == '/')
185e86bddeaSKristof Provost 		path++;
186e86bddeaSKristof Provost 	ruleset = pf_find_kruleset(path);
187e86bddeaSKristof Provost 	if (ruleset != NULL)
188e86bddeaSKristof Provost 		return (ruleset);
189e86bddeaSKristof Provost 	p = (char *)rs_malloc(MAXPATHLEN);
190e86bddeaSKristof Provost 	if (p == NULL)
191e86bddeaSKristof Provost 		return (NULL);
192e86bddeaSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
193e86bddeaSKristof Provost 	while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
194e86bddeaSKristof Provost 		*q = 0;
195e86bddeaSKristof Provost 		if ((ruleset = pf_find_kruleset(p)) != NULL) {
196e86bddeaSKristof Provost 			parent = ruleset->anchor;
197e86bddeaSKristof Provost 			break;
198e86bddeaSKristof Provost 		}
199e86bddeaSKristof Provost 	}
200e86bddeaSKristof Provost 	if (q == NULL)
201e86bddeaSKristof Provost 		q = p;
202e86bddeaSKristof Provost 	else
203e86bddeaSKristof Provost 		q++;
204e86bddeaSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
205e86bddeaSKristof Provost 	if (!*q) {
206e86bddeaSKristof Provost 		rs_free(p);
207e86bddeaSKristof Provost 		return (NULL);
208e86bddeaSKristof Provost 	}
209e86bddeaSKristof Provost 	while ((r = strchr(q, '/')) != NULL || *q) {
210e86bddeaSKristof Provost 		if (r != NULL)
211e86bddeaSKristof Provost 			*r = 0;
212e86bddeaSKristof Provost 		if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
213e86bddeaSKristof Provost 		    (parent != NULL && strlen(parent->path) >=
214e86bddeaSKristof Provost 		    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
215e86bddeaSKristof Provost 			rs_free(p);
216e86bddeaSKristof Provost 			return (NULL);
217e86bddeaSKristof Provost 		}
218e86bddeaSKristof Provost 		anchor = (struct pf_kanchor *)rs_malloc(sizeof(*anchor));
219e86bddeaSKristof Provost 		if (anchor == NULL) {
220e86bddeaSKristof Provost 			rs_free(p);
221e86bddeaSKristof Provost 			return (NULL);
222e86bddeaSKristof Provost 		}
223e86bddeaSKristof Provost 		RB_INIT(&anchor->children);
224e86bddeaSKristof Provost 		strlcpy(anchor->name, q, sizeof(anchor->name));
225e86bddeaSKristof Provost 		if (parent != NULL) {
226e86bddeaSKristof Provost 			strlcpy(anchor->path, parent->path,
227e86bddeaSKristof Provost 			    sizeof(anchor->path));
228e86bddeaSKristof Provost 			strlcat(anchor->path, "/", sizeof(anchor->path));
229e86bddeaSKristof Provost 		}
230e86bddeaSKristof Provost 		strlcat(anchor->path, anchor->name, sizeof(anchor->path));
231e86bddeaSKristof Provost 		if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
232e86bddeaSKristof Provost 		    NULL) {
233e86bddeaSKristof Provost 			printf("pf_find_or_create_ruleset: RB_INSERT1 "
234e86bddeaSKristof Provost 			    "'%s' '%s' collides with '%s' '%s'\n",
235e86bddeaSKristof Provost 			    anchor->path, anchor->name, dup->path, dup->name);
236e86bddeaSKristof Provost 			rs_free(anchor);
237e86bddeaSKristof Provost 			rs_free(p);
238e86bddeaSKristof Provost 			return (NULL);
239e86bddeaSKristof Provost 		}
240e86bddeaSKristof Provost 		if (parent != NULL) {
241e86bddeaSKristof Provost 			anchor->parent = parent;
242e86bddeaSKristof Provost 			if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
243e86bddeaSKristof Provost 			    anchor)) != NULL) {
244e86bddeaSKristof Provost 				printf("pf_find_or_create_ruleset: "
245e86bddeaSKristof Provost 				    "RB_INSERT2 '%s' '%s' collides with "
246e86bddeaSKristof Provost 				    "'%s' '%s'\n", anchor->path, anchor->name,
247e86bddeaSKristof Provost 				    dup->path, dup->name);
248e86bddeaSKristof Provost 				RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
249e86bddeaSKristof Provost 				    anchor);
250e86bddeaSKristof Provost 				rs_free(anchor);
251e86bddeaSKristof Provost 				rs_free(p);
252e86bddeaSKristof Provost 				return (NULL);
253e86bddeaSKristof Provost 			}
254e86bddeaSKristof Provost 		}
255e86bddeaSKristof Provost 		pf_init_kruleset(&anchor->ruleset);
256e86bddeaSKristof Provost 		anchor->ruleset.anchor = anchor;
257e86bddeaSKristof Provost 		parent = anchor;
258e86bddeaSKristof Provost 		if (r != NULL)
259e86bddeaSKristof Provost 			q = r + 1;
260e86bddeaSKristof Provost 		else
261e86bddeaSKristof Provost 			*q = 0;
262e86bddeaSKristof Provost 	}
263e86bddeaSKristof Provost 	rs_free(p);
264e86bddeaSKristof Provost 	return (&anchor->ruleset);
265e86bddeaSKristof Provost }
266e86bddeaSKristof Provost 
267e86bddeaSKristof Provost void
268e86bddeaSKristof Provost pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
269e86bddeaSKristof Provost {
270e86bddeaSKristof Provost 	struct pf_kanchor	*parent;
271e86bddeaSKristof Provost 	int			 i;
272e86bddeaSKristof Provost 
273e86bddeaSKristof Provost 	while (ruleset != NULL) {
274e86bddeaSKristof Provost 		if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
275e86bddeaSKristof Provost 		    !RB_EMPTY(&ruleset->anchor->children) ||
276e86bddeaSKristof Provost 		    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
277e86bddeaSKristof Provost 		    ruleset->topen)
278e86bddeaSKristof Provost 			return;
279e86bddeaSKristof Provost 		for (i = 0; i < PF_RULESET_MAX; ++i)
280e86bddeaSKristof Provost 			if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
281e86bddeaSKristof Provost 			    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
282e86bddeaSKristof Provost 			    ruleset->rules[i].inactive.open)
283e86bddeaSKristof Provost 				return;
284e86bddeaSKristof Provost 		RB_REMOVE(pf_kanchor_global, &V_pf_anchors, ruleset->anchor);
285e86bddeaSKristof Provost 		if ((parent = ruleset->anchor->parent) != NULL)
286e86bddeaSKristof Provost 			RB_REMOVE(pf_kanchor_node, &parent->children,
287e86bddeaSKristof Provost 			    ruleset->anchor);
288e86bddeaSKristof Provost 		rs_free(ruleset->anchor);
289e86bddeaSKristof Provost 		if (parent == NULL)
290e86bddeaSKristof Provost 			return;
291e86bddeaSKristof Provost 		ruleset = &parent->ruleset;
292e86bddeaSKristof Provost 	}
293e86bddeaSKristof Provost }
294e86bddeaSKristof Provost 
295e86bddeaSKristof Provost int
296e86bddeaSKristof Provost pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
297e86bddeaSKristof Provost     const char *name)
298e86bddeaSKristof Provost {
299e86bddeaSKristof Provost 	char			*p, *path;
300e86bddeaSKristof Provost 	struct pf_kruleset	*ruleset;
301e86bddeaSKristof Provost 
302e86bddeaSKristof Provost 	r->anchor = NULL;
303e86bddeaSKristof Provost 	r->anchor_relative = 0;
304e86bddeaSKristof Provost 	r->anchor_wildcard = 0;
305e86bddeaSKristof Provost 	if (!name[0])
306e86bddeaSKristof Provost 		return (0);
307e86bddeaSKristof Provost 	path = (char *)rs_malloc(MAXPATHLEN);
308e86bddeaSKristof Provost 	if (path == NULL)
309e86bddeaSKristof Provost 		return (1);
310e86bddeaSKristof Provost 	if (name[0] == '/')
311e86bddeaSKristof Provost 		strlcpy(path, name + 1, MAXPATHLEN);
312e86bddeaSKristof Provost 	else {
313e86bddeaSKristof Provost 		/* relative path */
314e86bddeaSKristof Provost 		r->anchor_relative = 1;
315e86bddeaSKristof Provost 		if (s->anchor == NULL || !s->anchor->path[0])
316e86bddeaSKristof Provost 			path[0] = 0;
317e86bddeaSKristof Provost 		else
318e86bddeaSKristof Provost 			strlcpy(path, s->anchor->path, MAXPATHLEN);
319e86bddeaSKristof Provost 		while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
320e86bddeaSKristof Provost 			if (!path[0]) {
32186b653edSKristof Provost 				DPFPRINTF("pf_anchor_setup: .. beyond root\n");
322e86bddeaSKristof Provost 				rs_free(path);
323e86bddeaSKristof Provost 				return (1);
324e86bddeaSKristof Provost 			}
325e86bddeaSKristof Provost 			if ((p = strrchr(path, '/')) != NULL)
326e86bddeaSKristof Provost 				*p = 0;
327e86bddeaSKristof Provost 			else
328e86bddeaSKristof Provost 				path[0] = 0;
329e86bddeaSKristof Provost 			r->anchor_relative++;
330e86bddeaSKristof Provost 			name += 3;
331e86bddeaSKristof Provost 		}
332e86bddeaSKristof Provost 		if (path[0])
333e86bddeaSKristof Provost 			strlcat(path, "/", MAXPATHLEN);
334e86bddeaSKristof Provost 		strlcat(path, name, MAXPATHLEN);
335e86bddeaSKristof Provost 	}
336e86bddeaSKristof Provost 	if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
337e86bddeaSKristof Provost 		r->anchor_wildcard = 1;
338e86bddeaSKristof Provost 		*p = 0;
339e86bddeaSKristof Provost 	}
340e86bddeaSKristof Provost 	ruleset = pf_find_or_create_kruleset(path);
341e86bddeaSKristof Provost 	rs_free(path);
342e86bddeaSKristof Provost 	if (ruleset == NULL || ruleset->anchor == NULL) {
34386b653edSKristof Provost 		DPFPRINTF("pf_anchor_setup: ruleset\n");
344e86bddeaSKristof Provost 		return (1);
345e86bddeaSKristof Provost 	}
346e86bddeaSKristof Provost 	r->anchor = ruleset->anchor;
347e86bddeaSKristof Provost 	r->anchor->refcnt++;
348e86bddeaSKristof Provost 	return (0);
349e86bddeaSKristof Provost }
350e86bddeaSKristof Provost 
351e86bddeaSKristof Provost int
352d710367dSKristof Provost pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
353d710367dSKristof Provost     nvlist_t *nvl)
354d710367dSKristof Provost {
355d710367dSKristof Provost 	char anchor_call[MAXPATHLEN] = { 0 };
356d710367dSKristof Provost 
357d710367dSKristof Provost 	if (r->anchor == NULL)
358d710367dSKristof Provost 		goto done;
359d710367dSKristof Provost 	if (!r->anchor_relative) {
360d710367dSKristof Provost 		strlcpy(anchor_call, "/", sizeof(anchor_call));
361d710367dSKristof Provost 		strlcat(anchor_call, r->anchor->path,
362d710367dSKristof Provost 		    sizeof(anchor_call));
363d710367dSKristof Provost 	} else {
364d710367dSKristof Provost 		char	 a[MAXPATHLEN];
365d710367dSKristof Provost 		char	*p;
366d710367dSKristof Provost 		int	 i;
367d710367dSKristof Provost 		if (rs->anchor == NULL)
368d710367dSKristof Provost 			a[0] = 0;
369d710367dSKristof Provost 		else
370d710367dSKristof Provost 			strlcpy(a, rs->anchor->path, MAXPATHLEN);
371d710367dSKristof Provost 		for (i = 1; i < r->anchor_relative; ++i) {
372d710367dSKristof Provost 			if ((p = strrchr(a, '/')) == NULL)
373d710367dSKristof Provost 				p = a;
374d710367dSKristof Provost 			*p = 0;
375d710367dSKristof Provost 			strlcat(anchor_call, "../",
376d710367dSKristof Provost 			    sizeof(anchor_call));
377d710367dSKristof Provost 		}
378d710367dSKristof Provost 		if (strncmp(a, r->anchor->path, strlen(a))) {
379d710367dSKristof Provost 			printf("pf_anchor_copyout: '%s' '%s'\n", a,
380d710367dSKristof Provost 			    r->anchor->path);
381d710367dSKristof Provost 			return (1);
382d710367dSKristof Provost 		}
383d710367dSKristof Provost 		if (strlen(r->anchor->path) > strlen(a))
384d710367dSKristof Provost 			strlcat(anchor_call, r->anchor->path + (a[0] ?
385d710367dSKristof Provost 			    strlen(a) + 1 : 0), sizeof(anchor_call));
386d710367dSKristof Provost 
387d710367dSKristof Provost 	}
388d710367dSKristof Provost 	if (r->anchor_wildcard)
389d710367dSKristof Provost 		strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
390d710367dSKristof Provost 		    sizeof(anchor_call));
391d710367dSKristof Provost 
392d710367dSKristof Provost done:
393d710367dSKristof Provost 	nvlist_add_string(nvl, "anchor_call", anchor_call);
394d710367dSKristof Provost 
395d710367dSKristof Provost 	return (0);
396d710367dSKristof Provost }
397d710367dSKristof Provost 
398d710367dSKristof Provost int
399e86bddeaSKristof Provost pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
400e86bddeaSKristof Provost     struct pfioc_rule *pr)
401e86bddeaSKristof Provost {
402e86bddeaSKristof Provost 	pr->anchor_call[0] = 0;
403e86bddeaSKristof Provost 	if (r->anchor == NULL)
404e86bddeaSKristof Provost 		return (0);
405e86bddeaSKristof Provost 	if (!r->anchor_relative) {
406e86bddeaSKristof Provost 		strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
407e86bddeaSKristof Provost 		strlcat(pr->anchor_call, r->anchor->path,
408e86bddeaSKristof Provost 		    sizeof(pr->anchor_call));
409e86bddeaSKristof Provost 	} else {
410e86bddeaSKristof Provost 		char	*a, *p;
411e86bddeaSKristof Provost 		int	 i;
412e86bddeaSKristof Provost 
413e86bddeaSKristof Provost 		a = (char *)rs_malloc(MAXPATHLEN);
414e86bddeaSKristof Provost 		if (a == NULL)
415e86bddeaSKristof Provost 			return (1);
416e86bddeaSKristof Provost 		if (rs->anchor == NULL)
417e86bddeaSKristof Provost 			a[0] = 0;
418e86bddeaSKristof Provost 		else
419e86bddeaSKristof Provost 			strlcpy(a, rs->anchor->path, MAXPATHLEN);
420e86bddeaSKristof Provost 		for (i = 1; i < r->anchor_relative; ++i) {
421e86bddeaSKristof Provost 			if ((p = strrchr(a, '/')) == NULL)
422e86bddeaSKristof Provost 				p = a;
423e86bddeaSKristof Provost 			*p = 0;
424e86bddeaSKristof Provost 			strlcat(pr->anchor_call, "../",
425e86bddeaSKristof Provost 			    sizeof(pr->anchor_call));
426e86bddeaSKristof Provost 		}
427e86bddeaSKristof Provost 		if (strncmp(a, r->anchor->path, strlen(a))) {
428e86bddeaSKristof Provost 			printf("pf_anchor_copyout: '%s' '%s'\n", a,
429e86bddeaSKristof Provost 			    r->anchor->path);
430e86bddeaSKristof Provost 			rs_free(a);
431e86bddeaSKristof Provost 			return (1);
432e86bddeaSKristof Provost 		}
433e86bddeaSKristof Provost 		if (strlen(r->anchor->path) > strlen(a))
434e86bddeaSKristof Provost 			strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
435e86bddeaSKristof Provost 			    strlen(a) + 1 : 0), sizeof(pr->anchor_call));
436e86bddeaSKristof Provost 		rs_free(a);
437e86bddeaSKristof Provost 	}
438e86bddeaSKristof Provost 	if (r->anchor_wildcard)
439e86bddeaSKristof Provost 		strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
440e86bddeaSKristof Provost 		    sizeof(pr->anchor_call));
441e86bddeaSKristof Provost 	return (0);
442e86bddeaSKristof Provost }
443e86bddeaSKristof Provost 
444e86bddeaSKristof Provost void
445e86bddeaSKristof Provost pf_kanchor_remove(struct pf_krule *r)
446e86bddeaSKristof Provost {
447e86bddeaSKristof Provost 	if (r->anchor == NULL)
448e86bddeaSKristof Provost 		return;
449e86bddeaSKristof Provost 	if (r->anchor->refcnt <= 0) {
450e86bddeaSKristof Provost 		printf("pf_anchor_remove: broken refcount\n");
451e86bddeaSKristof Provost 		r->anchor = NULL;
452e86bddeaSKristof Provost 		return;
453e86bddeaSKristof Provost 	}
454e86bddeaSKristof Provost 	if (!--r->anchor->refcnt)
455e86bddeaSKristof Provost 		pf_remove_if_empty_kruleset(&r->anchor->ruleset);
456e86bddeaSKristof Provost 	r->anchor = NULL;
457e86bddeaSKristof Provost }
458