[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

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