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 struct pf_kruleset *
pf_get_leaf_kruleset(char * path,char ** path_remainder)193 pf_get_leaf_kruleset(char *path, char **path_remainder)
194 {
195 struct pf_kruleset *ruleset;
196 char *leaf, *p;
197 int i = 0;
198
199 p = path;
200 while (*p == '/')
201 p++;
202
203 ruleset = pf_find_kruleset(p);
204 leaf = p;
205 while (ruleset == NULL) {
206 leaf = strrchr(p, '/');
207 if (leaf != NULL) {
208 *leaf = '\0';
209 i++;
210 ruleset = pf_find_kruleset(p);
211 } else {
212 leaf = path;
213 /*
214 * if no path component exists, then main ruleset is
215 * our parent.
216 */
217 ruleset = &pf_main_ruleset;
218 }
219 }
220
221 if (path_remainder != NULL)
222 *path_remainder = leaf;
223
224 /* restore slashes in path. */
225 while (i != 0) {
226 while (*leaf != '\0')
227 leaf++;
228 *leaf = '/';
229 i--;
230 }
231
232 return (ruleset);
233 }
234
235 struct pf_kanchor *
pf_create_kanchor(struct pf_kanchor * parent,const char * aname)236 pf_create_kanchor(struct pf_kanchor *parent, const char *aname)
237 {
238 struct pf_kanchor *anchor, *dup;
239
240 if (!*aname || (strlen(aname) >= PF_ANCHOR_NAME_SIZE) ||
241 ((parent != NULL) && (strlen(parent->path) >= PF_ANCHOR_MAXPATH)))
242 return (NULL);
243
244 anchor = rs_malloc(sizeof(*anchor));
245 if (anchor == NULL)
246 return (NULL);
247
248 RB_INIT(&anchor->children);
249 strlcpy(anchor->name, aname, sizeof(anchor->name));
250 if (parent != NULL) {
251 /*
252 * Make sure path for levels 2, 3, ... is terminated by '/':
253 * 1/2/3/...
254 */
255 strlcpy(anchor->path, parent->path, sizeof(anchor->path));
256 strlcat(anchor->path, "/", sizeof(anchor->path));
257 }
258 strlcat(anchor->path, anchor->name, sizeof(anchor->path));
259
260 if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
261 NULL) {
262 printf("pf_find_or_create_ruleset: RB_INSERT1 "
263 "'%s' '%s' collides with '%s' '%s'\n",
264 anchor->path, anchor->name, dup->path, dup->name);
265 rs_free(anchor);
266 return (NULL);
267 }
268
269 if (parent != NULL) {
270 anchor->parent = parent;
271 if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
272 anchor)) != NULL) {
273 printf("pf_find_or_create_ruleset: "
274 "RB_INSERT2 '%s' '%s' collides with "
275 "'%s' '%s'\n", anchor->path, anchor->name,
276 dup->path, dup->name);
277 RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
278 anchor);
279 rs_free(anchor);
280 return (NULL);
281 }
282 }
283 pf_init_kruleset(&anchor->ruleset);
284 anchor->ruleset.anchor = anchor;
285 return (anchor);
286 }
287
288 struct pf_kruleset *
pf_find_or_create_kruleset(const char * path)289 pf_find_or_create_kruleset(const char *path)
290 {
291 char *p, *aname, *r;
292 struct pf_kruleset *ruleset;
293 struct pf_kanchor *anchor = NULL;
294
295 if (path[0] == 0)
296 return (&pf_main_ruleset);
297 while (*path == '/')
298 path++;
299 ruleset = pf_find_kruleset(path);
300 if (ruleset != NULL)
301 return (ruleset);
302 p = (char *)rs_malloc(MAXPATHLEN);
303 if (p == NULL)
304 return (NULL);
305 strlcpy(p, path, MAXPATHLEN);
306
307 ruleset = pf_get_leaf_kruleset(p, &aname);
308 anchor = ruleset->anchor;
309
310 while (*aname == '/')
311 aname++;
312 /*
313 * aname is a path remainder, which contains nodes we must create. We
314 * process the aname path from left to right, effectively descending
315 * from parents to children.
316 */
317 while ((r = strchr(aname, '/')) != NULL || *aname) {
318 if (r != NULL)
319 *r = 0;
320 anchor = pf_create_kanchor(anchor, aname);
321 if (anchor == NULL) {
322 rs_free(p);
323 return (NULL);
324 }
325 if (r == NULL)
326 break;
327 else
328 aname = r + 1;
329 }
330
331 rs_free(p);
332 return (&anchor->ruleset);
333 }
334
335 void
pf_remove_if_empty_kruleset(struct pf_kruleset * ruleset)336 pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
337 {
338 struct pf_kanchor *parent;
339 int i;
340
341 while (ruleset != NULL) {
342 if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
343 !RB_EMPTY(&ruleset->anchor->children) ||
344 ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
345 ruleset->topen)
346 return;
347 for (i = 0; i < PF_RULESET_MAX; ++i)
348 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
349 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
350 ruleset->rules[i].inactive.open)
351 return;
352 RB_REMOVE(pf_kanchor_global, &V_pf_anchors, ruleset->anchor);
353 if ((parent = ruleset->anchor->parent) != NULL)
354 RB_REMOVE(pf_kanchor_node, &parent->children,
355 ruleset->anchor);
356 rs_free(ruleset->anchor);
357 if (parent == NULL)
358 return;
359 ruleset = &parent->ruleset;
360 }
361 }
362
363 int
pf_kanchor_setup(struct pf_krule * r,const struct pf_kruleset * s,const char * name)364 pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
365 const char *name)
366 {
367 char *p, *path;
368 struct pf_kruleset *ruleset;
369
370 r->anchor = NULL;
371 r->anchor_relative = 0;
372 r->anchor_wildcard = 0;
373 if (!name[0])
374 return (0);
375 path = (char *)rs_malloc(MAXPATHLEN);
376 if (path == NULL)
377 return (1);
378 if (name[0] == '/')
379 strlcpy(path, name + 1, MAXPATHLEN);
380 else {
381 /* relative path */
382 r->anchor_relative = 1;
383 if (s->anchor == NULL || !s->anchor->path[0])
384 path[0] = 0;
385 else
386 strlcpy(path, s->anchor->path, MAXPATHLEN);
387 while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
388 if (!path[0]) {
389 DPFPRINTF("%s: .. beyond root\n", __func__);
390 rs_free(path);
391 return (1);
392 }
393 if ((p = strrchr(path, '/')) != NULL)
394 *p = 0;
395 else
396 path[0] = 0;
397 r->anchor_relative++;
398 name += 3;
399 }
400 if (path[0])
401 strlcat(path, "/", MAXPATHLEN);
402 strlcat(path, name, MAXPATHLEN);
403 }
404 if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
405 r->anchor_wildcard = 1;
406 *p = 0;
407 }
408 ruleset = pf_find_or_create_kruleset(path);
409 rs_free(path);
410 if (ruleset == NULL || ruleset->anchor == NULL) {
411 DPFPRINTF("%s: ruleset\n", __func__);
412 return (1);
413 }
414 r->anchor = ruleset->anchor;
415 r->anchor->refcnt++;
416 return (0);
417 }
418
419 int
pf_kanchor_copyout(const struct pf_kruleset * rs,const struct pf_krule * r,char * anchor_call,size_t anchor_call_len)420 pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
421 char *anchor_call, size_t anchor_call_len)
422 {
423 anchor_call[0] = 0;
424
425 if (r->anchor == NULL)
426 goto done;
427 if (!r->anchor_relative) {
428 strlcpy(anchor_call, "/", anchor_call_len);
429 strlcat(anchor_call, r->anchor->path,
430 anchor_call_len);
431 } else {
432 char a[MAXPATHLEN];
433 char *p;
434 int i;
435 if (rs->anchor == NULL)
436 a[0] = 0;
437 else
438 strlcpy(a, rs->anchor->path, MAXPATHLEN);
439 for (i = 1; i < r->anchor_relative; ++i) {
440 if ((p = strrchr(a, '/')) == NULL)
441 p = a;
442 *p = 0;
443 strlcat(anchor_call, "../",
444 anchor_call_len);
445 }
446 if (strncmp(a, r->anchor->path, strlen(a))) {
447 printf("pf_anchor_copyout: '%s' '%s'\n", a,
448 r->anchor->path);
449 return (1);
450 }
451 if (strlen(r->anchor->path) > strlen(a))
452 strlcat(anchor_call, r->anchor->path + (a[0] ?
453 strlen(a) + 1 : 0), anchor_call_len);
454
455 }
456 if (r->anchor_wildcard)
457 strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
458 anchor_call_len);
459
460 done:
461
462 return (0);
463 }
464
465 int
pf_kanchor_nvcopyout(const struct pf_kruleset * rs,const struct pf_krule * r,nvlist_t * nvl)466 pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
467 nvlist_t *nvl)
468 {
469 char anchor_call[MAXPATHLEN] = { 0 };
470 int ret;
471
472 ret = pf_kanchor_copyout(rs, r, anchor_call, sizeof(anchor_call));
473 MPASS(ret == 0);
474
475 nvlist_add_string(nvl, "anchor_call", anchor_call);
476
477 return (ret);
478 }
479
480 int
pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset * rs,const struct pf_keth_rule * r,nvlist_t * nvl)481 pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
482 const struct pf_keth_rule *r, nvlist_t *nvl)
483 {
484 char anchor_call[MAXPATHLEN] = { 0 };
485
486 if (r->anchor == NULL)
487 goto done;
488 if (!r->anchor_relative) {
489 strlcpy(anchor_call, "/", sizeof(anchor_call));
490 strlcat(anchor_call, r->anchor->path,
491 sizeof(anchor_call));
492 } else {
493 char a[MAXPATHLEN];
494 char *p;
495 int i;
496 if (rs->anchor == NULL)
497 a[0] = 0;
498 else
499 strlcpy(a, rs->anchor->path, MAXPATHLEN);
500 for (i = 1; i < r->anchor_relative; ++i) {
501 if ((p = strrchr(a, '/')) == NULL)
502 p = a;
503 *p = 0;
504 strlcat(anchor_call, "../",
505 sizeof(anchor_call));
506 }
507 if (strncmp(a, r->anchor->path, strlen(a))) {
508 printf("%s(): '%s' '%s'\n", __func__, a,
509 r->anchor->path);
510 return (1);
511 }
512 if (strlen(r->anchor->path) > strlen(a))
513 strlcat(anchor_call, r->anchor->path + (a[0] ?
514 strlen(a) + 1 : 0), sizeof(anchor_call));
515
516 }
517 if (r->anchor_wildcard)
518 strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
519 sizeof(anchor_call));
520
521 done:
522 nvlist_add_string(nvl, "anchor_call", anchor_call);
523
524 return (0);
525 }
526
527 void
pf_kanchor_remove(struct pf_krule * r)528 pf_kanchor_remove(struct pf_krule *r)
529 {
530 if (r->anchor == NULL)
531 return;
532 if (r->anchor->refcnt <= 0) {
533 printf("pf_anchor_remove: broken refcount\n");
534 r->anchor = NULL;
535 return;
536 }
537 if (!--r->anchor->refcnt)
538 pf_remove_if_empty_kruleset(&r->anchor->ruleset);
539 r->anchor = NULL;
540 }
541
542 struct pf_keth_ruleset *
pf_find_keth_ruleset(const char * path)543 pf_find_keth_ruleset(const char *path)
544 {
545 struct pf_keth_anchor *anchor;
546
547 while (*path == '/')
548 path++;
549 if (!*path)
550 return (V_pf_keth);
551 anchor = pf_find_keth_anchor(path);
552 if (anchor == NULL)
553 return (NULL);
554 else
555 return (&anchor->ruleset);
556 }
557
558 static struct pf_keth_anchor *
_pf_find_keth_anchor(struct pf_keth_ruleset * rs,const char * path)559 _pf_find_keth_anchor(struct pf_keth_ruleset *rs, const char *path)
560 {
561 struct pf_keth_anchor *key, *found;
562
563 key = (struct pf_keth_anchor *)rs_malloc(sizeof(*key));
564 if (key == NULL)
565 return (NULL);
566 strlcpy(key->path, path, sizeof(key->path));
567 found = RB_FIND(pf_keth_anchor_global, &V_pf_keth_anchors, key);
568 rs_free(key);
569 return (found);
570 }
571
572 struct pf_keth_anchor *
pf_find_keth_anchor(const char * path)573 pf_find_keth_anchor(const char *path)
574 {
575 return (_pf_find_keth_anchor(V_pf_keth, path));
576 }
577
578 struct pf_keth_ruleset *
pf_find_or_create_keth_ruleset(const char * path)579 pf_find_or_create_keth_ruleset(const char *path)
580 {
581 char *p, *q, *r;
582 struct pf_keth_anchor *anchor = NULL, *dup = NULL, *parent = NULL;
583 struct pf_keth_ruleset *ruleset;
584
585 if (path[0] == 0)
586 return (V_pf_keth);
587 while (*path == '/')
588 path++;
589 ruleset = pf_find_keth_ruleset(path);
590 if (ruleset != NULL)
591 return (ruleset);
592 p = (char *)rs_malloc(MAXPATHLEN);
593 if (p == NULL)
594 return (NULL);
595 strlcpy(p, path, MAXPATHLEN);
596 while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
597 *q = 0;
598 if ((ruleset = pf_find_keth_ruleset(p)) != NULL) {
599 parent = ruleset->anchor;
600 break;
601 }
602 }
603 if (q == NULL)
604 q = p;
605 else
606 q++;
607 strlcpy(p, path, MAXPATHLEN);
608 if (!*q) {
609 rs_free(p);
610 return (NULL);
611 }
612 while ((r = strchr(q, '/')) != NULL || *q) {
613 if (r != NULL)
614 *r = 0;
615 if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
616 (parent != NULL && strlen(parent->path) >=
617 MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
618 rs_free(p);
619 return (NULL);
620 }
621 anchor = (struct pf_keth_anchor *)rs_malloc(sizeof(*anchor));
622 if (anchor == NULL) {
623 rs_free(p);
624 return (NULL);
625 }
626 RB_INIT(&anchor->children);
627 strlcpy(anchor->name, q, sizeof(anchor->name));
628 if (parent != NULL) {
629 strlcpy(anchor->path, parent->path,
630 sizeof(anchor->path));
631 strlcat(anchor->path, "/", sizeof(anchor->path));
632 }
633 strlcat(anchor->path, anchor->name, sizeof(anchor->path));
634 if ((dup = RB_INSERT(pf_keth_anchor_global, &V_pf_keth_anchors, anchor)) !=
635 NULL) {
636 printf("%s: RB_INSERT1 "
637 "'%s' '%s' collides with '%s' '%s'\n", __func__,
638 anchor->path, anchor->name, dup->path, dup->name);
639 rs_free(anchor);
640 rs_free(p);
641 return (NULL);
642 }
643 if (parent != NULL) {
644 anchor->parent = parent;
645 if ((dup = RB_INSERT(pf_keth_anchor_node, &parent->children,
646 anchor)) != NULL) {
647 printf("%s: "
648 "RB_INSERT2 '%s' '%s' collides with "
649 "'%s' '%s'\n", __func__, anchor->path,
650 anchor->name, dup->path, dup->name);
651 RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors,
652 anchor);
653 rs_free(anchor);
654 rs_free(p);
655 return (NULL);
656 }
657 }
658 pf_init_keth(&anchor->ruleset);
659 anchor->ruleset.anchor = anchor;
660 parent = anchor;
661 if (r != NULL)
662 q = r + 1;
663 else
664 *q = 0;
665 }
666 rs_free(p);
667 return (&anchor->ruleset);
668 }
669
670 int
pf_keth_anchor_setup(struct pf_keth_rule * r,const struct pf_keth_ruleset * s,const char * name)671 pf_keth_anchor_setup(struct pf_keth_rule *r, const struct pf_keth_ruleset *s,
672 const char *name)
673 {
674 char *p, *path;
675 struct pf_keth_ruleset *ruleset;
676
677 r->anchor = NULL;
678 r->anchor_relative = 0;
679 r->anchor_wildcard = 0;
680 if (!name[0])
681 return (0);
682 path = (char *)rs_malloc(MAXPATHLEN);
683 if (path == NULL)
684 return (1);
685 if (name[0] == '/')
686 strlcpy(path, name + 1, MAXPATHLEN);
687 else {
688 /* relative path */
689 r->anchor_relative = 1;
690 if (s->anchor == NULL || !s->anchor->path[0])
691 path[0] = 0;
692 else
693 strlcpy(path, s->anchor->path, MAXPATHLEN);
694 while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
695 if (!path[0]) {
696 DPFPRINTF("%s: .. beyond root\n", __func__);
697 rs_free(path);
698 return (1);
699 }
700 if ((p = strrchr(path, '/')) != NULL)
701 *p = 0;
702 else
703 path[0] = 0;
704 r->anchor_relative++;
705 name += 3;
706 }
707 if (path[0])
708 strlcat(path, "/", MAXPATHLEN);
709 strlcat(path, name, MAXPATHLEN);
710 }
711 if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
712 r->anchor_wildcard = 1;
713 *p = 0;
714 }
715 ruleset = pf_find_or_create_keth_ruleset(path);
716 rs_free(path);
717 if (ruleset == NULL || ruleset->anchor == NULL) {
718 DPFPRINTF("%s: ruleset\n", __func__);
719 return (1);
720 }
721 r->anchor = ruleset->anchor;
722 r->anchor->refcnt++;
723 return (0);
724 }
725
726 void
pf_keth_anchor_remove(struct pf_keth_rule * r)727 pf_keth_anchor_remove(struct pf_keth_rule *r)
728 {
729 if (r->anchor == NULL)
730 return;
731 if (r->anchor->refcnt <= 0) {
732 printf("%s: broken refcount\n", __func__);
733 r->anchor = NULL;
734 return;
735 }
736 if (!--r->anchor->refcnt)
737 pf_remove_if_empty_keth_ruleset(&r->anchor->ruleset);
738 r->anchor = NULL;
739 }
740
741 void
pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset * ruleset)742 pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset *ruleset)
743 {
744 struct pf_keth_anchor *parent;
745 int i;
746
747 while (ruleset != NULL) {
748 if (ruleset == V_pf_keth || ruleset->anchor == NULL ||
749 !RB_EMPTY(&ruleset->anchor->children) ||
750 ruleset->anchor->refcnt > 0)
751 return;
752 for (i = 0; i < PF_RULESET_MAX; ++i)
753 if (!TAILQ_EMPTY(ruleset->active.rules) ||
754 !TAILQ_EMPTY(ruleset->inactive.rules) ||
755 ruleset->inactive.open)
756 return;
757 RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors, ruleset->anchor);
758 if ((parent = ruleset->anchor->parent) != NULL)
759 RB_REMOVE(pf_keth_anchor_node, &parent->children,
760 ruleset->anchor);
761 rs_free(ruleset->anchor);
762 if (parent == NULL)
763 return;
764 ruleset = &parent->ruleset;
765 }
766 }
767