[BACK]Return to pf_ruleset.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/pf_ruleset.c, Revision 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