Annotation of sys/net/pf_ruleset.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pf_ruleset.c,v 1.1 2006/10/27 13:56:51 mcbride Exp $ */
2:
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: */
37:
38: #include <sys/param.h>
39: #include <sys/socket.h>
40: #ifdef _KERNEL
41: # include <sys/systm.h>
42: #endif /* _KERNEL */
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/pfvar.h>
52:
53: #ifdef INET6
54: #include <netinet/ip6.h>
55: #endif /* INET6 */
56:
57:
58: #ifdef _KERNEL
59: # define DPFPRINTF(format, x...) \
60: if (pf_status.debug >= PF_DEBUG_NOISY) \
61: printf(format , ##x)
62: #define rs_malloc(x) malloc(x, M_TEMP, M_WAITOK)
63: #define rs_free(x) free(x, M_TEMP)
64:
65: #else
66: /* Userland equivalents so we can lend code to pfctl et al. */
67:
68: # include <arpa/inet.h>
69: # include <errno.h>
70: # include <stdio.h>
71: # include <stdlib.h>
72: # include <string.h>
73: # define rs_malloc(x) malloc(x)
74: # define rs_free(x) free(x)
75:
76: # ifdef PFDEBUG
77: # include <sys/stdarg.h>
78: # define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
79: # else
80: # define DPFPRINTF(format, x...) ((void)0)
81: # endif /* PFDEBUG */
82: #endif /* _KERNEL */
83:
84:
85: struct pf_anchor_global pf_anchors;
86: struct pf_anchor pf_main_anchor;
87:
88: int pf_get_ruleset_number(u_int8_t);
89: void pf_init_ruleset(struct pf_ruleset *);
90: int pf_anchor_setup(struct pf_rule *,
91: const struct pf_ruleset *, const char *);
92: int pf_anchor_copyout(const struct pf_ruleset *,
93: const struct pf_rule *, struct pfioc_rule *);
94: void pf_anchor_remove(struct pf_rule *);
95:
96: static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
97:
98: RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
99: RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
100:
101: static __inline int
102: pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
103: {
104: int c = strcmp(a->path, b->path);
105:
106: return (c ? (c < 0 ? -1 : 1) : 0);
107: }
108:
109: int
110: pf_get_ruleset_number(u_int8_t action)
111: {
112: switch (action) {
113: case PF_SCRUB:
114: case PF_NOSCRUB:
115: return (PF_RULESET_SCRUB);
116: break;
117: case PF_PASS:
118: case PF_DROP:
119: return (PF_RULESET_FILTER);
120: break;
121: case PF_NAT:
122: case PF_NONAT:
123: return (PF_RULESET_NAT);
124: break;
125: case PF_BINAT:
126: case PF_NOBINAT:
127: return (PF_RULESET_BINAT);
128: break;
129: case PF_RDR:
130: case PF_NORDR:
131: return (PF_RULESET_RDR);
132: break;
133: default:
134: return (PF_RULESET_MAX);
135: break;
136: }
137: }
138:
139: void
140: pf_init_ruleset(struct pf_ruleset *ruleset)
141: {
142: int i;
143:
144: memset(ruleset, 0, sizeof(struct pf_ruleset));
145: for (i = 0; i < PF_RULESET_MAX; i++) {
146: TAILQ_INIT(&ruleset->rules[i].queues[0]);
147: TAILQ_INIT(&ruleset->rules[i].queues[1]);
148: ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
149: ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
150: }
151: }
152:
153: struct pf_anchor *
154: pf_find_anchor(const char *path)
155: {
156: struct pf_anchor *key, *found;
157:
158: key = (struct pf_anchor *)rs_malloc(sizeof(*key));
159: memset(key, 0, sizeof(*key));
160: strlcpy(key->path, path, sizeof(key->path));
161: found = RB_FIND(pf_anchor_global, &pf_anchors, key);
162: rs_free(key);
163: return (found);
164: }
165:
166: struct pf_ruleset *
167: pf_find_ruleset(const char *path)
168: {
169: struct pf_anchor *anchor;
170:
171: while (*path == '/')
172: path++;
173: if (!*path)
174: return (&pf_main_ruleset);
175: anchor = pf_find_anchor(path);
176: if (anchor == NULL)
177: return (NULL);
178: else
179: return (&anchor->ruleset);
180: }
181:
182: struct pf_ruleset *
183: pf_find_or_create_ruleset(const char *path)
184: {
185: char *p, *q, *r;
186: struct pf_ruleset *ruleset;
187: struct pf_anchor *anchor, *dup, *parent = NULL;
188:
189: if (path[0] == 0)
190: return (&pf_main_ruleset);
191: while (*path == '/')
192: path++;
193: ruleset = pf_find_ruleset(path);
194: if (ruleset != NULL)
195: return (ruleset);
196: p = (char *)rs_malloc(MAXPATHLEN);
197: bzero(p, MAXPATHLEN);
198: strlcpy(p, path, MAXPATHLEN);
199: while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
200: *q = 0;
201: if ((ruleset = pf_find_ruleset(p)) != NULL) {
202: parent = ruleset->anchor;
203: break;
204: }
205: }
206: if (q == NULL)
207: q = p;
208: else
209: q++;
210: strlcpy(p, path, MAXPATHLEN);
211: if (!*q) {
212: rs_free(p);
213: return (NULL);
214: }
215: while ((r = strchr(q, '/')) != NULL || *q) {
216: if (r != NULL)
217: *r = 0;
218: if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
219: (parent != NULL && strlen(parent->path) >=
220: MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
221: rs_free(p);
222: return (NULL);
223: }
224: anchor = (struct pf_anchor *)rs_malloc(sizeof(*anchor));
225: if (anchor == NULL) {
226: rs_free(p);
227: return (NULL);
228: }
229: memset(anchor, 0, sizeof(*anchor));
230: RB_INIT(&anchor->children);
231: strlcpy(anchor->name, q, sizeof(anchor->name));
232: if (parent != NULL) {
233: strlcpy(anchor->path, parent->path,
234: sizeof(anchor->path));
235: strlcat(anchor->path, "/", sizeof(anchor->path));
236: }
237: strlcat(anchor->path, anchor->name, sizeof(anchor->path));
238: if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
239: NULL) {
240: printf("pf_find_or_create_ruleset: RB_INSERT1 "
241: "'%s' '%s' collides with '%s' '%s'\n",
242: anchor->path, anchor->name, dup->path, dup->name);
243: rs_free(anchor);
244: rs_free(p);
245: return (NULL);
246: }
247: if (parent != NULL) {
248: anchor->parent = parent;
249: if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
250: anchor)) != NULL) {
251: printf("pf_find_or_create_ruleset: "
252: "RB_INSERT2 '%s' '%s' collides with "
253: "'%s' '%s'\n", anchor->path, anchor->name,
254: dup->path, dup->name);
255: RB_REMOVE(pf_anchor_global, &pf_anchors,
256: anchor);
257: rs_free(anchor);
258: rs_free(p);
259: return (NULL);
260: }
261: }
262: pf_init_ruleset(&anchor->ruleset);
263: anchor->ruleset.anchor = anchor;
264: parent = anchor;
265: if (r != NULL)
266: q = r + 1;
267: else
268: *q = 0;
269: }
270: rs_free(p);
271: return (&anchor->ruleset);
272: }
273:
274: void
275: pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
276: {
277: struct pf_anchor *parent;
278: int i;
279:
280: while (ruleset != NULL) {
281: if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
282: !RB_EMPTY(&ruleset->anchor->children) ||
283: ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
284: ruleset->topen)
285: return;
286: for (i = 0; i < PF_RULESET_MAX; ++i)
287: if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
288: !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
289: ruleset->rules[i].inactive.open)
290: return;
291: RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
292: if ((parent = ruleset->anchor->parent) != NULL)
293: RB_REMOVE(pf_anchor_node, &parent->children,
294: ruleset->anchor);
295: rs_free(ruleset->anchor);
296: if (parent == NULL)
297: return;
298: ruleset = &parent->ruleset;
299: }
300: }
301:
302: int
303: pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
304: const char *name)
305: {
306: char *p, *path;
307: struct pf_ruleset *ruleset;
308:
309: r->anchor = NULL;
310: r->anchor_relative = 0;
311: r->anchor_wildcard = 0;
312: if (!name[0])
313: return (0);
314: path = (char *)rs_malloc(MAXPATHLEN);
315: bzero(path, MAXPATHLEN);
316: if (name[0] == '/')
317: strlcpy(path, name + 1, MAXPATHLEN);
318: else {
319: /* relative path */
320: r->anchor_relative = 1;
321: if (s->anchor == NULL || !s->anchor->path[0])
322: path[0] = 0;
323: else
324: strlcpy(path, s->anchor->path, MAXPATHLEN);
325: while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
326: if (!path[0]) {
327: printf("pf_anchor_setup: .. beyond root\n");
328: rs_free(path);
329: return (1);
330: }
331: if ((p = strrchr(path, '/')) != NULL)
332: *p = 0;
333: else
334: path[0] = 0;
335: r->anchor_relative++;
336: name += 3;
337: }
338: if (path[0])
339: strlcat(path, "/", MAXPATHLEN);
340: strlcat(path, name, MAXPATHLEN);
341: }
342: if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
343: r->anchor_wildcard = 1;
344: *p = 0;
345: }
346: ruleset = pf_find_or_create_ruleset(path);
347: rs_free(path);
348: if (ruleset == NULL || ruleset->anchor == NULL) {
349: printf("pf_anchor_setup: ruleset\n");
350: return (1);
351: }
352: r->anchor = ruleset->anchor;
353: r->anchor->refcnt++;
354: return (0);
355: }
356:
357: int
358: pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
359: struct pfioc_rule *pr)
360: {
361: pr->anchor_call[0] = 0;
362: if (r->anchor == NULL)
363: return (0);
364: if (!r->anchor_relative) {
365: strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
366: strlcat(pr->anchor_call, r->anchor->path,
367: sizeof(pr->anchor_call));
368: } else {
369: char *a, *p;
370: int i;
371:
372: a = (char *)rs_malloc(MAXPATHLEN);
373: bzero(a, MAXPATHLEN);
374: if (rs->anchor == NULL)
375: a[0] = 0;
376: else
377: strlcpy(a, rs->anchor->path, MAXPATHLEN);
378: for (i = 1; i < r->anchor_relative; ++i) {
379: if ((p = strrchr(a, '/')) == NULL)
380: p = a;
381: *p = 0;
382: strlcat(pr->anchor_call, "../",
383: sizeof(pr->anchor_call));
384: }
385: if (strncmp(a, r->anchor->path, strlen(a))) {
386: printf("pf_anchor_copyout: '%s' '%s'\n", a,
387: r->anchor->path);
388: rs_free(a);
389: return (1);
390: }
391: if (strlen(r->anchor->path) > strlen(a))
392: strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
393: strlen(a) + 1 : 0), sizeof(pr->anchor_call));
394: rs_free(a);
395: }
396: if (r->anchor_wildcard)
397: strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
398: sizeof(pr->anchor_call));
399: return (0);
400: }
401:
402: void
403: pf_anchor_remove(struct pf_rule *r)
404: {
405: if (r->anchor == NULL)
406: return;
407: if (r->anchor->refcnt <= 0) {
408: printf("pf_anchor_remove: broken refcount\n");
409: r->anchor = NULL;
410: return;
411: }
412: if (!--r->anchor->refcnt)
413: pf_remove_if_empty_ruleset(&r->anchor->ruleset);
414: r->anchor = NULL;
415: }
CVSweb