1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2001 Daniel Hartmeier
5 * Copyright (c) 2002,2003 Henning Brauer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Effort sponsored in part by the Defense Advanced Research Projects
33 * Agency (DARPA) and Air Force Research Laboratory, Air Force
34 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35 *
36 * $OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $
37 */
38
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/systm.h>
42 #include <sys/refcount.h>
43 #include <sys/mbuf.h>
44
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip.h>
48 #include <netinet/tcp.h>
49
50 #include <net/if.h>
51 #include <net/vnet.h>
52 #include <net/pfvar.h>
53
54 #ifdef INET6
55 #include <netinet/ip6.h>
56 #endif /* INET6 */
57
58 #ifndef _KERNEL
59 #error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead."
60 #endif
61
62 #define DPFPRINTF(format, x...) \
63 if (V_pf_status.debug >= PF_DEBUG_NOISY) \
64 printf(format , ##x)
65 #define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
66 #define rs_free(x) free(x, M_TEMP)
67
68 VNET_DEFINE(struct pf_kanchor_global, pf_anchors);
69 VNET_DEFINE(struct pf_kanchor, pf_main_anchor);
70 VNET_DEFINE(struct pf_keth_ruleset*, pf_keth);
71 VNET_DEFINE(struct pf_keth_anchor, pf_main_keth_anchor);
72 VNET_DEFINE(struct pf_keth_anchor_global, pf_keth_anchors);
73
74 static __inline int pf_kanchor_compare(struct pf_kanchor *,
75 struct pf_kanchor *);
76 static __inline int pf_keth_anchor_compare(struct pf_keth_anchor *,
77 struct pf_keth_anchor *);
78 static struct pf_kanchor *pf_find_kanchor(const char *);
79
80 RB_GENERATE(pf_kanchor_global, pf_kanchor, entry_global, pf_kanchor_compare);
81 RB_GENERATE(pf_kanchor_node, pf_kanchor, entry_node, pf_kanchor_compare);
82 RB_GENERATE(pf_keth_anchor_global, pf_keth_anchor, entry_global,
83 pf_keth_anchor_compare);
84 RB_GENERATE(pf_keth_anchor_node, pf_keth_anchor, entry_node,
85 pf_keth_anchor_compare);
86
87 static __inline int
pf_kanchor_compare(struct pf_kanchor * a,struct pf_kanchor * b)88 pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
89 {
90 int c = strcmp(a->path, b->path);
91
92 return (c ? (c < 0 ? -1 : 1) : 0);
93 }
94
95 static __inline int
pf_keth_anchor_compare(struct pf_keth_anchor * a,struct pf_keth_anchor * b)96 pf_keth_anchor_compare(struct pf_keth_anchor *a, struct pf_keth_anchor *b)
97 {
98 int c = strcmp(a->path, b->path);
99
100 return (c ? (c < 0 ? -1 : 1) : 0);
101 }
102
103 int
pf_get_ruleset_number(u_int8_t action)104 pf_get_ruleset_number(u_int8_t action)
105 {
106 switch (action) {
107 case PF_SCRUB:
108 case PF_NOSCRUB:
109 return (PF_RULESET_SCRUB);
110 break;
111 case PF_PASS:
112 case PF_MATCH:
113 case PF_DROP:
114 return (PF_RULESET_FILTER);
115 break;
116 case PF_NAT:
117 case PF_NONAT:
118 return (PF_RULESET_NAT);
119 break;
120 case PF_BINAT:
121 case PF_NOBINAT:
122 return (PF_RULESET_BINAT);
123 break;
124 case PF_RDR:
125 case PF_NORDR:
126 return (PF_RULESET_RDR);
127 break;
128 default:
129 return (PF_RULESET_MAX);
130 break;
131 }
132 }
133
134 static struct pf_kanchor *
pf_find_kanchor(const char * path)135 pf_find_kanchor(const char *path)
136 {
137 struct pf_kanchor *key, *found;
138
139 key = (struct pf_kanchor *)rs_malloc(sizeof(*key));
140 if (key == NULL)
141 return (NULL);
142 strlcpy(key->path, path, sizeof(key->path));
143 found = RB_FIND(pf_kanchor_global, &V_pf_anchors, key);
144 rs_free(key);
145 return (found);
146 }
147
148 void
pf_init_kruleset(struct pf_kruleset * ruleset)149 pf_init_kruleset(struct pf_kruleset *ruleset)
150 {
151 int i;
152
153 memset(ruleset, 0, sizeof(struct pf_kruleset));
154 for (i = 0; i < PF_RULESET_MAX; i++) {
155 TAILQ_INIT(&ruleset->rules[i].queues[0]);
156 TAILQ_INIT(&ruleset->rules[i].queues[1]);
157 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
158 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
159 }
160 }
161
162 void
pf_init_keth(struct pf_keth_ruleset * rs)163 pf_init_keth(struct pf_keth_ruleset *rs)
164 {
165
166 bzero(rs, sizeof(*rs));
167 TAILQ_INIT(&rs->rules[0]);
168 TAILQ_INIT(&rs->rules[1]);
169 rs->active.rules = &rs->rules[0];
170 rs->active.open = 0;
171 rs->inactive.rules = &rs->rules[1];
172 rs->inactive.open = 0;
173
174 rs->vnet = curvnet;
175 }
176
177 struct pf_kruleset *
pf_find_kruleset(const char * path)178 pf_find_kruleset(const char *path)
179 {
180 struct pf_kanchor *anchor;
181
182 while (*path == '/')
183 path++;
184 if (!*path)
185 return (&pf_main_ruleset);
186 anchor = pf_find_kanchor(path);
187 if (anchor == NULL)
188 return (NULL);
189 else
190 return (&anchor->ruleset);
191 }
192
193 struct pf_kruleset *
pf_find_or_create_kruleset(const char * path)194 pf_find_or_create_kruleset(const char *path)
195 {
196 char *p, *q, *r;
197 struct pf_kruleset *ruleset;
198 struct pf_kanchor *anchor = NULL, *dup, *parent = NULL;
199
200 if (path[0] == 0)
201 return (&pf_main_ruleset);
202 while (*path == '/')
203 path++;
204 ruleset = pf_find_kruleset(path);
205 if (ruleset != NULL)
206 return (ruleset);
207 p = (char *)rs_malloc(MAXPATHLEN);
208 if (p == NULL)
209 return (NULL);
210 strlcpy(p, path, MAXPATHLEN);
211 while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
212 *q = 0;
213 if ((ruleset = pf_find_kruleset(p)) != NULL) {
214 parent = ruleset->anchor;
215 break;
216 }
217 }
218 if (q == NULL)
219 q = p;
220 else
221 q++;
222 strlcpy(p, path, MAXPATHLEN);
223 if (!*q) {
224 rs_free(p);
225 return (NULL);
226 }
227 while ((r = strchr(q, '/')) != NULL || *q) {
228 if (r != NULL)
229 *r = 0;
230 if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
231 (parent != NULL && strlen(parent->path) >=
232 MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
233 rs_free(p);
234 return (NULL);
235 }
236 anchor = (struct pf_kanchor *)rs_malloc(sizeof(*anchor));
237 if (anchor == NULL) {
238 rs_free(p);
239 return (NULL);
240 }
241 RB_INIT(&anchor->children);
242 strlcpy(anchor->name, q, sizeof(anchor->name));
243 if (parent != NULL) {
244 strlcpy(anchor->path, parent->path,
245 sizeof(anchor->path));
246 strlcat(anchor->path, "/", sizeof(anchor->path));
247 }
248 strlcat(anchor->path, anchor->name, sizeof(anchor->path));
249 if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
250 NULL) {
251 printf("pf_find_or_create_ruleset: RB_INSERT1 "
252 "'%s' '%s' collides with '%s' '%s'\n",
253 anchor->path, anchor->name, dup->path, dup->name);
254 rs_free(anchor);
255 rs_free(p);
256 return (NULL);
257 }
258 if (parent != NULL) {
259 anchor->parent = parent;
260 if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
261 anchor)) != NULL) {
262 printf("pf_find_or_create_ruleset: "
263 "RB_INSERT2 '%s' '%s' collides with "
264 "'%s' '%s'\n", anchor->path, anchor->name,
265 dup->path, dup->name);
266 RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
267 anchor);
268 rs_free(anchor);
269 rs_free(p);
270 return (NULL);
271 }
272 }
273 pf_init_kruleset(&anchor->ruleset);
274 anchor->ruleset.anchor = anchor;
275 parent = anchor;
276 if (r != NULL)
277 q = r + 1;
278 else
279 *q = 0;
280 }
281 rs_free(p);
282 return (&anchor->ruleset);
283 }
284
285 void
pf_remove_if_empty_kruleset(struct pf_kruleset * ruleset)286 pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
287 {
288 struct pf_kanchor *parent;
289 int i;
290
291 while (ruleset != NULL) {
292 if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
293 !RB_EMPTY(&ruleset->anchor->children) ||
294 ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
295 ruleset->topen)
296 return;
297 for (i = 0; i < PF_RULESET_MAX; ++i)
298 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
299 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
300 ruleset->rules[i].inactive.open)
301 return;
302 RB_REMOVE(pf_kanchor_global, &V_pf_anchors, ruleset->anchor);
303 if ((parent = ruleset->anchor->parent) != NULL)
304 RB_REMOVE(pf_kanchor_node, &parent->children,
305 ruleset->anchor);
306 rs_free(ruleset->anchor);
307 if (parent == NULL)
308 return;
309 ruleset = &parent->ruleset;
310 }
311 }
312
313 int
pf_kanchor_setup(struct pf_krule * r,const struct pf_kruleset * s,const char * name)314 pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
315 const char *name)
316 {
317 char *p, *path;
318 struct pf_kruleset *ruleset;
319
320 r->anchor = NULL;
321 r->anchor_relative = 0;
322 r->anchor_wildcard = 0;
323 if (!name[0])
324 return (0);
325 path = (char *)rs_malloc(MAXPATHLEN);
326 if (path == NULL)
327 return (1);
328 if (name[0] == '/')
329 strlcpy(path, name + 1, MAXPATHLEN);
330 else {
331 /* relative path */
332 r->anchor_relative = 1;
333 if (s->anchor == NULL || !s->anchor->path[0])
334 path[0] = 0;
335 else
336 strlcpy(path, s->anchor->path, MAXPATHLEN);
337 while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
338 if (!path[0]) {
339 DPFPRINTF("pf_anchor_setup: .. beyond root\n");
340 rs_free(path);
341 return (1);
342 }
343 if ((p = strrchr(path, '/')) != NULL)
344 *p = 0;
345 else
346 path[0] = 0;
347 r->anchor_relative++;
348 name += 3;
349 }
350 if (path[0])
351 strlcat(path, "/", MAXPATHLEN);
352 strlcat(path, name, MAXPATHLEN);
353 }
354 if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
355 r->anchor_wildcard = 1;
356 *p = 0;
357 }
358 ruleset = pf_find_or_create_kruleset(path);
359 rs_free(path);
360 if (ruleset == NULL || ruleset->anchor == NULL) {
361 DPFPRINTF("pf_anchor_setup: ruleset\n");
362 return (1);
363 }
364 r->anchor = ruleset->anchor;
365 r->anchor->refcnt++;
366 return (0);
367 }
368
369 int
pf_kanchor_copyout(const struct pf_kruleset * rs,const struct pf_krule * r,char * anchor_call,size_t anchor_call_len)370 pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
371 char *anchor_call, size_t anchor_call_len)
372 {
373 anchor_call[0] = 0;
374
375 if (r->anchor == NULL)
376 goto done;
377 if (!r->anchor_relative) {
378 strlcpy(anchor_call, "/", anchor_call_len);
379 strlcat(anchor_call, r->anchor->path,
380 anchor_call_len);
381 } else {
382 char a[MAXPATHLEN];
383 char *p;
384 int i;
385 if (rs->anchor == NULL)
386 a[0] = 0;
387 else
388 strlcpy(a, rs->anchor->path, MAXPATHLEN);
389 for (i = 1; i < r->anchor_relative; ++i) {
390 if ((p = strrchr(a, '/')) == NULL)
391 p = a;
392 *p = 0;
393 strlcat(anchor_call, "../",
394 anchor_call_len);
395 }
396 if (strncmp(a, r->anchor->path, strlen(a))) {
397 printf("pf_anchor_copyout: '%s' '%s'\n", a,
398 r->anchor->path);
399 return (1);
400 }
401 if (strlen(r->anchor->path) > strlen(a))
402 strlcat(anchor_call, r->anchor->path + (a[0] ?
403 strlen(a) + 1 : 0), anchor_call_len);
404
405 }
406 if (r->anchor_wildcard)
407 strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
408 anchor_call_len);
409
410 done:
411
412 return (0);
413 }
414
415 int
pf_kanchor_nvcopyout(const struct pf_kruleset * rs,const struct pf_krule * r,nvlist_t * nvl)416 pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
417 nvlist_t *nvl)
418 {
419 char anchor_call[MAXPATHLEN] = { 0 };
420 int ret;
421
422 ret = pf_kanchor_copyout(rs, r, anchor_call, sizeof(anchor_call));
423 MPASS(ret == 0);
424
425 nvlist_add_string(nvl, "anchor_call", anchor_call);
426
427 return (ret);
428 }
429
430 int
pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset * rs,const struct pf_keth_rule * r,nvlist_t * nvl)431 pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
432 const struct pf_keth_rule *r, nvlist_t *nvl)
433 {
434 char anchor_call[MAXPATHLEN] = { 0 };
435
436 if (r->anchor == NULL)
437 goto done;
438 if (!r->anchor_relative) {
439 strlcpy(anchor_call, "/", sizeof(anchor_call));
440 strlcat(anchor_call, r->anchor->path,
441 sizeof(anchor_call));
442 } else {
443 char a[MAXPATHLEN];
444 char *p;
445 int i;
446 if (rs->anchor == NULL)
447 a[0] = 0;
448 else
449 strlcpy(a, rs->anchor->path, MAXPATHLEN);
450 for (i = 1; i < r->anchor_relative; ++i) {
451 if ((p = strrchr(a, '/')) == NULL)
452 p = a;
453 *p = 0;
454 strlcat(anchor_call, "../",
455 sizeof(anchor_call));
456 }
457 if (strncmp(a, r->anchor->path, strlen(a))) {
458 printf("%s(): '%s' '%s'\n", __func__, a,
459 r->anchor->path);
460 return (1);
461 }
462 if (strlen(r->anchor->path) > strlen(a))
463 strlcat(anchor_call, r->anchor->path + (a[0] ?
464 strlen(a) + 1 : 0), sizeof(anchor_call));
465
466 }
467 if (r->anchor_wildcard)
468 strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
469 sizeof(anchor_call));
470
471 done:
472 nvlist_add_string(nvl, "anchor_call", anchor_call);
473
474 return (0);
475 }
476
477 void
pf_kanchor_remove(struct pf_krule * r)478 pf_kanchor_remove(struct pf_krule *r)
479 {
480 if (r->anchor == NULL)
481 return;
482 if (r->anchor->refcnt <= 0) {
483 printf("pf_anchor_remove: broken refcount\n");
484 r->anchor = NULL;
485 return;
486 }
487 if (!--r->anchor->refcnt)
488 pf_remove_if_empty_kruleset(&r->anchor->ruleset);
489 r->anchor = NULL;
490 }
491
492 struct pf_keth_ruleset *
pf_find_keth_ruleset(const char * path)493 pf_find_keth_ruleset(const char *path)
494 {
495 struct pf_keth_anchor *anchor;
496
497 while (*path == '/')
498 path++;
499 if (!*path)
500 return (V_pf_keth);
501 anchor = pf_find_keth_anchor(path);
502 if (anchor == NULL)
503 return (NULL);
504 else
505 return (&anchor->ruleset);
506 }
507
508 static struct pf_keth_anchor *
_pf_find_keth_anchor(struct pf_keth_ruleset * rs,const char * path)509 _pf_find_keth_anchor(struct pf_keth_ruleset *rs, const char *path)
510 {
511 struct pf_keth_anchor *key, *found;
512
513 key = (struct pf_keth_anchor *)rs_malloc(sizeof(*key));
514 if (key == NULL)
515 return (NULL);
516 strlcpy(key->path, path, sizeof(key->path));
517 found = RB_FIND(pf_keth_anchor_global, &V_pf_keth_anchors, key);
518 rs_free(key);
519 return (found);
520 }
521
522 struct pf_keth_anchor *
pf_find_keth_anchor(const char * path)523 pf_find_keth_anchor(const char *path)
524 {
525 return (_pf_find_keth_anchor(V_pf_keth, path));
526 }
527
528 struct pf_keth_ruleset *
pf_find_or_create_keth_ruleset(const char * path)529 pf_find_or_create_keth_ruleset(const char *path)
530 {
531 char *p, *q, *r;
532 struct pf_keth_anchor *anchor = NULL, *dup = NULL, *parent = NULL;
533 struct pf_keth_ruleset *ruleset;
534
535 if (path[0] == 0)
536 return (V_pf_keth);
537 while (*path == '/')
538 path++;
539 ruleset = pf_find_keth_ruleset(path);
540 if (ruleset != NULL)
541 return (ruleset);
542 p = (char *)rs_malloc(MAXPATHLEN);
543 if (p == NULL)
544 return (NULL);
545 strlcpy(p, path, MAXPATHLEN);
546 while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
547 *q = 0;
548 if ((ruleset = pf_find_keth_ruleset(p)) != NULL) {
549 parent = ruleset->anchor;
550 break;
551 }
552 }
553 if (q == NULL)
554 q = p;
555 else
556 q++;
557 strlcpy(p, path, MAXPATHLEN);
558 if (!*q) {
559 rs_free(p);
560 return (NULL);
561 }
562 while ((r = strchr(q, '/')) != NULL || *q) {
563 if (r != NULL)
564 *r = 0;
565 if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
566 (parent != NULL && strlen(parent->path) >=
567 MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
568 rs_free(p);
569 return (NULL);
570 }
571 anchor = (struct pf_keth_anchor *)rs_malloc(sizeof(*anchor));
572 if (anchor == NULL) {
573 rs_free(p);
574 return (NULL);
575 }
576 RB_INIT(&anchor->children);
577 strlcpy(anchor->name, q, sizeof(anchor->name));
578 if (parent != NULL) {
579 strlcpy(anchor->path, parent->path,
580 sizeof(anchor->path));
581 strlcat(anchor->path, "/", sizeof(anchor->path));
582 }
583 strlcat(anchor->path, anchor->name, sizeof(anchor->path));
584 if ((dup = RB_INSERT(pf_keth_anchor_global, &V_pf_keth_anchors, anchor)) !=
585 NULL) {
586 printf("%s: RB_INSERT1 "
587 "'%s' '%s' collides with '%s' '%s'\n", __func__,
588 anchor->path, anchor->name, dup->path, dup->name);
589 rs_free(anchor);
590 rs_free(p);
591 return (NULL);
592 }
593 if (parent != NULL) {
594 anchor->parent = parent;
595 if ((dup = RB_INSERT(pf_keth_anchor_node, &parent->children,
596 anchor)) != NULL) {
597 printf("%s: "
598 "RB_INSERT2 '%s' '%s' collides with "
599 "'%s' '%s'\n", __func__, anchor->path,
600 anchor->name, dup->path, dup->name);
601 RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors,
602 anchor);
603 rs_free(anchor);
604 rs_free(p);
605 return (NULL);
606 }
607 }
608 pf_init_keth(&anchor->ruleset);
609 anchor->ruleset.anchor = anchor;
610 parent = anchor;
611 if (r != NULL)
612 q = r + 1;
613 else
614 *q = 0;
615 }
616 rs_free(p);
617 return (&anchor->ruleset);
618 }
619
620 int
pf_keth_anchor_setup(struct pf_keth_rule * r,const struct pf_keth_ruleset * s,const char * name)621 pf_keth_anchor_setup(struct pf_keth_rule *r, const struct pf_keth_ruleset *s,
622 const char *name)
623 {
624 char *p, *path;
625 struct pf_keth_ruleset *ruleset;
626
627 r->anchor = NULL;
628 r->anchor_relative = 0;
629 r->anchor_wildcard = 0;
630 if (!name[0])
631 return (0);
632 path = (char *)rs_malloc(MAXPATHLEN);
633 if (path == NULL)
634 return (1);
635 if (name[0] == '/')
636 strlcpy(path, name + 1, MAXPATHLEN);
637 else {
638 /* relative path */
639 r->anchor_relative = 1;
640 if (s->anchor == NULL || !s->anchor->path[0])
641 path[0] = 0;
642 else
643 strlcpy(path, s->anchor->path, MAXPATHLEN);
644 while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
645 if (!path[0]) {
646 DPFPRINTF("pf_anchor_setup: .. beyond root\n");
647 rs_free(path);
648 return (1);
649 }
650 if ((p = strrchr(path, '/')) != NULL)
651 *p = 0;
652 else
653 path[0] = 0;
654 r->anchor_relative++;
655 name += 3;
656 }
657 if (path[0])
658 strlcat(path, "/", MAXPATHLEN);
659 strlcat(path, name, MAXPATHLEN);
660 }
661 if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
662 r->anchor_wildcard = 1;
663 *p = 0;
664 }
665 ruleset = pf_find_or_create_keth_ruleset(path);
666 rs_free(path);
667 if (ruleset == NULL || ruleset->anchor == NULL) {
668 DPFPRINTF("pf_anchor_setup: ruleset\n");
669 return (1);
670 }
671 r->anchor = ruleset->anchor;
672 r->anchor->refcnt++;
673 return (0);
674 }
675
676 void
pf_keth_anchor_remove(struct pf_keth_rule * r)677 pf_keth_anchor_remove(struct pf_keth_rule *r)
678 {
679 if (r->anchor == NULL)
680 return;
681 if (r->anchor->refcnt <= 0) {
682 printf("%s: broken refcount\n", __func__);
683 r->anchor = NULL;
684 return;
685 }
686 if (!--r->anchor->refcnt)
687 pf_remove_if_empty_keth_ruleset(&r->anchor->ruleset);
688 r->anchor = NULL;
689 }
690
691 void
pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset * ruleset)692 pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset *ruleset)
693 {
694 struct pf_keth_anchor *parent;
695 int i;
696
697 while (ruleset != NULL) {
698 if (ruleset == V_pf_keth || ruleset->anchor == NULL ||
699 !RB_EMPTY(&ruleset->anchor->children) ||
700 ruleset->anchor->refcnt > 0)
701 return;
702 for (i = 0; i < PF_RULESET_MAX; ++i)
703 if (!TAILQ_EMPTY(ruleset->active.rules) ||
704 !TAILQ_EMPTY(ruleset->inactive.rules) ||
705 ruleset->inactive.open)
706 return;
707 RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors, ruleset->anchor);
708 if ((parent = ruleset->anchor->parent) != NULL)
709 RB_REMOVE(pf_keth_anchor_node, &parent->children,
710 ruleset->anchor);
711 rs_free(ruleset->anchor);
712 if (parent == NULL)
713 return;
714 ruleset = &parent->ruleset;
715 }
716 }
717