source: rtems-libbsd/freebsd/contrib/pf/rtems/freebsd/net/pf_ruleset.c @ e2d2bf5

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since e2d2bf5 was e2d2bf5, checked in by Joel Sherrill <joel.sherrill@…>, on 03/08/12 at 13:25:21

Move rtems/freebsd to freebsd and contrib to freebsd/contrib

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