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