2 /* $OpenBSD: pf_ruleset.c,v 1.1 2006/10/27 13:56:51 mcbride Exp $ */
5 * Copyright (c) 2001 Daniel Hartmeier
6 * Copyright (c) 2002,2003 Henning Brauer
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 * Effort sponsored in part by the Defense Advanced Research Projects
34 * Agency (DARPA) and Air Force Research Laboratory, Air Force
35 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD$");
42 #include <sys/param.h>
43 #include <sys/socket.h>
45 # include <sys/systm.h>
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/tcp.h>
55 #include <net/pfvar.h>
58 #include <netinet/ip6.h>
63 # define DPFPRINTF(format, x...) \
64 if (pf_status.debug >= PF_DEBUG_NOISY) \
66 #define rs_malloc(x) malloc(x, M_TEMP, M_WAITOK)
67 #define rs_free(x) free(x, M_TEMP)
70 /* Userland equivalents so we can lend code to pfctl et al. */
72 # include <arpa/inet.h>
77 # define rs_malloc(x) malloc(x)
78 # define rs_free(x) free(x)
81 # include <sys/stdarg.h>
82 # define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
84 # define DPFPRINTF(format, x...) ((void)0)
89 struct pf_anchor_global pf_anchors
;
90 struct pf_anchor pf_main_anchor
;
92 int pf_get_ruleset_number(u_int8_t
);
93 void pf_init_ruleset(struct pf_ruleset
*);
94 int pf_anchor_setup(struct pf_rule
*,
95 const struct pf_ruleset
*, const char *);
96 int pf_anchor_copyout(const struct pf_ruleset
*,
97 const struct pf_rule
*, struct pfioc_rule
*);
98 void pf_anchor_remove(struct pf_rule
*);
100 static __inline
int pf_anchor_compare(struct pf_anchor
*, struct pf_anchor
*);
102 RB_GENERATE(pf_anchor_global
, pf_anchor
, entry_global
, pf_anchor_compare
);
103 RB_GENERATE(pf_anchor_node
, pf_anchor
, entry_node
, pf_anchor_compare
);
106 pf_anchor_compare(struct pf_anchor
*a
, struct pf_anchor
*b
)
108 int c
= strcmp(a
->path
, b
->path
);
110 return (c
? (c
< 0 ? -1 : 1) : 0);
114 pf_get_ruleset_number(u_int8_t action
)
119 return (PF_RULESET_SCRUB
);
123 return (PF_RULESET_FILTER
);
127 return (PF_RULESET_NAT
);
131 return (PF_RULESET_BINAT
);
135 return (PF_RULESET_RDR
);
138 return (PF_RULESET_MAX
);
144 pf_init_ruleset(struct pf_ruleset
*ruleset
)
148 memset(ruleset
, 0, sizeof(struct pf_ruleset
));
149 for (i
= 0; i
< PF_RULESET_MAX
; i
++) {
150 TAILQ_INIT(&ruleset
->rules
[i
].queues
[0]);
151 TAILQ_INIT(&ruleset
->rules
[i
].queues
[1]);
152 ruleset
->rules
[i
].active
.ptr
= &ruleset
->rules
[i
].queues
[0];
153 ruleset
->rules
[i
].inactive
.ptr
= &ruleset
->rules
[i
].queues
[1];
158 pf_find_anchor(const char *path
)
160 struct pf_anchor
*key
, *found
;
162 key
= (struct pf_anchor
*)rs_malloc(sizeof(*key
));
163 memset(key
, 0, sizeof(*key
));
164 strlcpy(key
->path
, path
, sizeof(key
->path
));
165 found
= RB_FIND(pf_anchor_global
, &pf_anchors
, key
);
171 pf_find_ruleset(const char *path
)
173 struct pf_anchor
*anchor
;
178 return (&pf_main_ruleset
);
179 anchor
= pf_find_anchor(path
);
183 return (&anchor
->ruleset
);
187 pf_find_or_create_ruleset(const char *path
)
190 struct pf_ruleset
*ruleset
;
191 struct pf_anchor
*anchor
= NULL
/* XXX gcc */;
192 struct pf_anchor
*dup
, *parent
= NULL
;
195 return (&pf_main_ruleset
);
198 ruleset
= pf_find_ruleset(path
);
201 p
= (char *)rs_malloc(MAXPATHLEN
);
202 bzero(p
, MAXPATHLEN
);
203 strlcpy(p
, path
, MAXPATHLEN
);
204 while (parent
== NULL
&& (q
= strrchr(p
, '/')) != NULL
) {
206 if ((ruleset
= pf_find_ruleset(p
)) != NULL
) {
207 parent
= ruleset
->anchor
;
215 strlcpy(p
, path
, MAXPATHLEN
);
220 while ((r
= strchr(q
, '/')) != NULL
|| *q
) {
223 if (!*q
|| strlen(q
) >= PF_ANCHOR_NAME_SIZE
||
224 (parent
!= NULL
&& strlen(parent
->path
) >=
225 MAXPATHLEN
- PF_ANCHOR_NAME_SIZE
- 1)) {
229 anchor
= (struct pf_anchor
*)rs_malloc(sizeof(*anchor
));
230 if (anchor
== NULL
) {
234 memset(anchor
, 0, sizeof(*anchor
));
235 RB_INIT(&anchor
->children
);
236 strlcpy(anchor
->name
, q
, sizeof(anchor
->name
));
237 if (parent
!= NULL
) {
238 strlcpy(anchor
->path
, parent
->path
,
239 sizeof(anchor
->path
));
240 strlcat(anchor
->path
, "/", sizeof(anchor
->path
));
242 strlcat(anchor
->path
, anchor
->name
, sizeof(anchor
->path
));
243 if ((dup
= RB_INSERT(pf_anchor_global
, &pf_anchors
, anchor
)) !=
245 printf("pf_find_or_create_ruleset: RB_INSERT1 "
246 "'%s' '%s' collides with '%s' '%s'\n",
247 anchor
->path
, anchor
->name
, dup
->path
, dup
->name
);
252 if (parent
!= NULL
) {
253 anchor
->parent
= parent
;
254 if ((dup
= RB_INSERT(pf_anchor_node
, &parent
->children
,
256 printf("pf_find_or_create_ruleset: "
257 "RB_INSERT2 '%s' '%s' collides with "
258 "'%s' '%s'\n", anchor
->path
, anchor
->name
,
259 dup
->path
, dup
->name
);
260 RB_REMOVE(pf_anchor_global
, &pf_anchors
,
267 pf_init_ruleset(&anchor
->ruleset
);
268 anchor
->ruleset
.anchor
= anchor
;
276 return (&anchor
->ruleset
);
280 pf_remove_if_empty_ruleset(struct pf_ruleset
*ruleset
)
282 struct pf_anchor
*parent
;
285 while (ruleset
!= NULL
) {
286 if (ruleset
== &pf_main_ruleset
|| ruleset
->anchor
== NULL
||
287 !RB_EMPTY(&ruleset
->anchor
->children
) ||
288 ruleset
->anchor
->refcnt
> 0 || ruleset
->tables
> 0 ||
291 for (i
= 0; i
< PF_RULESET_MAX
; ++i
)
292 if (!TAILQ_EMPTY(ruleset
->rules
[i
].active
.ptr
) ||
293 !TAILQ_EMPTY(ruleset
->rules
[i
].inactive
.ptr
) ||
294 ruleset
->rules
[i
].inactive
.open
)
296 RB_REMOVE(pf_anchor_global
, &pf_anchors
, ruleset
->anchor
);
297 if ((parent
= ruleset
->anchor
->parent
) != NULL
)
298 RB_REMOVE(pf_anchor_node
, &parent
->children
,
300 rs_free(ruleset
->anchor
);
303 ruleset
= &parent
->ruleset
;
308 pf_anchor_setup(struct pf_rule
*r
, const struct pf_ruleset
*s
,
312 struct pf_ruleset
*ruleset
;
315 r
->anchor_relative
= 0;
316 r
->anchor_wildcard
= 0;
319 path
= (char *)rs_malloc(MAXPATHLEN
);
320 bzero(path
, MAXPATHLEN
);
322 strlcpy(path
, name
+ 1, MAXPATHLEN
);
325 r
->anchor_relative
= 1;
326 if (s
->anchor
== NULL
|| !s
->anchor
->path
[0])
329 strlcpy(path
, s
->anchor
->path
, MAXPATHLEN
);
330 while (name
[0] == '.' && name
[1] == '.' && name
[2] == '/') {
332 printf("pf_anchor_setup: .. beyond root\n");
336 if ((p
= strrchr(path
, '/')) != NULL
)
340 r
->anchor_relative
++;
344 strlcat(path
, "/", MAXPATHLEN
);
345 strlcat(path
, name
, MAXPATHLEN
);
347 if ((p
= strrchr(path
, '/')) != NULL
&& !strcmp(p
, "/*")) {
348 r
->anchor_wildcard
= 1;
351 ruleset
= pf_find_or_create_ruleset(path
);
353 if (ruleset
== NULL
|| ruleset
->anchor
== NULL
) {
354 printf("pf_anchor_setup: ruleset\n");
357 r
->anchor
= ruleset
->anchor
;
363 pf_anchor_copyout(const struct pf_ruleset
*rs
, const struct pf_rule
*r
,
364 struct pfioc_rule
*pr
)
366 pr
->anchor_call
[0] = 0;
367 if (r
->anchor
== NULL
)
369 if (!r
->anchor_relative
) {
370 strlcpy(pr
->anchor_call
, "/", sizeof(pr
->anchor_call
));
371 strlcat(pr
->anchor_call
, r
->anchor
->path
,
372 sizeof(pr
->anchor_call
));
377 a
= (char *)rs_malloc(MAXPATHLEN
);
378 bzero(a
, MAXPATHLEN
);
379 if (rs
->anchor
== NULL
)
382 strlcpy(a
, rs
->anchor
->path
, MAXPATHLEN
);
383 for (i
= 1; i
< r
->anchor_relative
; ++i
) {
384 if ((p
= strrchr(a
, '/')) == NULL
)
387 strlcat(pr
->anchor_call
, "../",
388 sizeof(pr
->anchor_call
));
390 if (strncmp(a
, r
->anchor
->path
, strlen(a
))) {
391 printf("pf_anchor_copyout: '%s' '%s'\n", a
,
396 if (strlen(r
->anchor
->path
) > strlen(a
))
397 strlcat(pr
->anchor_call
, r
->anchor
->path
+ (a
[0] ?
398 strlen(a
) + 1 : 0), sizeof(pr
->anchor_call
));
401 if (r
->anchor_wildcard
)
402 strlcat(pr
->anchor_call
, pr
->anchor_call
[0] ? "/*" : "*",
403 sizeof(pr
->anchor_call
));
408 pf_anchor_remove(struct pf_rule
*r
)
410 if (r
->anchor
== NULL
)
412 if (r
->anchor
->refcnt
<= 0) {
413 printf("pf_anchor_remove: broken refcount\n");
417 if (!--r
->anchor
->refcnt
)
418 pf_remove_if_empty_ruleset(&r
->anchor
->ruleset
);