source: rtems-libbsd/freebsd/sys/contrib/pf/net/pf_ruleset.c @ 66659ff

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 66659ff was 66659ff, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 15:20:21

Update to FreeBSD 9.2

  • Property mode set to 100644
File size: 11.2 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*      $OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $ */
4
5/*
6 * Copyright (c) 2001 Daniel Hartmeier
7 * Copyright (c) 2002,2003 Henning Brauer
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 *    - Redistributions of source code must retain the above copyright
15 *      notice, this list of conditions and the following disclaimer.
16 *    - Redistributions in binary form must reproduce the above
17 *      copyright notice, this list of conditions and the following
18 *      disclaimer in the documentation and/or other materials provided
19 *      with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 * Effort sponsored in part by the Defense Advanced Research Projects
35 * Agency (DARPA) and Air Force Research Laboratory, Air Force
36 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
37 *
38 */
39
40#ifdef __FreeBSD__
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD$");
43#endif
44
45#include <rtems/bsd/sys/param.h>
46#include <sys/socket.h>
47#ifdef _KERNEL
48# include <sys/systm.h>
49#endif /* _KERNEL */
50#include <sys/mbuf.h>
51
52#include <netinet/in.h>
53#include <netinet/in_systm.h>
54#include <netinet/ip.h>
55#include <netinet/tcp.h>
56
57#include <net/if.h>
58#include <net/pfvar.h>
59
60#ifdef INET6
61#include <netinet/ip6.h>
62#endif /* INET6 */
63
64
65#ifdef _KERNEL
66#ifdef __FreeBSD__
67#define DPFPRINTF(format, x...)                         \
68        if (V_pf_status.debug >= PF_DEBUG_NOISY)        \
69                printf(format , ##x)
70#else
71#define DPFPRINTF(format, x...)                         \
72        if (pf_status.debug >= PF_DEBUG_NOISY)          \
73                printf(format , ##x)
74#endif
75#ifdef __FreeBSD__
76#define rs_malloc(x)            malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
77#else
78#define rs_malloc(x)            malloc(x, M_TEMP, M_WAITOK|M_CANFAIL|M_ZERO)
79#endif
80#define rs_free(x)              free(x, M_TEMP)
81
82#else
83/* Userland equivalents so we can lend code to pfctl et al. */
84
85#include <arpa/inet.h>
86#include <errno.h>
87#include <stdio.h>
88#include <stdlib.h>
89#include <string.h>
90#define rs_malloc(x)             calloc(1, x)
91#define rs_free(x)               free(x)
92
93#ifdef PFDEBUG
94#include <sys/stdarg.h>
95#define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
96#else
97#define DPFPRINTF(format, x...) ((void)0)
98#endif /* PFDEBUG */
99#endif /* _KERNEL */
100
101#if defined(__FreeBSD__) && !defined(_KERNEL)
102#undef V_pf_anchors
103#define V_pf_anchors             pf_anchors
104
105#undef pf_main_ruleset
106#define pf_main_ruleset          pf_main_anchor.ruleset
107#endif
108
109#if defined(__FreeBSD__) && defined(_KERNEL)
110VNET_DEFINE(struct pf_anchor_global,    pf_anchors);
111VNET_DEFINE(struct pf_anchor,           pf_main_anchor);
112#else
113struct pf_anchor_global  pf_anchors;
114struct pf_anchor         pf_main_anchor;
115#endif
116
117static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
118
119RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
120RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
121
122static __inline int
123pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
124{
125        int c = strcmp(a->path, b->path);
126
127        return (c ? (c < 0 ? -1 : 1) : 0);
128}
129
130int
131pf_get_ruleset_number(u_int8_t action)
132{
133        switch (action) {
134        case PF_SCRUB:
135        case PF_NOSCRUB:
136                return (PF_RULESET_SCRUB);
137                break;
138        case PF_PASS:
139        case PF_DROP:
140                return (PF_RULESET_FILTER);
141                break;
142        case PF_NAT:
143        case PF_NONAT:
144                return (PF_RULESET_NAT);
145                break;
146        case PF_BINAT:
147        case PF_NOBINAT:
148                return (PF_RULESET_BINAT);
149                break;
150        case PF_RDR:
151        case PF_NORDR:
152                return (PF_RULESET_RDR);
153                break;
154        default:
155                return (PF_RULESET_MAX);
156                break;
157        }
158}
159
160void
161pf_init_ruleset(struct pf_ruleset *ruleset)
162{
163        int     i;
164
165        memset(ruleset, 0, sizeof(struct pf_ruleset));
166        for (i = 0; i < PF_RULESET_MAX; i++) {
167                TAILQ_INIT(&ruleset->rules[i].queues[0]);
168                TAILQ_INIT(&ruleset->rules[i].queues[1]);
169                ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
170                ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
171        }
172}
173
174struct pf_anchor *
175pf_find_anchor(const char *path)
176{
177        struct pf_anchor        *key, *found;
178
179        key = (struct pf_anchor *)rs_malloc(sizeof(*key));
180        if (key == NULL)
181                return (NULL);
182        strlcpy(key->path, path, sizeof(key->path));
183#ifdef __FreeBSD__
184        found = RB_FIND(pf_anchor_global, &V_pf_anchors, key);
185#else
186        found = RB_FIND(pf_anchor_global, &pf_anchors, key);
187#endif
188        rs_free(key);
189        return (found);
190}
191
192struct pf_ruleset *
193pf_find_ruleset(const char *path)
194{
195        struct pf_anchor        *anchor;
196
197        while (*path == '/')
198                path++;
199        if (!*path)
200                return (&pf_main_ruleset);
201        anchor = pf_find_anchor(path);
202        if (anchor == NULL)
203                return (NULL);
204        else
205                return (&anchor->ruleset);
206}
207
208struct pf_ruleset *
209pf_find_or_create_ruleset(const char *path)
210{
211        char                    *p, *q, *r;
212        struct pf_ruleset       *ruleset;
213#ifdef __FreeBSD__
214        struct pf_anchor        *anchor = NULL, *dup, *parent = NULL;
215#else
216        struct pf_anchor        *anchor, *dup, *parent = NULL;
217#endif
218
219        if (path[0] == 0)
220                return (&pf_main_ruleset);
221        while (*path == '/')
222                path++;
223        ruleset = pf_find_ruleset(path);
224        if (ruleset != NULL)
225                return (ruleset);
226        p = (char *)rs_malloc(MAXPATHLEN);
227        if (p == NULL)
228                return (NULL);
229        strlcpy(p, path, MAXPATHLEN);
230        while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
231                *q = 0;
232                if ((ruleset = pf_find_ruleset(p)) != NULL) {
233                        parent = ruleset->anchor;
234                        break;
235                }
236        }
237        if (q == NULL)
238                q = p;
239        else
240                q++;
241        strlcpy(p, path, MAXPATHLEN);
242        if (!*q) {
243                rs_free(p);
244                return (NULL);
245        }
246        while ((r = strchr(q, '/')) != NULL || *q) {
247                if (r != NULL)
248                        *r = 0;
249                if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
250                    (parent != NULL && strlen(parent->path) >=
251                    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
252                        rs_free(p);
253                        return (NULL);
254                }
255                anchor = (struct pf_anchor *)rs_malloc(sizeof(*anchor));
256                if (anchor == NULL) {
257                        rs_free(p);
258                        return (NULL);
259                }
260                RB_INIT(&anchor->children);
261                strlcpy(anchor->name, q, sizeof(anchor->name));
262                if (parent != NULL) {
263                        strlcpy(anchor->path, parent->path,
264                            sizeof(anchor->path));
265                        strlcat(anchor->path, "/", sizeof(anchor->path));
266                }
267                strlcat(anchor->path, anchor->name, sizeof(anchor->path));
268#ifdef __FreeBSD__
269                if ((dup = RB_INSERT(pf_anchor_global, &V_pf_anchors, anchor)) !=
270#else
271                if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
272#endif
273                    NULL) {
274                        printf("pf_find_or_create_ruleset: RB_INSERT1 "
275                            "'%s' '%s' collides with '%s' '%s'\n",
276                            anchor->path, anchor->name, dup->path, dup->name);
277                        rs_free(anchor);
278                        rs_free(p);
279                        return (NULL);
280                }
281                if (parent != NULL) {
282                        anchor->parent = parent;
283                        if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
284                            anchor)) != NULL) {
285                                printf("pf_find_or_create_ruleset: "
286                                    "RB_INSERT2 '%s' '%s' collides with "
287                                    "'%s' '%s'\n", anchor->path, anchor->name,
288                                    dup->path, dup->name);
289#ifdef __FreeBSD__
290                                RB_REMOVE(pf_anchor_global, &V_pf_anchors,
291#else
292                                RB_REMOVE(pf_anchor_global, &pf_anchors,
293#endif
294                                    anchor);
295                                rs_free(anchor);
296                                rs_free(p);
297                                return (NULL);
298                        }
299                }
300                pf_init_ruleset(&anchor->ruleset);
301                anchor->ruleset.anchor = anchor;
302                parent = anchor;
303                if (r != NULL)
304                        q = r + 1;
305                else
306                        *q = 0;
307        }
308        rs_free(p);
309        return (&anchor->ruleset);
310}
311
312void
313pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
314{
315        struct pf_anchor        *parent;
316        int                      i;
317
318        while (ruleset != NULL) {
319                if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
320                    !RB_EMPTY(&ruleset->anchor->children) ||
321                    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
322                    ruleset->topen)
323                        return;
324                for (i = 0; i < PF_RULESET_MAX; ++i)
325                        if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
326                            !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
327                            ruleset->rules[i].inactive.open)
328                                return;
329#ifdef __FreeBSD__
330                RB_REMOVE(pf_anchor_global, &V_pf_anchors, ruleset->anchor);
331#else
332                RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
333#endif
334                if ((parent = ruleset->anchor->parent) != NULL)
335                        RB_REMOVE(pf_anchor_node, &parent->children,
336                            ruleset->anchor);
337                rs_free(ruleset->anchor);
338                if (parent == NULL)
339                        return;
340                ruleset = &parent->ruleset;
341        }
342}
343
344int
345pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
346    const char *name)
347{
348        char                    *p, *path;
349        struct pf_ruleset       *ruleset;
350
351        r->anchor = NULL;
352        r->anchor_relative = 0;
353        r->anchor_wildcard = 0;
354        if (!name[0])
355                return (0);
356        path = (char *)rs_malloc(MAXPATHLEN);
357        if (path == NULL)
358                return (1);
359        if (name[0] == '/')
360                strlcpy(path, name + 1, MAXPATHLEN);
361        else {
362                /* relative path */
363                r->anchor_relative = 1;
364                if (s->anchor == NULL || !s->anchor->path[0])
365                        path[0] = 0;
366                else
367                        strlcpy(path, s->anchor->path, MAXPATHLEN);
368                while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
369                        if (!path[0]) {
370                                printf("pf_anchor_setup: .. beyond root\n");
371                                rs_free(path);
372                                return (1);
373                        }
374                        if ((p = strrchr(path, '/')) != NULL)
375                                *p = 0;
376                        else
377                                path[0] = 0;
378                        r->anchor_relative++;
379                        name += 3;
380                }
381                if (path[0])
382                        strlcat(path, "/", MAXPATHLEN);
383                strlcat(path, name, MAXPATHLEN);
384        }
385        if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
386                r->anchor_wildcard = 1;
387                *p = 0;
388        }
389        ruleset = pf_find_or_create_ruleset(path);
390        rs_free(path);
391        if (ruleset == NULL || ruleset->anchor == NULL) {
392                printf("pf_anchor_setup: ruleset\n");
393                return (1);
394        }
395        r->anchor = ruleset->anchor;
396        r->anchor->refcnt++;
397        return (0);
398}
399
400int
401pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
402    struct pfioc_rule *pr)
403{
404        pr->anchor_call[0] = 0;
405        if (r->anchor == NULL)
406                return (0);
407        if (!r->anchor_relative) {
408                strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
409                strlcat(pr->anchor_call, r->anchor->path,
410                    sizeof(pr->anchor_call));
411        } else {
412                char    *a, *p;
413                int      i;
414
415                a = (char *)rs_malloc(MAXPATHLEN);
416                if (a == NULL)
417                        return (1);
418                if (rs->anchor == NULL)
419                        a[0] = 0;
420                else
421                        strlcpy(a, rs->anchor->path, MAXPATHLEN);
422                for (i = 1; i < r->anchor_relative; ++i) {
423                        if ((p = strrchr(a, '/')) == NULL)
424                                p = a;
425                        *p = 0;
426                        strlcat(pr->anchor_call, "../",
427                            sizeof(pr->anchor_call));
428                }
429                if (strncmp(a, r->anchor->path, strlen(a))) {
430                        printf("pf_anchor_copyout: '%s' '%s'\n", a,
431                            r->anchor->path);
432                        rs_free(a);
433                        return (1);
434                }
435                if (strlen(r->anchor->path) > strlen(a))
436                        strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
437                            strlen(a) + 1 : 0), sizeof(pr->anchor_call));
438                rs_free(a);
439        }
440        if (r->anchor_wildcard)
441                strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
442                    sizeof(pr->anchor_call));
443        return (0);
444}
445
446void
447pf_anchor_remove(struct pf_rule *r)
448{
449        if (r->anchor == NULL)
450                return;
451        if (r->anchor->refcnt <= 0) {
452                printf("pf_anchor_remove: broken refcount\n");
453                r->anchor = NULL;
454                return;
455        }
456        if (!--r->anchor->refcnt)
457                pf_remove_if_empty_ruleset(&r->anchor->ruleset);
458        r->anchor = NULL;
459}
Note: See TracBrowser for help on using the repository browser.