xref: /freebsd/sys/netpfil/pf/pf_ruleset.c (revision 6ee3e376823fc16b04ab45663661f27246e7b004)
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/param.h>
403b3a8eb9SGleb Smirnoff #include <sys/socket.h>
413b3a8eb9SGleb Smirnoff #include <sys/systm.h>
423b3a8eb9SGleb Smirnoff #include <sys/refcount.h>
433b3a8eb9SGleb Smirnoff #include <sys/mbuf.h>
443b3a8eb9SGleb Smirnoff 
453b3a8eb9SGleb Smirnoff #include <netinet/in.h>
463b3a8eb9SGleb Smirnoff #include <netinet/in_systm.h>
473b3a8eb9SGleb Smirnoff #include <netinet/ip.h>
483b3a8eb9SGleb Smirnoff #include <netinet/tcp.h>
493b3a8eb9SGleb Smirnoff 
503b3a8eb9SGleb Smirnoff #include <net/if.h>
51eedc7fd9SGleb Smirnoff #include <net/vnet.h>
523b3a8eb9SGleb Smirnoff #include <net/pfvar.h>
533b3a8eb9SGleb Smirnoff 
543b3a8eb9SGleb Smirnoff #ifdef INET6
553b3a8eb9SGleb Smirnoff #include <netinet/ip6.h>
563b3a8eb9SGleb Smirnoff #endif /* INET6 */
573b3a8eb9SGleb Smirnoff 
58fda7daf0SKristof Provost #ifndef _KERNEL
59fda7daf0SKristof Provost #error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead."
60fda7daf0SKristof Provost #endif
61fda7daf0SKristof Provost 
623b3a8eb9SGleb Smirnoff #define DPFPRINTF(format, x...)				\
633b3a8eb9SGleb Smirnoff 	if (V_pf_status.debug >= PF_DEBUG_NOISY)	\
643b3a8eb9SGleb Smirnoff 		printf(format , ##x)
653b3a8eb9SGleb Smirnoff #define rs_malloc(x)		malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
663b3a8eb9SGleb Smirnoff #define rs_free(x)		free(x, M_TEMP)
673b3a8eb9SGleb Smirnoff 
68e86bddeaSKristof Provost VNET_DEFINE(struct pf_kanchor_global,	pf_anchors);
69e86bddeaSKristof Provost VNET_DEFINE(struct pf_kanchor,		pf_main_anchor);
70c5131afeSKristof Provost VNET_DEFINE(struct pf_keth_ruleset*,	pf_keth);
71c5131afeSKristof Provost VNET_DEFINE(struct pf_keth_anchor,	pf_main_keth_anchor);
72c5131afeSKristof Provost VNET_DEFINE(struct pf_keth_anchor_global,	 pf_keth_anchors);
733b3a8eb9SGleb Smirnoff 
74e86bddeaSKristof Provost static __inline int		pf_kanchor_compare(struct pf_kanchor *,
75e86bddeaSKristof Provost 				    struct pf_kanchor *);
76c5131afeSKristof Provost static __inline int		pf_keth_anchor_compare(struct pf_keth_anchor *,
77c5131afeSKristof Provost 				    struct pf_keth_anchor *);
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);
82c5131afeSKristof Provost RB_GENERATE(pf_keth_anchor_global, pf_keth_anchor, entry_global,
83c5131afeSKristof Provost     pf_keth_anchor_compare);
84c5131afeSKristof Provost RB_GENERATE(pf_keth_anchor_node, pf_keth_anchor, entry_node,
85c5131afeSKristof Provost     pf_keth_anchor_compare);
863b3a8eb9SGleb Smirnoff 
87e86bddeaSKristof Provost static __inline int
pf_kanchor_compare(struct pf_kanchor * a,struct pf_kanchor * b)88e86bddeaSKristof Provost pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
89e86bddeaSKristof Provost {
90e86bddeaSKristof Provost 	int c = strcmp(a->path, b->path);
91e86bddeaSKristof Provost 
92e86bddeaSKristof Provost 	return (c ? (c < 0 ? -1 : 1) : 0);
93e86bddeaSKristof Provost }
943b3a8eb9SGleb Smirnoff 
95c5131afeSKristof Provost static __inline int
pf_keth_anchor_compare(struct pf_keth_anchor * a,struct pf_keth_anchor * b)96c5131afeSKristof Provost pf_keth_anchor_compare(struct pf_keth_anchor *a, struct pf_keth_anchor *b)
97c5131afeSKristof Provost {
98c5131afeSKristof Provost 	int c = strcmp(a->path, b->path);
99c5131afeSKristof Provost 
100c5131afeSKristof Provost 	return (c ? (c < 0 ? -1 : 1) : 0);
101c5131afeSKristof Provost }
102c5131afeSKristof Provost 
1033b3a8eb9SGleb Smirnoff int
pf_get_ruleset_number(u_int8_t action)1043b3a8eb9SGleb Smirnoff pf_get_ruleset_number(u_int8_t action)
1053b3a8eb9SGleb Smirnoff {
1063b3a8eb9SGleb Smirnoff 	switch (action) {
1073b3a8eb9SGleb Smirnoff 	case PF_SCRUB:
1083b3a8eb9SGleb Smirnoff 	case PF_NOSCRUB:
1093b3a8eb9SGleb Smirnoff 		return (PF_RULESET_SCRUB);
1103b3a8eb9SGleb Smirnoff 		break;
1113b3a8eb9SGleb Smirnoff 	case PF_PASS:
112ef950daaSKristof Provost 	case PF_MATCH:
1133b3a8eb9SGleb Smirnoff 	case PF_DROP:
1143b3a8eb9SGleb Smirnoff 		return (PF_RULESET_FILTER);
1153b3a8eb9SGleb Smirnoff 		break;
1163b3a8eb9SGleb Smirnoff 	case PF_NAT:
1173b3a8eb9SGleb Smirnoff 	case PF_NONAT:
1183b3a8eb9SGleb Smirnoff 		return (PF_RULESET_NAT);
1193b3a8eb9SGleb Smirnoff 		break;
1203b3a8eb9SGleb Smirnoff 	case PF_BINAT:
1213b3a8eb9SGleb Smirnoff 	case PF_NOBINAT:
1223b3a8eb9SGleb Smirnoff 		return (PF_RULESET_BINAT);
1233b3a8eb9SGleb Smirnoff 		break;
1243b3a8eb9SGleb Smirnoff 	case PF_RDR:
1253b3a8eb9SGleb Smirnoff 	case PF_NORDR:
1263b3a8eb9SGleb Smirnoff 		return (PF_RULESET_RDR);
1273b3a8eb9SGleb Smirnoff 		break;
1283b3a8eb9SGleb Smirnoff 	default:
1293b3a8eb9SGleb Smirnoff 		return (PF_RULESET_MAX);
1303b3a8eb9SGleb Smirnoff 		break;
1313b3a8eb9SGleb Smirnoff 	}
1323b3a8eb9SGleb Smirnoff }
1333b3a8eb9SGleb Smirnoff 
134e86bddeaSKristof Provost static struct pf_kanchor *
pf_find_kanchor(const char * path)135e86bddeaSKristof Provost pf_find_kanchor(const char *path)
136e86bddeaSKristof Provost {
137e86bddeaSKristof Provost 	struct pf_kanchor	*key, *found;
138e86bddeaSKristof Provost 
139e86bddeaSKristof Provost 	key = (struct pf_kanchor *)rs_malloc(sizeof(*key));
140e86bddeaSKristof Provost 	if (key == NULL)
141e86bddeaSKristof Provost 		return (NULL);
142e86bddeaSKristof Provost 	strlcpy(key->path, path, sizeof(key->path));
143e86bddeaSKristof Provost 	found = RB_FIND(pf_kanchor_global, &V_pf_anchors, key);
144e86bddeaSKristof Provost 	rs_free(key);
145e86bddeaSKristof Provost 	return (found);
146e86bddeaSKristof Provost }
147e86bddeaSKristof Provost 
148e86bddeaSKristof Provost void
pf_init_kruleset(struct pf_kruleset * ruleset)149e86bddeaSKristof Provost pf_init_kruleset(struct pf_kruleset *ruleset)
150e86bddeaSKristof Provost {
151e86bddeaSKristof Provost 	int	i;
152e86bddeaSKristof Provost 
153e86bddeaSKristof Provost 	memset(ruleset, 0, sizeof(struct pf_kruleset));
154e86bddeaSKristof Provost 	for (i = 0; i < PF_RULESET_MAX; i++) {
155e86bddeaSKristof Provost 		TAILQ_INIT(&ruleset->rules[i].queues[0]);
156e86bddeaSKristof Provost 		TAILQ_INIT(&ruleset->rules[i].queues[1]);
157e86bddeaSKristof Provost 		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
158e86bddeaSKristof Provost 		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
159e86bddeaSKristof Provost 	}
160e86bddeaSKristof Provost }
161e86bddeaSKristof Provost 
162e732e742SKristof Provost void
pf_init_keth(struct pf_keth_ruleset * rs)163c5131afeSKristof Provost pf_init_keth(struct pf_keth_ruleset *rs)
164e732e742SKristof Provost {
165e732e742SKristof Provost 
166c5131afeSKristof Provost 	bzero(rs, sizeof(*rs));
167c5131afeSKristof Provost 	TAILQ_INIT(&rs->rules[0]);
168c5131afeSKristof Provost 	TAILQ_INIT(&rs->rules[1]);
169c5131afeSKristof Provost 	rs->active.rules = &rs->rules[0];
170c5131afeSKristof Provost 	rs->active.open = 0;
171c5131afeSKristof Provost 	rs->inactive.rules = &rs->rules[1];
172c5131afeSKristof Provost 	rs->inactive.open = 0;
173c5131afeSKristof Provost 
174c5131afeSKristof Provost 	rs->vnet = curvnet;
175e732e742SKristof Provost }
176e732e742SKristof Provost 
177e86bddeaSKristof Provost struct pf_kruleset *
pf_find_kruleset(const char * path)178e86bddeaSKristof Provost pf_find_kruleset(const char *path)
179e86bddeaSKristof Provost {
180e86bddeaSKristof Provost 	struct pf_kanchor	*anchor;
181e86bddeaSKristof Provost 
182e86bddeaSKristof Provost 	while (*path == '/')
183e86bddeaSKristof Provost 		path++;
184e86bddeaSKristof Provost 	if (!*path)
185e86bddeaSKristof Provost 		return (&pf_main_ruleset);
186e86bddeaSKristof Provost 	anchor = pf_find_kanchor(path);
187e86bddeaSKristof Provost 	if (anchor == NULL)
188e86bddeaSKristof Provost 		return (NULL);
189e86bddeaSKristof Provost 	else
190e86bddeaSKristof Provost 		return (&anchor->ruleset);
191e86bddeaSKristof Provost }
192e86bddeaSKristof Provost 
193e86bddeaSKristof Provost struct pf_kruleset *
pf_find_or_create_kruleset(const char * path)194e86bddeaSKristof Provost pf_find_or_create_kruleset(const char *path)
195e86bddeaSKristof Provost {
196e86bddeaSKristof Provost 	char			*p, *q, *r;
197e86bddeaSKristof Provost 	struct pf_kruleset	*ruleset;
198e86bddeaSKristof Provost 	struct pf_kanchor	*anchor = NULL, *dup, *parent = NULL;
199e86bddeaSKristof Provost 
200e86bddeaSKristof Provost 	if (path[0] == 0)
201e86bddeaSKristof Provost 		return (&pf_main_ruleset);
202e86bddeaSKristof Provost 	while (*path == '/')
203e86bddeaSKristof Provost 		path++;
204e86bddeaSKristof Provost 	ruleset = pf_find_kruleset(path);
205e86bddeaSKristof Provost 	if (ruleset != NULL)
206e86bddeaSKristof Provost 		return (ruleset);
207e86bddeaSKristof Provost 	p = (char *)rs_malloc(MAXPATHLEN);
208e86bddeaSKristof Provost 	if (p == NULL)
209e86bddeaSKristof Provost 		return (NULL);
210e86bddeaSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
211e86bddeaSKristof Provost 	while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
212e86bddeaSKristof Provost 		*q = 0;
213e86bddeaSKristof Provost 		if ((ruleset = pf_find_kruleset(p)) != NULL) {
214e86bddeaSKristof Provost 			parent = ruleset->anchor;
215e86bddeaSKristof Provost 			break;
216e86bddeaSKristof Provost 		}
217e86bddeaSKristof Provost 	}
218e86bddeaSKristof Provost 	if (q == NULL)
219e86bddeaSKristof Provost 		q = p;
220e86bddeaSKristof Provost 	else
221e86bddeaSKristof Provost 		q++;
222e86bddeaSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
223e86bddeaSKristof Provost 	if (!*q) {
224e86bddeaSKristof Provost 		rs_free(p);
225e86bddeaSKristof Provost 		return (NULL);
226e86bddeaSKristof Provost 	}
227e86bddeaSKristof Provost 	while ((r = strchr(q, '/')) != NULL || *q) {
228e86bddeaSKristof Provost 		if (r != NULL)
229e86bddeaSKristof Provost 			*r = 0;
230e86bddeaSKristof Provost 		if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
231e86bddeaSKristof Provost 		    (parent != NULL && strlen(parent->path) >=
232e86bddeaSKristof Provost 		    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
233e86bddeaSKristof Provost 			rs_free(p);
234e86bddeaSKristof Provost 			return (NULL);
235e86bddeaSKristof Provost 		}
236e86bddeaSKristof Provost 		anchor = (struct pf_kanchor *)rs_malloc(sizeof(*anchor));
237e86bddeaSKristof Provost 		if (anchor == NULL) {
238e86bddeaSKristof Provost 			rs_free(p);
239e86bddeaSKristof Provost 			return (NULL);
240e86bddeaSKristof Provost 		}
241e86bddeaSKristof Provost 		RB_INIT(&anchor->children);
242e86bddeaSKristof Provost 		strlcpy(anchor->name, q, sizeof(anchor->name));
243e86bddeaSKristof Provost 		if (parent != NULL) {
244e86bddeaSKristof Provost 			strlcpy(anchor->path, parent->path,
245e86bddeaSKristof Provost 			    sizeof(anchor->path));
246e86bddeaSKristof Provost 			strlcat(anchor->path, "/", sizeof(anchor->path));
247e86bddeaSKristof Provost 		}
248e86bddeaSKristof Provost 		strlcat(anchor->path, anchor->name, sizeof(anchor->path));
249e86bddeaSKristof Provost 		if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
250e86bddeaSKristof Provost 		    NULL) {
251e86bddeaSKristof Provost 			printf("pf_find_or_create_ruleset: RB_INSERT1 "
252e86bddeaSKristof Provost 			    "'%s' '%s' collides with '%s' '%s'\n",
253e86bddeaSKristof Provost 			    anchor->path, anchor->name, dup->path, dup->name);
254e86bddeaSKristof Provost 			rs_free(anchor);
255e86bddeaSKristof Provost 			rs_free(p);
256e86bddeaSKristof Provost 			return (NULL);
257e86bddeaSKristof Provost 		}
258e86bddeaSKristof Provost 		if (parent != NULL) {
259e86bddeaSKristof Provost 			anchor->parent = parent;
260e86bddeaSKristof Provost 			if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
261e86bddeaSKristof Provost 			    anchor)) != NULL) {
262e86bddeaSKristof Provost 				printf("pf_find_or_create_ruleset: "
263e86bddeaSKristof Provost 				    "RB_INSERT2 '%s' '%s' collides with "
264e86bddeaSKristof Provost 				    "'%s' '%s'\n", anchor->path, anchor->name,
265e86bddeaSKristof Provost 				    dup->path, dup->name);
266e86bddeaSKristof Provost 				RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
267e86bddeaSKristof Provost 				    anchor);
268e86bddeaSKristof Provost 				rs_free(anchor);
269e86bddeaSKristof Provost 				rs_free(p);
270e86bddeaSKristof Provost 				return (NULL);
271e86bddeaSKristof Provost 			}
272e86bddeaSKristof Provost 		}
273e86bddeaSKristof Provost 		pf_init_kruleset(&anchor->ruleset);
274e86bddeaSKristof Provost 		anchor->ruleset.anchor = anchor;
275e86bddeaSKristof Provost 		parent = anchor;
276e86bddeaSKristof Provost 		if (r != NULL)
277e86bddeaSKristof Provost 			q = r + 1;
278e86bddeaSKristof Provost 		else
279e86bddeaSKristof Provost 			*q = 0;
280e86bddeaSKristof Provost 	}
281e86bddeaSKristof Provost 	rs_free(p);
282e86bddeaSKristof Provost 	return (&anchor->ruleset);
283e86bddeaSKristof Provost }
284e86bddeaSKristof Provost 
285e86bddeaSKristof Provost void
pf_remove_if_empty_kruleset(struct pf_kruleset * ruleset)286e86bddeaSKristof Provost pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
287e86bddeaSKristof Provost {
288e86bddeaSKristof Provost 	struct pf_kanchor	*parent;
289e86bddeaSKristof Provost 	int			 i;
290e86bddeaSKristof Provost 
291e86bddeaSKristof Provost 	while (ruleset != NULL) {
292e86bddeaSKristof Provost 		if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
293e86bddeaSKristof Provost 		    !RB_EMPTY(&ruleset->anchor->children) ||
294e86bddeaSKristof Provost 		    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
295e86bddeaSKristof Provost 		    ruleset->topen)
296e86bddeaSKristof Provost 			return;
297e86bddeaSKristof Provost 		for (i = 0; i < PF_RULESET_MAX; ++i)
298e86bddeaSKristof Provost 			if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
299e86bddeaSKristof Provost 			    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
300e86bddeaSKristof Provost 			    ruleset->rules[i].inactive.open)
301e86bddeaSKristof Provost 				return;
302e86bddeaSKristof Provost 		RB_REMOVE(pf_kanchor_global, &V_pf_anchors, ruleset->anchor);
303e86bddeaSKristof Provost 		if ((parent = ruleset->anchor->parent) != NULL)
304e86bddeaSKristof Provost 			RB_REMOVE(pf_kanchor_node, &parent->children,
305e86bddeaSKristof Provost 			    ruleset->anchor);
306e86bddeaSKristof Provost 		rs_free(ruleset->anchor);
307e86bddeaSKristof Provost 		if (parent == NULL)
308e86bddeaSKristof Provost 			return;
309e86bddeaSKristof Provost 		ruleset = &parent->ruleset;
310e86bddeaSKristof Provost 	}
311e86bddeaSKristof Provost }
312e86bddeaSKristof Provost 
313e86bddeaSKristof Provost int
pf_kanchor_setup(struct pf_krule * r,const struct pf_kruleset * s,const char * name)314e86bddeaSKristof Provost pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
315e86bddeaSKristof Provost     const char *name)
316e86bddeaSKristof Provost {
317e86bddeaSKristof Provost 	char			*p, *path;
318e86bddeaSKristof Provost 	struct pf_kruleset	*ruleset;
319e86bddeaSKristof Provost 
320e86bddeaSKristof Provost 	r->anchor = NULL;
321e86bddeaSKristof Provost 	r->anchor_relative = 0;
322e86bddeaSKristof Provost 	r->anchor_wildcard = 0;
323e86bddeaSKristof Provost 	if (!name[0])
324e86bddeaSKristof Provost 		return (0);
325e86bddeaSKristof Provost 	path = (char *)rs_malloc(MAXPATHLEN);
326e86bddeaSKristof Provost 	if (path == NULL)
327e86bddeaSKristof Provost 		return (1);
328e86bddeaSKristof Provost 	if (name[0] == '/')
329e86bddeaSKristof Provost 		strlcpy(path, name + 1, MAXPATHLEN);
330e86bddeaSKristof Provost 	else {
331e86bddeaSKristof Provost 		/* relative path */
332e86bddeaSKristof Provost 		r->anchor_relative = 1;
333e86bddeaSKristof Provost 		if (s->anchor == NULL || !s->anchor->path[0])
334e86bddeaSKristof Provost 			path[0] = 0;
335e86bddeaSKristof Provost 		else
336e86bddeaSKristof Provost 			strlcpy(path, s->anchor->path, MAXPATHLEN);
337e86bddeaSKristof Provost 		while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
338e86bddeaSKristof Provost 			if (!path[0]) {
33986b653edSKristof Provost 				DPFPRINTF("pf_anchor_setup: .. beyond root\n");
340e86bddeaSKristof Provost 				rs_free(path);
341e86bddeaSKristof Provost 				return (1);
342e86bddeaSKristof Provost 			}
343e86bddeaSKristof Provost 			if ((p = strrchr(path, '/')) != NULL)
344e86bddeaSKristof Provost 				*p = 0;
345e86bddeaSKristof Provost 			else
346e86bddeaSKristof Provost 				path[0] = 0;
347e86bddeaSKristof Provost 			r->anchor_relative++;
348e86bddeaSKristof Provost 			name += 3;
349e86bddeaSKristof Provost 		}
350e86bddeaSKristof Provost 		if (path[0])
351e86bddeaSKristof Provost 			strlcat(path, "/", MAXPATHLEN);
352e86bddeaSKristof Provost 		strlcat(path, name, MAXPATHLEN);
353e86bddeaSKristof Provost 	}
354e86bddeaSKristof Provost 	if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
355e86bddeaSKristof Provost 		r->anchor_wildcard = 1;
356e86bddeaSKristof Provost 		*p = 0;
357e86bddeaSKristof Provost 	}
358e86bddeaSKristof Provost 	ruleset = pf_find_or_create_kruleset(path);
359e86bddeaSKristof Provost 	rs_free(path);
360e86bddeaSKristof Provost 	if (ruleset == NULL || ruleset->anchor == NULL) {
36186b653edSKristof Provost 		DPFPRINTF("pf_anchor_setup: ruleset\n");
362e86bddeaSKristof Provost 		return (1);
363e86bddeaSKristof Provost 	}
364e86bddeaSKristof Provost 	r->anchor = ruleset->anchor;
365e86bddeaSKristof Provost 	r->anchor->refcnt++;
366e86bddeaSKristof Provost 	return (0);
367e86bddeaSKristof Provost }
368e86bddeaSKristof Provost 
369e86bddeaSKristof Provost int
pf_kanchor_copyout(const struct pf_kruleset * rs,const struct pf_krule * r,char * anchor_call,size_t anchor_call_len)370777a4702SKristof Provost pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
371*6ee3e376SKristof Provost     char *anchor_call, size_t anchor_call_len)
372d710367dSKristof Provost {
373777a4702SKristof Provost 	anchor_call[0] = 0;
374d710367dSKristof Provost 
375d710367dSKristof Provost 	if (r->anchor == NULL)
376d710367dSKristof Provost 		goto done;
377d710367dSKristof Provost 	if (!r->anchor_relative) {
378*6ee3e376SKristof Provost 		strlcpy(anchor_call, "/", anchor_call_len);
379d710367dSKristof Provost 		strlcat(anchor_call, r->anchor->path,
380*6ee3e376SKristof Provost 		    anchor_call_len);
381d710367dSKristof Provost 	} else {
382d710367dSKristof Provost 		char	 a[MAXPATHLEN];
383d710367dSKristof Provost 		char	*p;
384d710367dSKristof Provost 		int	 i;
385d710367dSKristof Provost 		if (rs->anchor == NULL)
386d710367dSKristof Provost 			a[0] = 0;
387d710367dSKristof Provost 		else
388d710367dSKristof Provost 			strlcpy(a, rs->anchor->path, MAXPATHLEN);
389d710367dSKristof Provost 		for (i = 1; i < r->anchor_relative; ++i) {
390d710367dSKristof Provost 			if ((p = strrchr(a, '/')) == NULL)
391d710367dSKristof Provost 				p = a;
392d710367dSKristof Provost 			*p = 0;
393d710367dSKristof Provost 			strlcat(anchor_call, "../",
394*6ee3e376SKristof Provost 			    anchor_call_len);
395d710367dSKristof Provost 		}
396d710367dSKristof Provost 		if (strncmp(a, r->anchor->path, strlen(a))) {
397d710367dSKristof Provost 			printf("pf_anchor_copyout: '%s' '%s'\n", a,
398d710367dSKristof Provost 			    r->anchor->path);
399d710367dSKristof Provost 			return (1);
400d710367dSKristof Provost 		}
401d710367dSKristof Provost 		if (strlen(r->anchor->path) > strlen(a))
402d710367dSKristof Provost 			strlcat(anchor_call, r->anchor->path + (a[0] ?
403*6ee3e376SKristof Provost 			    strlen(a) + 1 : 0), anchor_call_len);
404d710367dSKristof Provost 
405d710367dSKristof Provost 	}
406d710367dSKristof Provost 	if (r->anchor_wildcard)
407d710367dSKristof Provost 		strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
408*6ee3e376SKristof Provost 		    anchor_call_len);
409d710367dSKristof Provost 
410d710367dSKristof Provost done:
411d710367dSKristof Provost 
412d710367dSKristof Provost 	return (0);
413d710367dSKristof Provost }
414d710367dSKristof Provost 
415d710367dSKristof Provost int
pf_kanchor_nvcopyout(const struct pf_kruleset * rs,const struct pf_krule * r,nvlist_t * nvl)416777a4702SKristof Provost pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
417777a4702SKristof Provost     nvlist_t *nvl)
418777a4702SKristof Provost {
419777a4702SKristof Provost 	char anchor_call[MAXPATHLEN] = { 0 };
420777a4702SKristof Provost 	int ret;
421777a4702SKristof Provost 
422*6ee3e376SKristof Provost 	ret = pf_kanchor_copyout(rs, r, anchor_call, sizeof(anchor_call));
423777a4702SKristof Provost 	MPASS(ret == 0);
424777a4702SKristof Provost 
425777a4702SKristof Provost 	nvlist_add_string(nvl, "anchor_call", anchor_call);
426777a4702SKristof Provost 
427777a4702SKristof Provost 	return (ret);
428777a4702SKristof Provost }
429777a4702SKristof Provost 
430777a4702SKristof Provost int
pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset * rs,const struct pf_keth_rule * r,nvlist_t * nvl)431c5131afeSKristof Provost pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
432c5131afeSKristof Provost     const struct pf_keth_rule *r, nvlist_t *nvl)
433c5131afeSKristof Provost {
434c5131afeSKristof Provost 	char anchor_call[MAXPATHLEN] = { 0 };
435c5131afeSKristof Provost 
436c5131afeSKristof Provost 	if (r->anchor == NULL)
437c5131afeSKristof Provost 		goto done;
438c5131afeSKristof Provost 	if (!r->anchor_relative) {
439c5131afeSKristof Provost 		strlcpy(anchor_call, "/", sizeof(anchor_call));
440c5131afeSKristof Provost 		strlcat(anchor_call, r->anchor->path,
441c5131afeSKristof Provost 		    sizeof(anchor_call));
442c5131afeSKristof Provost 	} else {
443c5131afeSKristof Provost 		char	 a[MAXPATHLEN];
444c5131afeSKristof Provost 		char	*p;
445c5131afeSKristof Provost 		int	 i;
446c5131afeSKristof Provost 		if (rs->anchor == NULL)
447c5131afeSKristof Provost 			a[0] = 0;
448c5131afeSKristof Provost 		else
449c5131afeSKristof Provost 			strlcpy(a, rs->anchor->path, MAXPATHLEN);
450c5131afeSKristof Provost 		for (i = 1; i < r->anchor_relative; ++i) {
451c5131afeSKristof Provost 			if ((p = strrchr(a, '/')) == NULL)
452c5131afeSKristof Provost 				p = a;
453c5131afeSKristof Provost 			*p = 0;
454c5131afeSKristof Provost 			strlcat(anchor_call, "../",
455c5131afeSKristof Provost 			    sizeof(anchor_call));
456c5131afeSKristof Provost 		}
457c5131afeSKristof Provost 		if (strncmp(a, r->anchor->path, strlen(a))) {
458c5131afeSKristof Provost 			printf("%s(): '%s' '%s'\n", __func__, a,
459c5131afeSKristof Provost 			    r->anchor->path);
460c5131afeSKristof Provost 			return (1);
461c5131afeSKristof Provost 		}
462c5131afeSKristof Provost 		if (strlen(r->anchor->path) > strlen(a))
463c5131afeSKristof Provost 			strlcat(anchor_call, r->anchor->path + (a[0] ?
464c5131afeSKristof Provost 			    strlen(a) + 1 : 0), sizeof(anchor_call));
465c5131afeSKristof Provost 
466c5131afeSKristof Provost 	}
467c5131afeSKristof Provost 	if (r->anchor_wildcard)
468c5131afeSKristof Provost 		strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
469c5131afeSKristof Provost 		    sizeof(anchor_call));
470c5131afeSKristof Provost 
471c5131afeSKristof Provost done:
472c5131afeSKristof Provost 	nvlist_add_string(nvl, "anchor_call", anchor_call);
473c5131afeSKristof Provost 
474c5131afeSKristof Provost 	return (0);
475c5131afeSKristof Provost }
476c5131afeSKristof Provost 
477e86bddeaSKristof Provost void
pf_kanchor_remove(struct pf_krule * r)478e86bddeaSKristof Provost pf_kanchor_remove(struct pf_krule *r)
479e86bddeaSKristof Provost {
480e86bddeaSKristof Provost 	if (r->anchor == NULL)
481e86bddeaSKristof Provost 		return;
482e86bddeaSKristof Provost 	if (r->anchor->refcnt <= 0) {
483e86bddeaSKristof Provost 		printf("pf_anchor_remove: broken refcount\n");
484e86bddeaSKristof Provost 		r->anchor = NULL;
485e86bddeaSKristof Provost 		return;
486e86bddeaSKristof Provost 	}
487e86bddeaSKristof Provost 	if (!--r->anchor->refcnt)
488e86bddeaSKristof Provost 		pf_remove_if_empty_kruleset(&r->anchor->ruleset);
489e86bddeaSKristof Provost 	r->anchor = NULL;
490e86bddeaSKristof Provost }
491c5131afeSKristof Provost 
492c5131afeSKristof Provost struct pf_keth_ruleset *
pf_find_keth_ruleset(const char * path)493c5131afeSKristof Provost pf_find_keth_ruleset(const char *path)
494c5131afeSKristof Provost {
495c5131afeSKristof Provost 	struct pf_keth_anchor	*anchor;
496c5131afeSKristof Provost 
497c5131afeSKristof Provost 	while (*path == '/')
498c5131afeSKristof Provost 		path++;
499c5131afeSKristof Provost 	if (!*path)
500c5131afeSKristof Provost 		return (V_pf_keth);
501c5131afeSKristof Provost 	anchor = pf_find_keth_anchor(path);
502c5131afeSKristof Provost 	if (anchor == NULL)
503c5131afeSKristof Provost 		return (NULL);
504c5131afeSKristof Provost 	else
505c5131afeSKristof Provost 		return (&anchor->ruleset);
506c5131afeSKristof Provost }
507c5131afeSKristof Provost 
508c5131afeSKristof Provost static struct pf_keth_anchor *
_pf_find_keth_anchor(struct pf_keth_ruleset * rs,const char * path)509c5131afeSKristof Provost _pf_find_keth_anchor(struct pf_keth_ruleset *rs, const char *path)
510c5131afeSKristof Provost {
511c5131afeSKristof Provost 	struct pf_keth_anchor	*key, *found;
512c5131afeSKristof Provost 
513c5131afeSKristof Provost 	key = (struct pf_keth_anchor *)rs_malloc(sizeof(*key));
514c5131afeSKristof Provost 	if (key == NULL)
515c5131afeSKristof Provost 		return (NULL);
516c5131afeSKristof Provost 	strlcpy(key->path, path, sizeof(key->path));
517c5131afeSKristof Provost 	found = RB_FIND(pf_keth_anchor_global, &V_pf_keth_anchors, key);
518c5131afeSKristof Provost 	rs_free(key);
519c5131afeSKristof Provost 	return (found);
520c5131afeSKristof Provost }
521c5131afeSKristof Provost 
522c5131afeSKristof Provost struct pf_keth_anchor *
pf_find_keth_anchor(const char * path)523c5131afeSKristof Provost pf_find_keth_anchor(const char *path)
524c5131afeSKristof Provost {
525c5131afeSKristof Provost 	return (_pf_find_keth_anchor(V_pf_keth, path));
526c5131afeSKristof Provost }
527c5131afeSKristof Provost 
528c5131afeSKristof Provost struct pf_keth_ruleset *
pf_find_or_create_keth_ruleset(const char * path)529c5131afeSKristof Provost pf_find_or_create_keth_ruleset(const char *path)
530c5131afeSKristof Provost {
531c5131afeSKristof Provost 	char			*p, *q, *r;
532c5131afeSKristof Provost 	struct pf_keth_anchor	*anchor = NULL, *dup = NULL, *parent = NULL;
533c5131afeSKristof Provost 	struct pf_keth_ruleset	*ruleset;
534c5131afeSKristof Provost 
535c5131afeSKristof Provost 	if (path[0] == 0)
536c5131afeSKristof Provost 		return (V_pf_keth);
537c5131afeSKristof Provost 	while (*path == '/')
538c5131afeSKristof Provost 		path++;
539c5131afeSKristof Provost 	ruleset = pf_find_keth_ruleset(path);
540c5131afeSKristof Provost 	if (ruleset != NULL)
541c5131afeSKristof Provost 		return (ruleset);
542c5131afeSKristof Provost 	p = (char *)rs_malloc(MAXPATHLEN);
543c5131afeSKristof Provost 	if (p == NULL)
544c5131afeSKristof Provost 		return (NULL);
545c5131afeSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
546c5131afeSKristof Provost 	while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
547c5131afeSKristof Provost 		*q = 0;
548c5131afeSKristof Provost 		if ((ruleset = pf_find_keth_ruleset(p)) != NULL) {
549c5131afeSKristof Provost 			parent = ruleset->anchor;
550c5131afeSKristof Provost 			break;
551c5131afeSKristof Provost 		}
552c5131afeSKristof Provost 	}
553c5131afeSKristof Provost 	if (q == NULL)
554c5131afeSKristof Provost 		q = p;
555c5131afeSKristof Provost 	else
556c5131afeSKristof Provost 		q++;
557c5131afeSKristof Provost 	strlcpy(p, path, MAXPATHLEN);
558c5131afeSKristof Provost 	if (!*q) {
559c5131afeSKristof Provost 		rs_free(p);
560c5131afeSKristof Provost 		return (NULL);
561c5131afeSKristof Provost 	}
562c5131afeSKristof Provost 	while ((r = strchr(q, '/')) != NULL || *q) {
563c5131afeSKristof Provost 		if (r != NULL)
564c5131afeSKristof Provost 			*r = 0;
565c5131afeSKristof Provost 		if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
566c5131afeSKristof Provost 		    (parent != NULL && strlen(parent->path) >=
567c5131afeSKristof Provost 		    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
568c5131afeSKristof Provost 			rs_free(p);
569c5131afeSKristof Provost 			return (NULL);
570c5131afeSKristof Provost 		}
571c5131afeSKristof Provost 		anchor = (struct pf_keth_anchor *)rs_malloc(sizeof(*anchor));
572c5131afeSKristof Provost 		if (anchor == NULL) {
573c5131afeSKristof Provost 			rs_free(p);
574c5131afeSKristof Provost 			return (NULL);
575c5131afeSKristof Provost 		}
576c5131afeSKristof Provost 		RB_INIT(&anchor->children);
577c5131afeSKristof Provost 		strlcpy(anchor->name, q, sizeof(anchor->name));
578c5131afeSKristof Provost 		if (parent != NULL) {
579c5131afeSKristof Provost 			strlcpy(anchor->path, parent->path,
580c5131afeSKristof Provost 			    sizeof(anchor->path));
581c5131afeSKristof Provost 			strlcat(anchor->path, "/", sizeof(anchor->path));
582c5131afeSKristof Provost 		}
583c5131afeSKristof Provost 		strlcat(anchor->path, anchor->name, sizeof(anchor->path));
584c5131afeSKristof Provost 		if ((dup = RB_INSERT(pf_keth_anchor_global, &V_pf_keth_anchors, anchor)) !=
585c5131afeSKristof Provost 		    NULL) {
586c5131afeSKristof Provost 			printf("%s: RB_INSERT1 "
587c5131afeSKristof Provost 			    "'%s' '%s' collides with '%s' '%s'\n", __func__,
588c5131afeSKristof Provost 			    anchor->path, anchor->name, dup->path, dup->name);
589c5131afeSKristof Provost 			rs_free(anchor);
590c5131afeSKristof Provost 			rs_free(p);
591c5131afeSKristof Provost 			return (NULL);
592c5131afeSKristof Provost 		}
593c5131afeSKristof Provost 		if (parent != NULL) {
594c5131afeSKristof Provost 			anchor->parent = parent;
595c5131afeSKristof Provost 			if ((dup = RB_INSERT(pf_keth_anchor_node, &parent->children,
596c5131afeSKristof Provost 			    anchor)) != NULL) {
597c5131afeSKristof Provost 				printf("%s: "
598c5131afeSKristof Provost 				    "RB_INSERT2 '%s' '%s' collides with "
599c5131afeSKristof Provost 				    "'%s' '%s'\n", __func__, anchor->path,
600c5131afeSKristof Provost 				    anchor->name, dup->path, dup->name);
601c5131afeSKristof Provost 				RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors,
602c5131afeSKristof Provost 				    anchor);
603c5131afeSKristof Provost 				rs_free(anchor);
604c5131afeSKristof Provost 				rs_free(p);
605c5131afeSKristof Provost 				return (NULL);
606c5131afeSKristof Provost 			}
607c5131afeSKristof Provost 		}
608c5131afeSKristof Provost 		pf_init_keth(&anchor->ruleset);
609c5131afeSKristof Provost 		anchor->ruleset.anchor = anchor;
610c5131afeSKristof Provost 		parent = anchor;
611c5131afeSKristof Provost 		if (r != NULL)
612c5131afeSKristof Provost 			q = r + 1;
613c5131afeSKristof Provost 		else
614c5131afeSKristof Provost 			*q = 0;
615c5131afeSKristof Provost 	}
616c5131afeSKristof Provost 	rs_free(p);
617c5131afeSKristof Provost 	return (&anchor->ruleset);
618c5131afeSKristof Provost }
619c5131afeSKristof Provost 
620c5131afeSKristof Provost int
pf_keth_anchor_setup(struct pf_keth_rule * r,const struct pf_keth_ruleset * s,const char * name)621c5131afeSKristof Provost pf_keth_anchor_setup(struct pf_keth_rule *r, const struct pf_keth_ruleset *s,
622c5131afeSKristof Provost     const char *name)
623c5131afeSKristof Provost {
624c5131afeSKristof Provost 	char			*p, *path;
625c5131afeSKristof Provost 	struct pf_keth_ruleset	*ruleset;
626c5131afeSKristof Provost 
627c5131afeSKristof Provost 	r->anchor = NULL;
628c5131afeSKristof Provost 	r->anchor_relative = 0;
629c5131afeSKristof Provost 	r->anchor_wildcard = 0;
630c5131afeSKristof Provost 	if (!name[0])
631c5131afeSKristof Provost 		return (0);
632c5131afeSKristof Provost 	path = (char *)rs_malloc(MAXPATHLEN);
633c5131afeSKristof Provost 	if (path == NULL)
634c5131afeSKristof Provost 		return (1);
635c5131afeSKristof Provost 	if (name[0] == '/')
636c5131afeSKristof Provost 		strlcpy(path, name + 1, MAXPATHLEN);
637c5131afeSKristof Provost 	else {
638c5131afeSKristof Provost 		/* relative path */
639c5131afeSKristof Provost 		r->anchor_relative = 1;
640c5131afeSKristof Provost 		if (s->anchor == NULL || !s->anchor->path[0])
641c5131afeSKristof Provost 			path[0] = 0;
642c5131afeSKristof Provost 		else
643c5131afeSKristof Provost 			strlcpy(path, s->anchor->path, MAXPATHLEN);
644c5131afeSKristof Provost 		while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
645c5131afeSKristof Provost 			if (!path[0]) {
646c5131afeSKristof Provost 				DPFPRINTF("pf_anchor_setup: .. beyond root\n");
647c5131afeSKristof Provost 				rs_free(path);
648c5131afeSKristof Provost 				return (1);
649c5131afeSKristof Provost 			}
650c5131afeSKristof Provost 			if ((p = strrchr(path, '/')) != NULL)
651c5131afeSKristof Provost 				*p = 0;
652c5131afeSKristof Provost 			else
653c5131afeSKristof Provost 				path[0] = 0;
654c5131afeSKristof Provost 			r->anchor_relative++;
655c5131afeSKristof Provost 			name += 3;
656c5131afeSKristof Provost 		}
657c5131afeSKristof Provost 		if (path[0])
658c5131afeSKristof Provost 			strlcat(path, "/", MAXPATHLEN);
659c5131afeSKristof Provost 		strlcat(path, name, MAXPATHLEN);
660c5131afeSKristof Provost 	}
661c5131afeSKristof Provost 	if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
662c5131afeSKristof Provost 		r->anchor_wildcard = 1;
663c5131afeSKristof Provost 		*p = 0;
664c5131afeSKristof Provost 	}
665c5131afeSKristof Provost 	ruleset = pf_find_or_create_keth_ruleset(path);
666c5131afeSKristof Provost 	rs_free(path);
667c5131afeSKristof Provost 	if (ruleset == NULL || ruleset->anchor == NULL) {
668c5131afeSKristof Provost 		DPFPRINTF("pf_anchor_setup: ruleset\n");
669c5131afeSKristof Provost 		return (1);
670c5131afeSKristof Provost 	}
671c5131afeSKristof Provost 	r->anchor = ruleset->anchor;
672c5131afeSKristof Provost 	r->anchor->refcnt++;
673c5131afeSKristof Provost 	return (0);
674c5131afeSKristof Provost }
675c5131afeSKristof Provost 
676c5131afeSKristof Provost void
pf_keth_anchor_remove(struct pf_keth_rule * r)677c5131afeSKristof Provost pf_keth_anchor_remove(struct pf_keth_rule *r)
678c5131afeSKristof Provost {
679c5131afeSKristof Provost 	if (r->anchor == NULL)
680c5131afeSKristof Provost 		return;
681c5131afeSKristof Provost 	if (r->anchor->refcnt <= 0) {
682c5131afeSKristof Provost 		printf("%s: broken refcount\n", __func__);
683c5131afeSKristof Provost 		r->anchor = NULL;
684c5131afeSKristof Provost 		return;
685c5131afeSKristof Provost 	}
686c5131afeSKristof Provost 	if (!--r->anchor->refcnt)
687c5131afeSKristof Provost 		pf_remove_if_empty_keth_ruleset(&r->anchor->ruleset);
688c5131afeSKristof Provost 	r->anchor = NULL;
689c5131afeSKristof Provost }
690c5131afeSKristof Provost 
691c5131afeSKristof Provost void
pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset * ruleset)692c5131afeSKristof Provost pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset *ruleset)
693c5131afeSKristof Provost {
694c5131afeSKristof Provost 	struct pf_keth_anchor	*parent;
695c5131afeSKristof Provost 	int			 i;
696c5131afeSKristof Provost 
697c5131afeSKristof Provost 	while (ruleset != NULL) {
698c5131afeSKristof Provost 		if (ruleset == V_pf_keth || ruleset->anchor == NULL ||
699c5131afeSKristof Provost 		    !RB_EMPTY(&ruleset->anchor->children) ||
700c5131afeSKristof Provost 		    ruleset->anchor->refcnt > 0)
701c5131afeSKristof Provost 			return;
702c5131afeSKristof Provost 		for (i = 0; i < PF_RULESET_MAX; ++i)
703c5131afeSKristof Provost 			if (!TAILQ_EMPTY(ruleset->active.rules) ||
704c5131afeSKristof Provost 			    !TAILQ_EMPTY(ruleset->inactive.rules) ||
705c5131afeSKristof Provost 			    ruleset->inactive.open)
706c5131afeSKristof Provost 				return;
707c5131afeSKristof Provost 		RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors, ruleset->anchor);
708c5131afeSKristof Provost 		if ((parent = ruleset->anchor->parent) != NULL)
709c5131afeSKristof Provost 			RB_REMOVE(pf_keth_anchor_node, &parent->children,
710c5131afeSKristof Provost 			    ruleset->anchor);
711c5131afeSKristof Provost 		rs_free(ruleset->anchor);
712c5131afeSKristof Provost 		if (parent == NULL)
713c5131afeSKristof Provost 			return;
714c5131afeSKristof Provost 		ruleset = &parent->ruleset;
715c5131afeSKristof Provost 	}
716c5131afeSKristof Provost }
717