Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/pf/pf_ruleset.c
39507 views
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
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
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
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 *
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
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
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 *
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 *
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 *
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 *
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
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
if (ruleset == &pf_main_ruleset ||
340
!RB_EMPTY(&ruleset->anchor->children) ||
341
ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
342
ruleset->topen)
343
return;
344
for (i = 0; i < PF_RULESET_MAX; ++i)
345
if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
346
!TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
347
ruleset->rules[i].inactive.open)
348
return;
349
for (int i = 0; i < PF_RULESET_MAX; i++) {
350
pf_rule_tree_free(ruleset->rules[i].active.tree);
351
ruleset->rules[i].active.tree = NULL;
352
pf_rule_tree_free(ruleset->rules[i].inactive.tree);
353
ruleset->rules[i].inactive.tree = NULL;
354
}
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
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
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
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
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
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 *
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 *
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 *
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 *
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
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
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
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
770