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