Home | History | Annotate | Line # | Download | only in net
      1  1.2  yamt /*	$NetBSD: pf_ruleset.c,v 1.2 2008/06/18 09:06:27 yamt Exp $ */
      2  1.2  yamt /*	$OpenBSD: pf_ruleset.c,v 1.1 2006/10/27 13:56:51 mcbride Exp $ */
      3  1.2  yamt 
      4  1.2  yamt /*
      5  1.2  yamt  * Copyright (c) 2001 Daniel Hartmeier
      6  1.2  yamt  * Copyright (c) 2002,2003 Henning Brauer
      7  1.2  yamt  * All rights reserved.
      8  1.2  yamt  *
      9  1.2  yamt  * Redistribution and use in source and binary forms, with or without
     10  1.2  yamt  * modification, are permitted provided that the following conditions
     11  1.2  yamt  * are met:
     12  1.2  yamt  *
     13  1.2  yamt  *    - Redistributions of source code must retain the above copyright
     14  1.2  yamt  *      notice, this list of conditions and the following disclaimer.
     15  1.2  yamt  *    - Redistributions in binary form must reproduce the above
     16  1.2  yamt  *      copyright notice, this list of conditions and the following
     17  1.2  yamt  *      disclaimer in the documentation and/or other materials provided
     18  1.2  yamt  *      with the distribution.
     19  1.2  yamt  *
     20  1.2  yamt  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  1.2  yamt  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  1.2  yamt  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     23  1.2  yamt  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     24  1.2  yamt  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  1.2  yamt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     26  1.2  yamt  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27  1.2  yamt  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     28  1.2  yamt  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  1.2  yamt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     30  1.2  yamt  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  1.2  yamt  * POSSIBILITY OF SUCH DAMAGE.
     32  1.2  yamt  *
     33  1.2  yamt  * Effort sponsored in part by the Defense Advanced Research Projects
     34  1.2  yamt  * Agency (DARPA) and Air Force Research Laboratory, Air Force
     35  1.2  yamt  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
     36  1.2  yamt  *
     37  1.2  yamt  */
     38  1.2  yamt 
     39  1.2  yamt #include <sys/cdefs.h>
     40  1.2  yamt __KERNEL_RCSID(0, "$NetBSD: pf_ruleset.c,v 1.2 2008/06/18 09:06:27 yamt Exp $");
     41  1.2  yamt 
     42  1.2  yamt #include <sys/param.h>
     43  1.2  yamt #include <sys/socket.h>
     44  1.2  yamt #ifdef _KERNEL
     45  1.2  yamt # include <sys/systm.h>
     46  1.2  yamt #endif /* _KERNEL */
     47  1.2  yamt #include <sys/mbuf.h>
     48  1.2  yamt 
     49  1.2  yamt #include <netinet/in.h>
     50  1.2  yamt #include <netinet/in_systm.h>
     51  1.2  yamt #include <netinet/ip.h>
     52  1.2  yamt #include <netinet/tcp.h>
     53  1.2  yamt 
     54  1.2  yamt #include <net/if.h>
     55  1.2  yamt #include <net/pfvar.h>
     56  1.2  yamt 
     57  1.2  yamt #ifdef INET6
     58  1.2  yamt #include <netinet/ip6.h>
     59  1.2  yamt #endif /* INET6 */
     60  1.2  yamt 
     61  1.2  yamt 
     62  1.2  yamt #ifdef _KERNEL
     63  1.2  yamt # define DPFPRINTF(format, x...)		\
     64  1.2  yamt 	if (pf_status.debug >= PF_DEBUG_NOISY)	\
     65  1.2  yamt 		printf(format , ##x)
     66  1.2  yamt #define rs_malloc(x)		malloc(x, M_TEMP, M_WAITOK)
     67  1.2  yamt #define rs_free(x)		free(x, M_TEMP)
     68  1.2  yamt 
     69  1.2  yamt #else
     70  1.2  yamt /* Userland equivalents so we can lend code to pfctl et al. */
     71  1.2  yamt 
     72  1.2  yamt # include <arpa/inet.h>
     73  1.2  yamt # include <errno.h>
     74  1.2  yamt # include <stdio.h>
     75  1.2  yamt # include <stdlib.h>
     76  1.2  yamt # include <string.h>
     77  1.2  yamt # define rs_malloc(x)		 malloc(x)
     78  1.2  yamt # define rs_free(x)		 free(x)
     79  1.2  yamt 
     80  1.2  yamt # ifdef PFDEBUG
     81  1.2  yamt #  include <sys/stdarg.h>
     82  1.2  yamt #  define DPFPRINTF(format, x...)	fprintf(stderr, format , ##x)
     83  1.2  yamt # else
     84  1.2  yamt #  define DPFPRINTF(format, x...)	((void)0)
     85  1.2  yamt # endif /* PFDEBUG */
     86  1.2  yamt #endif /* _KERNEL */
     87  1.2  yamt 
     88  1.2  yamt 
     89  1.2  yamt struct pf_anchor_global	 pf_anchors;
     90  1.2  yamt struct pf_anchor	 pf_main_anchor;
     91  1.2  yamt 
     92  1.2  yamt int			 pf_get_ruleset_number(u_int8_t);
     93  1.2  yamt void			 pf_init_ruleset(struct pf_ruleset *);
     94  1.2  yamt int			 pf_anchor_setup(struct pf_rule *,
     95  1.2  yamt 			    const struct pf_ruleset *, const char *);
     96  1.2  yamt int			 pf_anchor_copyout(const struct pf_ruleset *,
     97  1.2  yamt 			    const struct pf_rule *, struct pfioc_rule *);
     98  1.2  yamt void			 pf_anchor_remove(struct pf_rule *);
     99  1.2  yamt 
    100  1.2  yamt static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
    101  1.2  yamt 
    102  1.2  yamt RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
    103  1.2  yamt RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
    104  1.2  yamt 
    105  1.2  yamt static __inline int
    106  1.2  yamt pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
    107  1.2  yamt {
    108  1.2  yamt 	int c = strcmp(a->path, b->path);
    109  1.2  yamt 
    110  1.2  yamt 	return (c ? (c < 0 ? -1 : 1) : 0);
    111  1.2  yamt }
    112  1.2  yamt 
    113  1.2  yamt int
    114  1.2  yamt pf_get_ruleset_number(u_int8_t action)
    115  1.2  yamt {
    116  1.2  yamt 	switch (action) {
    117  1.2  yamt 	case PF_SCRUB:
    118  1.2  yamt 	case PF_NOSCRUB:
    119  1.2  yamt 		return (PF_RULESET_SCRUB);
    120  1.2  yamt 		break;
    121  1.2  yamt 	case PF_PASS:
    122  1.2  yamt 	case PF_DROP:
    123  1.2  yamt 		return (PF_RULESET_FILTER);
    124  1.2  yamt 		break;
    125  1.2  yamt 	case PF_NAT:
    126  1.2  yamt 	case PF_NONAT:
    127  1.2  yamt 		return (PF_RULESET_NAT);
    128  1.2  yamt 		break;
    129  1.2  yamt 	case PF_BINAT:
    130  1.2  yamt 	case PF_NOBINAT:
    131  1.2  yamt 		return (PF_RULESET_BINAT);
    132  1.2  yamt 		break;
    133  1.2  yamt 	case PF_RDR:
    134  1.2  yamt 	case PF_NORDR:
    135  1.2  yamt 		return (PF_RULESET_RDR);
    136  1.2  yamt 		break;
    137  1.2  yamt 	default:
    138  1.2  yamt 		return (PF_RULESET_MAX);
    139  1.2  yamt 		break;
    140  1.2  yamt 	}
    141  1.2  yamt }
    142  1.2  yamt 
    143  1.2  yamt void
    144  1.2  yamt pf_init_ruleset(struct pf_ruleset *ruleset)
    145  1.2  yamt {
    146  1.2  yamt 	int	i;
    147  1.2  yamt 
    148  1.2  yamt 	memset(ruleset, 0, sizeof(struct pf_ruleset));
    149  1.2  yamt 	for (i = 0; i < PF_RULESET_MAX; i++) {
    150  1.2  yamt 		TAILQ_INIT(&ruleset->rules[i].queues[0]);
    151  1.2  yamt 		TAILQ_INIT(&ruleset->rules[i].queues[1]);
    152  1.2  yamt 		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
    153  1.2  yamt 		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
    154  1.2  yamt 	}
    155  1.2  yamt }
    156  1.2  yamt 
    157  1.2  yamt struct pf_anchor *
    158  1.2  yamt pf_find_anchor(const char *path)
    159  1.2  yamt {
    160  1.2  yamt 	struct pf_anchor	*key, *found;
    161  1.2  yamt 
    162  1.2  yamt 	key = (struct pf_anchor *)rs_malloc(sizeof(*key));
    163  1.2  yamt 	memset(key, 0, sizeof(*key));
    164  1.2  yamt 	strlcpy(key->path, path, sizeof(key->path));
    165  1.2  yamt 	found = RB_FIND(pf_anchor_global, &pf_anchors, key);
    166  1.2  yamt 	rs_free(key);
    167  1.2  yamt 	return (found);
    168  1.2  yamt }
    169  1.2  yamt 
    170  1.2  yamt struct pf_ruleset *
    171  1.2  yamt pf_find_ruleset(const char *path)
    172  1.2  yamt {
    173  1.2  yamt 	struct pf_anchor	*anchor;
    174  1.2  yamt 
    175  1.2  yamt 	while (*path == '/')
    176  1.2  yamt 		path++;
    177  1.2  yamt 	if (!*path)
    178  1.2  yamt 		return (&pf_main_ruleset);
    179  1.2  yamt 	anchor = pf_find_anchor(path);
    180  1.2  yamt 	if (anchor == NULL)
    181  1.2  yamt 		return (NULL);
    182  1.2  yamt 	else
    183  1.2  yamt 		return (&anchor->ruleset);
    184  1.2  yamt }
    185  1.2  yamt 
    186  1.2  yamt struct pf_ruleset *
    187  1.2  yamt pf_find_or_create_ruleset(const char *path)
    188  1.2  yamt {
    189  1.2  yamt 	char			*p, *q, *r;
    190  1.2  yamt 	struct pf_ruleset	*ruleset;
    191  1.2  yamt 	struct pf_anchor	*anchor = NULL /* XXX gcc */;
    192  1.2  yamt 	struct pf_anchor	*dup, *parent = NULL;
    193  1.2  yamt 
    194  1.2  yamt 	if (path[0] == 0)
    195  1.2  yamt 		return (&pf_main_ruleset);
    196  1.2  yamt 	while (*path == '/')
    197  1.2  yamt 		path++;
    198  1.2  yamt 	ruleset = pf_find_ruleset(path);
    199  1.2  yamt 	if (ruleset != NULL)
    200  1.2  yamt 		return (ruleset);
    201  1.2  yamt 	p = (char *)rs_malloc(MAXPATHLEN);
    202  1.2  yamt 	bzero(p, MAXPATHLEN);
    203  1.2  yamt 	strlcpy(p, path, MAXPATHLEN);
    204  1.2  yamt 	while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
    205  1.2  yamt 		*q = 0;
    206  1.2  yamt 		if ((ruleset = pf_find_ruleset(p)) != NULL) {
    207  1.2  yamt 			parent = ruleset->anchor;
    208  1.2  yamt 			break;
    209  1.2  yamt 		}
    210  1.2  yamt 	}
    211  1.2  yamt 	if (q == NULL)
    212  1.2  yamt 		q = p;
    213  1.2  yamt 	else
    214  1.2  yamt 		q++;
    215  1.2  yamt 	strlcpy(p, path, MAXPATHLEN);
    216  1.2  yamt 	if (!*q) {
    217  1.2  yamt 		rs_free(p);
    218  1.2  yamt 		return (NULL);
    219  1.2  yamt 	}
    220  1.2  yamt 	while ((r = strchr(q, '/')) != NULL || *q) {
    221  1.2  yamt 		if (r != NULL)
    222  1.2  yamt 			*r = 0;
    223  1.2  yamt 		if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
    224  1.2  yamt 		    (parent != NULL && strlen(parent->path) >=
    225  1.2  yamt 		    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
    226  1.2  yamt 			rs_free(p);
    227  1.2  yamt 			return (NULL);
    228  1.2  yamt 		}
    229  1.2  yamt 		anchor = (struct pf_anchor *)rs_malloc(sizeof(*anchor));
    230  1.2  yamt 		if (anchor == NULL) {
    231  1.2  yamt 			rs_free(p);
    232  1.2  yamt 			return (NULL);
    233  1.2  yamt 		}
    234  1.2  yamt 		memset(anchor, 0, sizeof(*anchor));
    235  1.2  yamt 		RB_INIT(&anchor->children);
    236  1.2  yamt 		strlcpy(anchor->name, q, sizeof(anchor->name));
    237  1.2  yamt 		if (parent != NULL) {
    238  1.2  yamt 			strlcpy(anchor->path, parent->path,
    239  1.2  yamt 			    sizeof(anchor->path));
    240  1.2  yamt 			strlcat(anchor->path, "/", sizeof(anchor->path));
    241  1.2  yamt 		}
    242  1.2  yamt 		strlcat(anchor->path, anchor->name, sizeof(anchor->path));
    243  1.2  yamt 		if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
    244  1.2  yamt 		    NULL) {
    245  1.2  yamt 			printf("pf_find_or_create_ruleset: RB_INSERT1 "
    246  1.2  yamt 			    "'%s' '%s' collides with '%s' '%s'\n",
    247  1.2  yamt 			    anchor->path, anchor->name, dup->path, dup->name);
    248  1.2  yamt 			rs_free(anchor);
    249  1.2  yamt 			rs_free(p);
    250  1.2  yamt 			return (NULL);
    251  1.2  yamt 		}
    252  1.2  yamt 		if (parent != NULL) {
    253  1.2  yamt 			anchor->parent = parent;
    254  1.2  yamt 			if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
    255  1.2  yamt 			    anchor)) != NULL) {
    256  1.2  yamt 				printf("pf_find_or_create_ruleset: "
    257  1.2  yamt 				    "RB_INSERT2 '%s' '%s' collides with "
    258  1.2  yamt 				    "'%s' '%s'\n", anchor->path, anchor->name,
    259  1.2  yamt 				    dup->path, dup->name);
    260  1.2  yamt 				RB_REMOVE(pf_anchor_global, &pf_anchors,
    261  1.2  yamt 				    anchor);
    262  1.2  yamt 				rs_free(anchor);
    263  1.2  yamt 				rs_free(p);
    264  1.2  yamt 				return (NULL);
    265  1.2  yamt 			}
    266  1.2  yamt 		}
    267  1.2  yamt 		pf_init_ruleset(&anchor->ruleset);
    268  1.2  yamt 		anchor->ruleset.anchor = anchor;
    269  1.2  yamt 		parent = anchor;
    270  1.2  yamt 		if (r != NULL)
    271  1.2  yamt 			q = r + 1;
    272  1.2  yamt 		else
    273  1.2  yamt 			*q = 0;
    274  1.2  yamt 	}
    275  1.2  yamt 	rs_free(p);
    276  1.2  yamt 	return (&anchor->ruleset);
    277  1.2  yamt }
    278  1.2  yamt 
    279  1.2  yamt void
    280  1.2  yamt pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
    281  1.2  yamt {
    282  1.2  yamt 	struct pf_anchor	*parent;
    283  1.2  yamt 	int			 i;
    284  1.2  yamt 
    285  1.2  yamt 	while (ruleset != NULL) {
    286  1.2  yamt 		if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
    287  1.2  yamt 		    !RB_EMPTY(&ruleset->anchor->children) ||
    288  1.2  yamt 		    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
    289  1.2  yamt 		    ruleset->topen)
    290  1.2  yamt 			return;
    291  1.2  yamt 		for (i = 0; i < PF_RULESET_MAX; ++i)
    292  1.2  yamt 			if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
    293  1.2  yamt 			    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
    294  1.2  yamt 			    ruleset->rules[i].inactive.open)
    295  1.2  yamt 				return;
    296  1.2  yamt 		RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
    297  1.2  yamt 		if ((parent = ruleset->anchor->parent) != NULL)
    298  1.2  yamt 			RB_REMOVE(pf_anchor_node, &parent->children,
    299  1.2  yamt 			    ruleset->anchor);
    300  1.2  yamt 		rs_free(ruleset->anchor);
    301  1.2  yamt 		if (parent == NULL)
    302  1.2  yamt 			return;
    303  1.2  yamt 		ruleset = &parent->ruleset;
    304  1.2  yamt 	}
    305  1.2  yamt }
    306  1.2  yamt 
    307  1.2  yamt int
    308  1.2  yamt pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
    309  1.2  yamt     const char *name)
    310  1.2  yamt {
    311  1.2  yamt 	char			*p, *path;
    312  1.2  yamt 	struct pf_ruleset	*ruleset;
    313  1.2  yamt 
    314  1.2  yamt 	r->anchor = NULL;
    315  1.2  yamt 	r->anchor_relative = 0;
    316  1.2  yamt 	r->anchor_wildcard = 0;
    317  1.2  yamt 	if (!name[0])
    318  1.2  yamt 		return (0);
    319  1.2  yamt 	path = (char *)rs_malloc(MAXPATHLEN);
    320  1.2  yamt 	bzero(path, MAXPATHLEN);
    321  1.2  yamt 	if (name[0] == '/')
    322  1.2  yamt 		strlcpy(path, name + 1, MAXPATHLEN);
    323  1.2  yamt 	else {
    324  1.2  yamt 		/* relative path */
    325  1.2  yamt 		r->anchor_relative = 1;
    326  1.2  yamt 		if (s->anchor == NULL || !s->anchor->path[0])
    327  1.2  yamt 			path[0] = 0;
    328  1.2  yamt 		else
    329  1.2  yamt 			strlcpy(path, s->anchor->path, MAXPATHLEN);
    330  1.2  yamt 		while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
    331  1.2  yamt 			if (!path[0]) {
    332  1.2  yamt 				printf("pf_anchor_setup: .. beyond root\n");
    333  1.2  yamt 				rs_free(path);
    334  1.2  yamt 				return (1);
    335  1.2  yamt 			}
    336  1.2  yamt 			if ((p = strrchr(path, '/')) != NULL)
    337  1.2  yamt 				*p = 0;
    338  1.2  yamt 			else
    339  1.2  yamt 				path[0] = 0;
    340  1.2  yamt 			r->anchor_relative++;
    341  1.2  yamt 			name += 3;
    342  1.2  yamt 		}
    343  1.2  yamt 		if (path[0])
    344  1.2  yamt 			strlcat(path, "/", MAXPATHLEN);
    345  1.2  yamt 		strlcat(path, name, MAXPATHLEN);
    346  1.2  yamt 	}
    347  1.2  yamt 	if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
    348  1.2  yamt 		r->anchor_wildcard = 1;
    349  1.2  yamt 		*p = 0;
    350  1.2  yamt 	}
    351  1.2  yamt 	ruleset = pf_find_or_create_ruleset(path);
    352  1.2  yamt 	rs_free(path);
    353  1.2  yamt 	if (ruleset == NULL || ruleset->anchor == NULL) {
    354  1.2  yamt 		printf("pf_anchor_setup: ruleset\n");
    355  1.2  yamt 		return (1);
    356  1.2  yamt 	}
    357  1.2  yamt 	r->anchor = ruleset->anchor;
    358  1.2  yamt 	r->anchor->refcnt++;
    359  1.2  yamt 	return (0);
    360  1.2  yamt }
    361  1.2  yamt 
    362  1.2  yamt int
    363  1.2  yamt pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
    364  1.2  yamt     struct pfioc_rule *pr)
    365  1.2  yamt {
    366  1.2  yamt 	pr->anchor_call[0] = 0;
    367  1.2  yamt 	if (r->anchor == NULL)
    368  1.2  yamt 		return (0);
    369  1.2  yamt 	if (!r->anchor_relative) {
    370  1.2  yamt 		strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
    371  1.2  yamt 		strlcat(pr->anchor_call, r->anchor->path,
    372  1.2  yamt 		    sizeof(pr->anchor_call));
    373  1.2  yamt 	} else {
    374  1.2  yamt 		char	*a, *p;
    375  1.2  yamt 		int	 i;
    376  1.2  yamt 
    377  1.2  yamt 		a = (char *)rs_malloc(MAXPATHLEN);
    378  1.2  yamt 		bzero(a, MAXPATHLEN);
    379  1.2  yamt 		if (rs->anchor == NULL)
    380  1.2  yamt 			a[0] = 0;
    381  1.2  yamt 		else
    382  1.2  yamt 			strlcpy(a, rs->anchor->path, MAXPATHLEN);
    383  1.2  yamt 		for (i = 1; i < r->anchor_relative; ++i) {
    384  1.2  yamt 			if ((p = strrchr(a, '/')) == NULL)
    385  1.2  yamt 				p = a;
    386  1.2  yamt 			*p = 0;
    387  1.2  yamt 			strlcat(pr->anchor_call, "../",
    388  1.2  yamt 			    sizeof(pr->anchor_call));
    389  1.2  yamt 		}
    390  1.2  yamt 		if (strncmp(a, r->anchor->path, strlen(a))) {
    391  1.2  yamt 			printf("pf_anchor_copyout: '%s' '%s'\n", a,
    392  1.2  yamt 			    r->anchor->path);
    393  1.2  yamt 			rs_free(a);
    394  1.2  yamt 			return (1);
    395  1.2  yamt 		}
    396  1.2  yamt 		if (strlen(r->anchor->path) > strlen(a))
    397  1.2  yamt 			strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
    398  1.2  yamt 			    strlen(a) + 1 : 0), sizeof(pr->anchor_call));
    399  1.2  yamt 		rs_free(a);
    400  1.2  yamt 	}
    401  1.2  yamt 	if (r->anchor_wildcard)
    402  1.2  yamt 		strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
    403  1.2  yamt 		    sizeof(pr->anchor_call));
    404  1.2  yamt 	return (0);
    405  1.2  yamt }
    406  1.2  yamt 
    407  1.2  yamt void
    408  1.2  yamt pf_anchor_remove(struct pf_rule *r)
    409  1.2  yamt {
    410  1.2  yamt 	if (r->anchor == NULL)
    411  1.2  yamt 		return;
    412  1.2  yamt 	if (r->anchor->refcnt <= 0) {
    413  1.2  yamt 		printf("pf_anchor_remove: broken refcount\n");
    414  1.2  yamt 		r->anchor = NULL;
    415  1.2  yamt 		return;
    416  1.2  yamt 	}
    417  1.2  yamt 	if (!--r->anchor->refcnt)
    418  1.2  yamt 		pf_remove_if_empty_ruleset(&r->anchor->ruleset);
    419  1.2  yamt 	r->anchor = NULL;
    420  1.2  yamt }
    421