xref: /freebsd/sys/netpfil/pf/pf_ruleset.c (revision d710367d1159423ed4da6628b7ab042d3e44f900)
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);
733b3a8eb9SGleb Smirnoff 
74e86bddeaSKristof Provost static __inline int		pf_kanchor_compare(struct pf_kanchor *,
75e86bddeaSKristof Provost 				    struct pf_kanchor *);
76e86bddeaSKristof Provost static struct pf_kanchor	*pf_find_kanchor(const char *);
77e86bddeaSKristof Provost 
78e86bddeaSKristof Provost RB_GENERATE(pf_kanchor_global, pf_kanchor, entry_global, pf_kanchor_compare);
79e86bddeaSKristof Provost RB_GENERATE(pf_kanchor_node, pf_kanchor, entry_node, pf_kanchor_compare);
803b3a8eb9SGleb Smirnoff 
81e86bddeaSKristof Provost static __inline int
82e86bddeaSKristof Provost pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
83e86bddeaSKristof Provost {
84e86bddeaSKristof Provost 	int c = strcmp(a->path, b->path);
85e86bddeaSKristof Provost 
86e86bddeaSKristof Provost 	return (c ? (c < 0 ? -1 : 1) : 0);
87e86bddeaSKristof Provost }
883b3a8eb9SGleb Smirnoff 
893b3a8eb9SGleb Smirnoff int
903b3a8eb9SGleb Smirnoff pf_get_ruleset_number(u_int8_t action)
913b3a8eb9SGleb Smirnoff {
923b3a8eb9SGleb Smirnoff 	switch (action) {
933b3a8eb9SGleb Smirnoff 	case PF_SCRUB:
943b3a8eb9SGleb Smirnoff 	case PF_NOSCRUB:
953b3a8eb9SGleb Smirnoff 		return (PF_RULESET_SCRUB);
963b3a8eb9SGleb Smirnoff 		break;
973b3a8eb9SGleb Smirnoff 	case PF_PASS:
983b3a8eb9SGleb Smirnoff 	case PF_DROP:
993b3a8eb9SGleb Smirnoff 		return (PF_RULESET_FILTER);
1003b3a8eb9SGleb Smirnoff 		break;
1013b3a8eb9SGleb Smirnoff 	case PF_NAT:
1023b3a8eb9SGleb Smirnoff 	case PF_NONAT:
1033b3a8eb9SGleb Smirnoff 		return (PF_RULESET_NAT);
1043b3a8eb9SGleb Smirnoff 		break;
1053b3a8eb9SGleb Smirnoff 	case PF_BINAT:
1063b3a8eb9SGleb Smirnoff 	case PF_NOBINAT:
1073b3a8eb9SGleb Smirnoff 		return (PF_RULESET_BINAT);
1083b3a8eb9SGleb Smirnoff 		break;
1093b3a8eb9SGleb Smirnoff 	case PF_RDR:
1103b3a8eb9SGleb Smirnoff 	case PF_NORDR:
1113b3a8eb9SGleb Smirnoff 		return (PF_RULESET_RDR);
1123b3a8eb9SGleb Smirnoff 		break;
1133b3a8eb9SGleb Smirnoff 	default:
1143b3a8eb9SGleb Smirnoff 		return (PF_RULESET_MAX);
1153b3a8eb9SGleb Smirnoff 		break;
1163b3a8eb9SGleb Smirnoff 	}
1173b3a8eb9SGleb Smirnoff }
1183b3a8eb9SGleb Smirnoff 
119e86bddeaSKristof Provost static struct pf_kanchor *
120e86bddeaSKristof Provost pf_find_kanchor(const char *path)
121e86bddeaSKristof Provost {
122e86bddeaSKristof Provost 	struct pf_kanchor	*key, *found;
123e86bddeaSKristof Provost 
124e86bddeaSKristof Provost 	key = (struct pf_kanchor *)rs_malloc(sizeof(*key));
125e86bddeaSKristof Provost 	if (key == NULL)
126e86bddeaSKristof Provost 		return (NULL);
127e86bddeaSKristof Provost 	strlcpy(key->path, path, sizeof(key->path));
128e86bddeaSKristof Provost 	found = RB_FIND(pf_kanchor_global, &V_pf_anchors, key);
129e86bddeaSKristof Provost 	rs_free(key);
130e86bddeaSKristof Provost 	return (found);
131e86bddeaSKristof Provost }
132e86bddeaSKristof Provost 
133e86bddeaSKristof Provost void
134e86bddeaSKristof Provost pf_init_kruleset(struct pf_kruleset *ruleset)
135e86bddeaSKristof Provost {
136e86bddeaSKristof Provost 	int	i;
137e86bddeaSKristof Provost 
138e86bddeaSKristof Provost 	memset(ruleset, 0, sizeof(struct pf_kruleset));
139e86bddeaSKristof Provost 	for (i = 0; i < PF_RULESET_MAX; i++) {
140e86bddeaSKristof Provost 		TAILQ_INIT(&ruleset->rules[i].queues[0]);
141e86bddeaSKristof Provost 		TAILQ_INIT(&ruleset->rules[i].queues[1]);
142e86bddeaSKristof Provost 		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
143e86bddeaSKristof Provost 		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
144e86bddeaSKristof Provost 	}
145e86bddeaSKristof Provost }
146e86bddeaSKristof Provost 
147e86bddeaSKristof Provost struct pf_kruleset *
148e86bddeaSKristof Provost pf_find_kruleset(const char *path)
149e86bddeaSKristof Provost {
150e86bddeaSKristof Provost 	struct pf_kanchor	*anchor;
151e86bddeaSKristof Provost 
152e86bddeaSKristof Provost 	while (*path == '/')
153e86bddeaSKristof Provost 		path++;
154e86bddeaSKristof Provost 	if (!*path)
155e86bddeaSKristof Provost 		return (&pf_main_ruleset);
156e86bddeaSKristof Provost 	anchor = pf_find_kanchor(path);
157e86bddeaSKristof Provost 	if (anchor == NULL)
158e86bddeaSKristof Provost 		return (NULL);
159e86bddeaSKristof Provost 	else
160e86bddeaSKristof Provost 		return (&anchor->ruleset);
161e86bddeaSKristof Provost }
162e86bddeaSKristof Provost 
163e86bddeaSKristof Provost struct pf_kruleset *
164e86bddeaSKristof Provost pf_find_or_create_kruleset(const char *path)
165e86bddeaSKristof Provost {
166e86bddeaSKristof Provost 	char			*p, *q, *r;
167e86bddeaSKristof Provost 	struct pf_kruleset	*ruleset;
168e86bddeaSKristof Provost 	struct pf_kanchor	*anchor = NULL, *dup, *parent = NULL;
169e86bddeaSKristof Provost 
170e86bddeaSKristof Provost 	if (path[0] == 0)
171e86bddeaSKristof Provost 		return (&pf_main_ruleset);
172e86bddeaSKristof Provost 	while (*path == '/')
173e86bddeaSKristof Provost 		path++;
174e86bddeaSKristof Provost 	ruleset = pf_find_kruleset(path);
175e86bddeaSKristof Provost 	if (ruleset != NULL)
176e86bddeaSKristof Provost 		return (ruleset);
177e86bddeaSKristof Provost 	p = (char *)rs_malloc(MAXPATHLEN);
178e86bddeaSKristof Provost 	if (p == NULL)
179e86bddeaSKristof Provost 		return (NULL);
180e86bddeaSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
181e86bddeaSKristof Provost 	while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
182e86bddeaSKristof Provost 		*q = 0;
183e86bddeaSKristof Provost 		if ((ruleset = pf_find_kruleset(p)) != NULL) {
184e86bddeaSKristof Provost 			parent = ruleset->anchor;
185e86bddeaSKristof Provost 			break;
186e86bddeaSKristof Provost 		}
187e86bddeaSKristof Provost 	}
188e86bddeaSKristof Provost 	if (q == NULL)
189e86bddeaSKristof Provost 		q = p;
190e86bddeaSKristof Provost 	else
191e86bddeaSKristof Provost 		q++;
192e86bddeaSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
193e86bddeaSKristof Provost 	if (!*q) {
194e86bddeaSKristof Provost 		rs_free(p);
195e86bddeaSKristof Provost 		return (NULL);
196e86bddeaSKristof Provost 	}
197e86bddeaSKristof Provost 	while ((r = strchr(q, '/')) != NULL || *q) {
198e86bddeaSKristof Provost 		if (r != NULL)
199e86bddeaSKristof Provost 			*r = 0;
200e86bddeaSKristof Provost 		if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
201e86bddeaSKristof Provost 		    (parent != NULL && strlen(parent->path) >=
202e86bddeaSKristof Provost 		    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
203e86bddeaSKristof Provost 			rs_free(p);
204e86bddeaSKristof Provost 			return (NULL);
205e86bddeaSKristof Provost 		}
206e86bddeaSKristof Provost 		anchor = (struct pf_kanchor *)rs_malloc(sizeof(*anchor));
207e86bddeaSKristof Provost 		if (anchor == NULL) {
208e86bddeaSKristof Provost 			rs_free(p);
209e86bddeaSKristof Provost 			return (NULL);
210e86bddeaSKristof Provost 		}
211e86bddeaSKristof Provost 		RB_INIT(&anchor->children);
212e86bddeaSKristof Provost 		strlcpy(anchor->name, q, sizeof(anchor->name));
213e86bddeaSKristof Provost 		if (parent != NULL) {
214e86bddeaSKristof Provost 			strlcpy(anchor->path, parent->path,
215e86bddeaSKristof Provost 			    sizeof(anchor->path));
216e86bddeaSKristof Provost 			strlcat(anchor->path, "/", sizeof(anchor->path));
217e86bddeaSKristof Provost 		}
218e86bddeaSKristof Provost 		strlcat(anchor->path, anchor->name, sizeof(anchor->path));
219e86bddeaSKristof Provost 		if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
220e86bddeaSKristof Provost 		    NULL) {
221e86bddeaSKristof Provost 			printf("pf_find_or_create_ruleset: RB_INSERT1 "
222e86bddeaSKristof Provost 			    "'%s' '%s' collides with '%s' '%s'\n",
223e86bddeaSKristof Provost 			    anchor->path, anchor->name, dup->path, dup->name);
224e86bddeaSKristof Provost 			rs_free(anchor);
225e86bddeaSKristof Provost 			rs_free(p);
226e86bddeaSKristof Provost 			return (NULL);
227e86bddeaSKristof Provost 		}
228e86bddeaSKristof Provost 		if (parent != NULL) {
229e86bddeaSKristof Provost 			anchor->parent = parent;
230e86bddeaSKristof Provost 			if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
231e86bddeaSKristof Provost 			    anchor)) != NULL) {
232e86bddeaSKristof Provost 				printf("pf_find_or_create_ruleset: "
233e86bddeaSKristof Provost 				    "RB_INSERT2 '%s' '%s' collides with "
234e86bddeaSKristof Provost 				    "'%s' '%s'\n", anchor->path, anchor->name,
235e86bddeaSKristof Provost 				    dup->path, dup->name);
236e86bddeaSKristof Provost 				RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
237e86bddeaSKristof Provost 				    anchor);
238e86bddeaSKristof Provost 				rs_free(anchor);
239e86bddeaSKristof Provost 				rs_free(p);
240e86bddeaSKristof Provost 				return (NULL);
241e86bddeaSKristof Provost 			}
242e86bddeaSKristof Provost 		}
243e86bddeaSKristof Provost 		pf_init_kruleset(&anchor->ruleset);
244e86bddeaSKristof Provost 		anchor->ruleset.anchor = anchor;
245e86bddeaSKristof Provost 		parent = anchor;
246e86bddeaSKristof Provost 		if (r != NULL)
247e86bddeaSKristof Provost 			q = r + 1;
248e86bddeaSKristof Provost 		else
249e86bddeaSKristof Provost 			*q = 0;
250e86bddeaSKristof Provost 	}
251e86bddeaSKristof Provost 	rs_free(p);
252e86bddeaSKristof Provost 	return (&anchor->ruleset);
253e86bddeaSKristof Provost }
254e86bddeaSKristof Provost 
255e86bddeaSKristof Provost void
256e86bddeaSKristof Provost pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
257e86bddeaSKristof Provost {
258e86bddeaSKristof Provost 	struct pf_kanchor	*parent;
259e86bddeaSKristof Provost 	int			 i;
260e86bddeaSKristof Provost 
261e86bddeaSKristof Provost 	while (ruleset != NULL) {
262e86bddeaSKristof Provost 		if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
263e86bddeaSKristof Provost 		    !RB_EMPTY(&ruleset->anchor->children) ||
264e86bddeaSKristof Provost 		    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
265e86bddeaSKristof Provost 		    ruleset->topen)
266e86bddeaSKristof Provost 			return;
267e86bddeaSKristof Provost 		for (i = 0; i < PF_RULESET_MAX; ++i)
268e86bddeaSKristof Provost 			if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
269e86bddeaSKristof Provost 			    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
270e86bddeaSKristof Provost 			    ruleset->rules[i].inactive.open)
271e86bddeaSKristof Provost 				return;
272e86bddeaSKristof Provost 		RB_REMOVE(pf_kanchor_global, &V_pf_anchors, ruleset->anchor);
273e86bddeaSKristof Provost 		if ((parent = ruleset->anchor->parent) != NULL)
274e86bddeaSKristof Provost 			RB_REMOVE(pf_kanchor_node, &parent->children,
275e86bddeaSKristof Provost 			    ruleset->anchor);
276e86bddeaSKristof Provost 		rs_free(ruleset->anchor);
277e86bddeaSKristof Provost 		if (parent == NULL)
278e86bddeaSKristof Provost 			return;
279e86bddeaSKristof Provost 		ruleset = &parent->ruleset;
280e86bddeaSKristof Provost 	}
281e86bddeaSKristof Provost }
282e86bddeaSKristof Provost 
283e86bddeaSKristof Provost int
284e86bddeaSKristof Provost pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
285e86bddeaSKristof Provost     const char *name)
286e86bddeaSKristof Provost {
287e86bddeaSKristof Provost 	char			*p, *path;
288e86bddeaSKristof Provost 	struct pf_kruleset	*ruleset;
289e86bddeaSKristof Provost 
290e86bddeaSKristof Provost 	r->anchor = NULL;
291e86bddeaSKristof Provost 	r->anchor_relative = 0;
292e86bddeaSKristof Provost 	r->anchor_wildcard = 0;
293e86bddeaSKristof Provost 	if (!name[0])
294e86bddeaSKristof Provost 		return (0);
295e86bddeaSKristof Provost 	path = (char *)rs_malloc(MAXPATHLEN);
296e86bddeaSKristof Provost 	if (path == NULL)
297e86bddeaSKristof Provost 		return (1);
298e86bddeaSKristof Provost 	if (name[0] == '/')
299e86bddeaSKristof Provost 		strlcpy(path, name + 1, MAXPATHLEN);
300e86bddeaSKristof Provost 	else {
301e86bddeaSKristof Provost 		/* relative path */
302e86bddeaSKristof Provost 		r->anchor_relative = 1;
303e86bddeaSKristof Provost 		if (s->anchor == NULL || !s->anchor->path[0])
304e86bddeaSKristof Provost 			path[0] = 0;
305e86bddeaSKristof Provost 		else
306e86bddeaSKristof Provost 			strlcpy(path, s->anchor->path, MAXPATHLEN);
307e86bddeaSKristof Provost 		while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
308e86bddeaSKristof Provost 			if (!path[0]) {
30986b653edSKristof Provost 				DPFPRINTF("pf_anchor_setup: .. beyond root\n");
310e86bddeaSKristof Provost 				rs_free(path);
311e86bddeaSKristof Provost 				return (1);
312e86bddeaSKristof Provost 			}
313e86bddeaSKristof Provost 			if ((p = strrchr(path, '/')) != NULL)
314e86bddeaSKristof Provost 				*p = 0;
315e86bddeaSKristof Provost 			else
316e86bddeaSKristof Provost 				path[0] = 0;
317e86bddeaSKristof Provost 			r->anchor_relative++;
318e86bddeaSKristof Provost 			name += 3;
319e86bddeaSKristof Provost 		}
320e86bddeaSKristof Provost 		if (path[0])
321e86bddeaSKristof Provost 			strlcat(path, "/", MAXPATHLEN);
322e86bddeaSKristof Provost 		strlcat(path, name, MAXPATHLEN);
323e86bddeaSKristof Provost 	}
324e86bddeaSKristof Provost 	if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
325e86bddeaSKristof Provost 		r->anchor_wildcard = 1;
326e86bddeaSKristof Provost 		*p = 0;
327e86bddeaSKristof Provost 	}
328e86bddeaSKristof Provost 	ruleset = pf_find_or_create_kruleset(path);
329e86bddeaSKristof Provost 	rs_free(path);
330e86bddeaSKristof Provost 	if (ruleset == NULL || ruleset->anchor == NULL) {
33186b653edSKristof Provost 		DPFPRINTF("pf_anchor_setup: ruleset\n");
332e86bddeaSKristof Provost 		return (1);
333e86bddeaSKristof Provost 	}
334e86bddeaSKristof Provost 	r->anchor = ruleset->anchor;
335e86bddeaSKristof Provost 	r->anchor->refcnt++;
336e86bddeaSKristof Provost 	return (0);
337e86bddeaSKristof Provost }
338e86bddeaSKristof Provost 
339e86bddeaSKristof Provost int
340*d710367dSKristof Provost pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
341*d710367dSKristof Provost     nvlist_t *nvl)
342*d710367dSKristof Provost {
343*d710367dSKristof Provost 	char anchor_call[MAXPATHLEN] = { 0 };
344*d710367dSKristof Provost 
345*d710367dSKristof Provost 	if (r->anchor == NULL)
346*d710367dSKristof Provost 		goto done;
347*d710367dSKristof Provost 	if (!r->anchor_relative) {
348*d710367dSKristof Provost 		strlcpy(anchor_call, "/", sizeof(anchor_call));
349*d710367dSKristof Provost 		strlcat(anchor_call, r->anchor->path,
350*d710367dSKristof Provost 		    sizeof(anchor_call));
351*d710367dSKristof Provost 	} else {
352*d710367dSKristof Provost 		char	 a[MAXPATHLEN];
353*d710367dSKristof Provost 		char	*p;
354*d710367dSKristof Provost 		int	 i;
355*d710367dSKristof Provost 		if (rs->anchor == NULL)
356*d710367dSKristof Provost 			a[0] = 0;
357*d710367dSKristof Provost 		else
358*d710367dSKristof Provost 			strlcpy(a, rs->anchor->path, MAXPATHLEN);
359*d710367dSKristof Provost 		for (i = 1; i < r->anchor_relative; ++i) {
360*d710367dSKristof Provost 			if ((p = strrchr(a, '/')) == NULL)
361*d710367dSKristof Provost 				p = a;
362*d710367dSKristof Provost 			*p = 0;
363*d710367dSKristof Provost 			strlcat(anchor_call, "../",
364*d710367dSKristof Provost 			    sizeof(anchor_call));
365*d710367dSKristof Provost 		}
366*d710367dSKristof Provost 		if (strncmp(a, r->anchor->path, strlen(a))) {
367*d710367dSKristof Provost 			printf("pf_anchor_copyout: '%s' '%s'\n", a,
368*d710367dSKristof Provost 			    r->anchor->path);
369*d710367dSKristof Provost 			return (1);
370*d710367dSKristof Provost 		}
371*d710367dSKristof Provost 		if (strlen(r->anchor->path) > strlen(a))
372*d710367dSKristof Provost 			strlcat(anchor_call, r->anchor->path + (a[0] ?
373*d710367dSKristof Provost 			    strlen(a) + 1 : 0), sizeof(anchor_call));
374*d710367dSKristof Provost 
375*d710367dSKristof Provost 	}
376*d710367dSKristof Provost 	if (r->anchor_wildcard)
377*d710367dSKristof Provost 		strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
378*d710367dSKristof Provost 		    sizeof(anchor_call));
379*d710367dSKristof Provost 
380*d710367dSKristof Provost done:
381*d710367dSKristof Provost 	nvlist_add_string(nvl, "anchor_call", anchor_call);
382*d710367dSKristof Provost 
383*d710367dSKristof Provost 	return (0);
384*d710367dSKristof Provost }
385*d710367dSKristof Provost 
386*d710367dSKristof Provost int
387e86bddeaSKristof Provost pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
388e86bddeaSKristof Provost     struct pfioc_rule *pr)
389e86bddeaSKristof Provost {
390e86bddeaSKristof Provost 	pr->anchor_call[0] = 0;
391e86bddeaSKristof Provost 	if (r->anchor == NULL)
392e86bddeaSKristof Provost 		return (0);
393e86bddeaSKristof Provost 	if (!r->anchor_relative) {
394e86bddeaSKristof Provost 		strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
395e86bddeaSKristof Provost 		strlcat(pr->anchor_call, r->anchor->path,
396e86bddeaSKristof Provost 		    sizeof(pr->anchor_call));
397e86bddeaSKristof Provost 	} else {
398e86bddeaSKristof Provost 		char	*a, *p;
399e86bddeaSKristof Provost 		int	 i;
400e86bddeaSKristof Provost 
401e86bddeaSKristof Provost 		a = (char *)rs_malloc(MAXPATHLEN);
402e86bddeaSKristof Provost 		if (a == NULL)
403e86bddeaSKristof Provost 			return (1);
404e86bddeaSKristof Provost 		if (rs->anchor == NULL)
405e86bddeaSKristof Provost 			a[0] = 0;
406e86bddeaSKristof Provost 		else
407e86bddeaSKristof Provost 			strlcpy(a, rs->anchor->path, MAXPATHLEN);
408e86bddeaSKristof Provost 		for (i = 1; i < r->anchor_relative; ++i) {
409e86bddeaSKristof Provost 			if ((p = strrchr(a, '/')) == NULL)
410e86bddeaSKristof Provost 				p = a;
411e86bddeaSKristof Provost 			*p = 0;
412e86bddeaSKristof Provost 			strlcat(pr->anchor_call, "../",
413e86bddeaSKristof Provost 			    sizeof(pr->anchor_call));
414e86bddeaSKristof Provost 		}
415e86bddeaSKristof Provost 		if (strncmp(a, r->anchor->path, strlen(a))) {
416e86bddeaSKristof Provost 			printf("pf_anchor_copyout: '%s' '%s'\n", a,
417e86bddeaSKristof Provost 			    r->anchor->path);
418e86bddeaSKristof Provost 			rs_free(a);
419e86bddeaSKristof Provost 			return (1);
420e86bddeaSKristof Provost 		}
421e86bddeaSKristof Provost 		if (strlen(r->anchor->path) > strlen(a))
422e86bddeaSKristof Provost 			strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
423e86bddeaSKristof Provost 			    strlen(a) + 1 : 0), sizeof(pr->anchor_call));
424e86bddeaSKristof Provost 		rs_free(a);
425e86bddeaSKristof Provost 	}
426e86bddeaSKristof Provost 	if (r->anchor_wildcard)
427e86bddeaSKristof Provost 		strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
428e86bddeaSKristof Provost 		    sizeof(pr->anchor_call));
429e86bddeaSKristof Provost 	return (0);
430e86bddeaSKristof Provost }
431e86bddeaSKristof Provost 
432e86bddeaSKristof Provost void
433e86bddeaSKristof Provost pf_kanchor_remove(struct pf_krule *r)
434e86bddeaSKristof Provost {
435e86bddeaSKristof Provost 	if (r->anchor == NULL)
436e86bddeaSKristof Provost 		return;
437e86bddeaSKristof Provost 	if (r->anchor->refcnt <= 0) {
438e86bddeaSKristof Provost 		printf("pf_anchor_remove: broken refcount\n");
439e86bddeaSKristof Provost 		r->anchor = NULL;
440e86bddeaSKristof Provost 		return;
441e86bddeaSKristof Provost 	}
442e86bddeaSKristof Provost 	if (!--r->anchor->refcnt)
443e86bddeaSKristof Provost 		pf_remove_if_empty_kruleset(&r->anchor->ruleset);
444e86bddeaSKristof Provost 	r->anchor = NULL;
445e86bddeaSKristof Provost }
446