[BACK]Return to npf_build.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / npf / npfctl

Annotation of src/usr.sbin/npf/npfctl/npf_build.c, Revision 1.27

1.27    ! rmind       1: /*     $NetBSD: npf_build.c,v 1.26 2013/09/19 12:05:11 rmind Exp $     */
1.1       rmind       2:
                      3: /*-
1.18      rmind       4:  * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
1.1       rmind       5:  * All rights reserved.
                      6:  *
                      7:  * This material is based upon work partially supported by The
                      8:  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
                      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:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
                     33:  * npfctl(8) building of the configuration.
                     34:  */
                     35:
                     36: #include <sys/cdefs.h>
1.27    ! rmind      37: __RCSID("$NetBSD: npf_build.c,v 1.26 2013/09/19 12:05:11 rmind Exp $");
1.1       rmind      38:
                     39: #include <sys/types.h>
                     40: #include <sys/ioctl.h>
                     41:
                     42: #include <stdlib.h>
                     43: #include <inttypes.h>
                     44: #include <string.h>
1.14      rmind      45: #include <errno.h>
1.1       rmind      46: #include <err.h>
                     47:
1.25      rmind      48: #include <pcap/pcap.h>
                     49:
1.1       rmind      50: #include "npfctl.h"
                     51:
1.18      rmind      52: #define        MAX_RULE_NESTING        16
                     53:
1.1       rmind      54: static nl_config_t *           npf_conf = NULL;
                     55: static bool                    npf_debug = false;
1.18      rmind      56: static nl_rule_t *             the_rule = NULL;
                     57:
                     58: static nl_rule_t *             current_group[MAX_RULE_NESTING];
                     59: static unsigned                        rule_nesting_level = 0;
                     60: static nl_rule_t *             defgroup = NULL;
1.1       rmind      61:
1.27    ! rmind      62: static void                    npfctl_dump_bpf(struct bpf_program *);
        !            63:
1.1       rmind      64: void
                     65: npfctl_config_init(bool debug)
                     66: {
                     67:        npf_conf = npf_config_create();
                     68:        if (npf_conf == NULL) {
                     69:                errx(EXIT_FAILURE, "npf_config_create failed");
                     70:        }
                     71:        npf_debug = debug;
1.18      rmind      72:        memset(current_group, 0, sizeof(current_group));
1.1       rmind      73: }
                     74:
                     75: int
1.13      rmind      76: npfctl_config_send(int fd, const char *out)
1.1       rmind      77: {
                     78:        int error;
                     79:
1.13      rmind      80:        if (out) {
                     81:                _npf_config_setsubmit(npf_conf, out);
                     82:                printf("\nSaving to %s\n", out);
1.1       rmind      83:        }
1.18      rmind      84:        if (!defgroup) {
1.1       rmind      85:                errx(EXIT_FAILURE, "default group was not defined");
                     86:        }
1.18      rmind      87:        npf_rule_insert(npf_conf, NULL, defgroup);
1.1       rmind      88:        error = npf_config_submit(npf_conf, fd);
1.3       rmind      89:        if (error) {
                     90:                nl_error_t ne;
                     91:                _npf_config_error(npf_conf, &ne);
                     92:                npfctl_print_error(&ne);
                     93:        }
1.25      rmind      94:        if (fd) {
                     95:                npf_config_destroy(npf_conf);
                     96:        }
1.1       rmind      97:        return error;
                     98: }
                     99:
1.16      rmind     100: nl_config_t *
                    101: npfctl_config_ref(void)
                    102: {
                    103:        return npf_conf;
                    104: }
                    105:
1.18      rmind     106: nl_rule_t *
                    107: npfctl_rule_ref(void)
                    108: {
                    109:        return the_rule;
                    110: }
                    111:
1.13      rmind     112: unsigned long
                    113: npfctl_debug_addif(const char *ifname)
                    114: {
                    115:        char tname[] = "npftest";
                    116:        const size_t tnamelen = sizeof(tname) - 1;
                    117:
                    118:        if (!npf_debug || strncmp(ifname, tname, tnamelen) != 0) {
                    119:                return 0;
                    120:        }
                    121:        struct ifaddrs ifa = {
                    122:                .ifa_name = __UNCONST(ifname),
                    123:                .ifa_flags = 0
                    124:        };
                    125:        unsigned long if_idx = atol(ifname + tnamelen) + 1;
                    126:        _npf_debug_addif(npf_conf, &ifa, if_idx);
                    127:        return if_idx;
                    128: }
                    129:
1.1       rmind     130: bool
                    131: npfctl_table_exists_p(const char *id)
                    132: {
                    133:        return npf_table_exists_p(npf_conf, atoi(id));
                    134: }
                    135:
1.7       rmind     136: static in_port_t
1.1       rmind     137: npfctl_get_singleport(const npfvar_t *vp)
                    138: {
                    139:        port_range_t *pr;
1.7       rmind     140:        in_port_t *port;
1.1       rmind     141:
                    142:        if (npfvar_get_count(vp) > 1) {
                    143:                yyerror("multiple ports are not valid");
                    144:        }
                    145:        pr = npfvar_get_data(vp, NPFVAR_PORT_RANGE, 0);
                    146:        if (pr->pr_start != pr->pr_end) {
                    147:                yyerror("port range is not valid");
                    148:        }
1.7       rmind     149:        port = &pr->pr_start;
                    150:        return *port;
1.1       rmind     151: }
                    152:
                    153: static fam_addr_mask_t *
                    154: npfctl_get_singlefam(const npfvar_t *vp)
                    155: {
                    156:        if (npfvar_get_count(vp) > 1) {
                    157:                yyerror("multiple addresses are not valid");
                    158:        }
                    159:        return npfvar_get_data(vp, NPFVAR_FAM, 0);
                    160: }
                    161:
1.10      rmind     162: static bool
1.25      rmind     163: npfctl_build_fam(npf_bpf_t *ctx, sa_family_t family,
1.1       rmind     164:     fam_addr_mask_t *fam, int opts)
                    165: {
                    166:        /*
                    167:         * If family is specified, address does not match it and the
                    168:         * address is extracted from the interface, then simply ignore.
                    169:         * Otherwise, address of invalid family was passed manually.
                    170:         */
                    171:        if (family != AF_UNSPEC && family != fam->fam_family) {
1.15      rmind     172:                if (!fam->fam_ifindex) {
1.1       rmind     173:                        yyerror("specified address is not of the required "
                    174:                            "family %d", family);
                    175:                }
1.10      rmind     176:                return false;
1.1       rmind     177:        }
1.25      rmind     178:        family = fam->fam_family;
1.1       rmind     179:
                    180:        /*
                    181:         * Optimise 0.0.0.0/0 case to be NOP.  Otherwise, address with
                    182:         * zero mask would never match and therefore is not valid.
                    183:         */
                    184:        if (fam->fam_mask == 0) {
                    185:                npf_addr_t zero;
1.10      rmind     186:
1.1       rmind     187:                memset(&zero, 0, sizeof(npf_addr_t));
                    188:                if (memcmp(&fam->fam_addr, &zero, sizeof(npf_addr_t))) {
                    189:                        yyerror("filter criterion would never match");
                    190:                }
1.10      rmind     191:                return false;
1.1       rmind     192:        }
                    193:
1.25      rmind     194:        if (family != AF_INET && family != AF_INET6) {
                    195:                yyerror("family %d is not supported", family);
1.1       rmind     196:        }
1.25      rmind     197:        npfctl_bpf_cidr(ctx, opts, family, &fam->fam_addr, fam->fam_mask);
1.10      rmind     198:        return true;
1.1       rmind     199: }
                    200:
                    201: static void
1.25      rmind     202: npfctl_build_vars(npf_bpf_t *ctx, sa_family_t family, npfvar_t *vars, int opts)
1.1       rmind     203: {
1.6       christos  204:        const int type = npfvar_get_type(vars, 0);
1.1       rmind     205:        size_t i;
                    206:
1.25      rmind     207:        npfctl_bpf_group(ctx);
1.1       rmind     208:        for (i = 0; i < npfvar_get_count(vars); i++) {
                    209:                void *data = npfvar_get_data(vars, type, i);
                    210:                assert(data != NULL);
                    211:
                    212:                switch (type) {
                    213:                case NPFVAR_FAM: {
                    214:                        fam_addr_mask_t *fam = data;
1.25      rmind     215:                        npfctl_build_fam(ctx, family, fam, opts);
1.1       rmind     216:                        break;
                    217:                }
                    218:                case NPFVAR_PORT_RANGE: {
                    219:                        port_range_t *pr = data;
1.25      rmind     220:                        npfctl_bpf_ports(ctx, opts, pr->pr_start, pr->pr_end);
1.1       rmind     221:                        break;
                    222:                }
                    223:                case NPFVAR_TABLE: {
                    224:                        u_int tid = atoi(data);
1.25      rmind     225:                        npfctl_bpf_table(ctx, opts, tid);
1.1       rmind     226:                        break;
                    227:                }
                    228:                default:
                    229:                        assert(false);
                    230:                }
                    231:        }
1.25      rmind     232:        npfctl_bpf_endgroup(ctx);
1.1       rmind     233: }
                    234:
1.25      rmind     235: static void
                    236: npfctl_build_proto(npf_bpf_t *ctx, sa_family_t family, const opt_proto_t *op)
1.1       rmind     237: {
                    238:        const npfvar_t *popts = op->op_opts;
1.10      rmind     239:        const int proto = op->op_proto;
1.25      rmind     240:
                    241:        /* IP version and/or L4 protocol matching. */
                    242:        if (family != AF_UNSPEC || proto != -1) {
                    243:                npfctl_bpf_proto(ctx, family, proto);
                    244:        }
1.1       rmind     245:
1.10      rmind     246:        switch (proto) {
1.1       rmind     247:        case IPPROTO_TCP:
1.25      rmind     248:                /* Build TCP flags matching (optional). */
                    249:                if (popts) {
                    250:                        uint8_t *tf, *tf_mask;
                    251:
                    252:                        assert(npfvar_get_count(popts) == 2);
                    253:                        tf = npfvar_get_data(popts, NPFVAR_TCPFLAG, 0);
                    254:                        tf_mask = npfvar_get_data(popts, NPFVAR_TCPFLAG, 1);
                    255:                        npfctl_bpf_tcpfl(ctx, *tf, *tf_mask);
1.1       rmind     256:                }
                    257:                break;
                    258:        case IPPROTO_ICMP:
1.12      spz       259:        case IPPROTO_ICMPV6:
1.25      rmind     260:                /* Build ICMP/ICMPv6 type and/or code matching. */
                    261:                if (popts) {
                    262:                        int *icmp_type, *icmp_code;
                    263:
                    264:                        assert(npfvar_get_count(popts) == 2);
                    265:                        icmp_type = npfvar_get_data(popts, NPFVAR_ICMP, 0);
                    266:                        icmp_code = npfvar_get_data(popts, NPFVAR_ICMP, 1);
                    267:                        npfctl_bpf_icmp(ctx, *icmp_type, *icmp_code);
1.12      spz       268:                }
                    269:                break;
1.25      rmind     270:        default:
                    271:                /* No options for other protocols. */
1.1       rmind     272:                break;
1.10      rmind     273:        }
1.1       rmind     274: }
                    275:
                    276: static bool
1.25      rmind     277: npfctl_build_code(nl_rule_t *rl, sa_family_t family, const opt_proto_t *op,
1.27    ! rmind     278:     const filt_opts_t *fopts)
1.1       rmind     279: {
1.7       rmind     280:        const addr_port_t *apfrom = &fopts->fo_from;
                    281:        const addr_port_t *apto = &fopts->fo_to;
1.10      rmind     282:        const int proto = op->op_proto;
1.25      rmind     283:        bool noproto, noaddrs, noports;
                    284:        npf_bpf_t *bc;
1.1       rmind     285:        size_t len;
                    286:
1.25      rmind     287:        /* If none specified, then no byte-code. */
                    288:        noproto = family == AF_UNSPEC && proto == -1 && !op->op_opts;
1.20      rmind     289:        noaddrs = !apfrom->ap_netaddr && !apto->ap_netaddr;
                    290:        noports = !apfrom->ap_portrange && !apto->ap_portrange;
1.25      rmind     291:        if (noproto && noaddrs && noports) {
1.1       rmind     292:                return false;
1.25      rmind     293:        }
1.1       rmind     294:
1.25      rmind     295:        /*
                    296:         * Sanity check: ports can only be used with TCP or UDP protocol.
                    297:         * No filter options are supported for other protocols, only the
                    298:         * IP addresses are allowed.
                    299:         */
                    300:        if (!noports) {
                    301:                switch (proto) {
                    302:                case IPPROTO_TCP:
                    303:                case IPPROTO_UDP:
                    304:                case -1:
                    305:                        break;
                    306:                default:
                    307:                        yyerror("invalid filter options for protocol %d", proto);
                    308:                }
                    309:        }
1.1       rmind     310:
1.25      rmind     311:        bc = npfctl_bpf_create();
1.1       rmind     312:
1.10      rmind     313:        /* Build layer 4 protocol blocks. */
1.25      rmind     314:        npfctl_build_proto(bc, family, op);
1.10      rmind     315:
1.1       rmind     316:        /* Build IP address blocks. */
1.27    ! rmind     317:        npfctl_build_vars(bc, family, apfrom->ap_netaddr, MATCH_SRC);
        !           318:        npfctl_build_vars(bc, family, apto->ap_netaddr, MATCH_DST);
1.1       rmind     319:
                    320:        /* Build port-range blocks. */
1.27    ! rmind     321:        npfctl_build_vars(bc, family, apfrom->ap_portrange, MATCH_SRC);
        !           322:        npfctl_build_vars(bc, family, apto->ap_portrange, MATCH_DST);
1.25      rmind     323:
                    324:        /* Set the byte-code marks, if any. */
                    325:        const void *bmarks = npfctl_bpf_bmarks(bc, &len);
                    326:        if (npf_rule_setinfo(rl, bmarks, len) == -1) {
                    327:                errx(EXIT_FAILURE, "npf_rule_setinfo failed");
                    328:        }
1.1       rmind     329:
1.25      rmind     330:        /* Complete BPF byte-code and pass to the rule. */
                    331:        struct bpf_program *bf = npfctl_bpf_complete(bc);
                    332:        len = bf->bf_len * sizeof(struct bpf_insn);
1.10      rmind     333:
1.25      rmind     334:        if (npf_rule_setcode(rl, NPF_CODE_BPF, bf->bf_insns, len) == -1) {
1.1       rmind     335:                errx(EXIT_FAILURE, "npf_rule_setcode failed");
                    336:        }
1.27    ! rmind     337:        npfctl_dump_bpf(bf);
1.25      rmind     338:        npfctl_bpf_destroy(bc);
                    339:
1.1       rmind     340:        return true;
                    341: }
                    342:
1.4       rmind     343: static void
1.27    ! rmind     344: npfctl_build_pcap(nl_rule_t *rl, const char *filter)
        !           345: {
        !           346:        const size_t maxsnaplen = 64 * 1024;
        !           347:        struct bpf_program bf;
        !           348:        size_t len;
        !           349:
        !           350:        if (pcap_compile_nopcap(maxsnaplen, DLT_RAW, &bf,
        !           351:            filter, 1, PCAP_NETMASK_UNKNOWN) == -1) {
        !           352:                yyerror("invalid pcap-filter(7) syntax");
        !           353:        }
        !           354:        len = bf.bf_len * sizeof(struct bpf_insn);
        !           355:
        !           356:        if (npf_rule_setcode(rl, NPF_CODE_BPF, bf.bf_insns, len) == -1) {
        !           357:                errx(EXIT_FAILURE, "npf_rule_setcode failed");
        !           358:        }
        !           359:        npfctl_dump_bpf(&bf);
        !           360:        pcap_freecode(&bf);
        !           361: }
        !           362:
        !           363: static void
1.4       rmind     364: npfctl_build_rpcall(nl_rproc_t *rp, const char *name, npfvar_t *args)
                    365: {
1.14      rmind     366:        npf_extmod_t *extmod;
                    367:        nl_ext_t *extcall;
                    368:        int error;
1.4       rmind     369:
1.14      rmind     370:        extmod = npf_extmod_get(name, &extcall);
                    371:        if (extmod == NULL) {
1.4       rmind     372:                yyerror("unknown rule procedure '%s'", name);
                    373:        }
                    374:
                    375:        for (size_t i = 0; i < npfvar_get_count(args); i++) {
1.14      rmind     376:                const char *param, *value;
                    377:                proc_param_t *p;
1.4       rmind     378:
1.14      rmind     379:                p = npfvar_get_data(args, NPFVAR_PROC_PARAM, i);
                    380:                param = p->pp_param;
                    381:                value = p->pp_value;
                    382:
                    383:                error = npf_extmod_param(extmod, extcall, param, value);
                    384:                switch (error) {
                    385:                case EINVAL:
                    386:                        yyerror("invalid parameter '%s'", param);
                    387:                default:
                    388:                        break;
1.4       rmind     389:                }
                    390:        }
1.14      rmind     391:        error = npf_rproc_extcall(rp, extcall);
                    392:        if (error) {
                    393:                yyerror(error == EEXIST ?
                    394:                    "duplicate procedure call" : "unexpected error");
                    395:        }
1.4       rmind     396: }
                    397:
1.1       rmind     398: /*
                    399:  * npfctl_build_rproc: create and insert a rule procedure.
                    400:  */
                    401: void
1.4       rmind     402: npfctl_build_rproc(const char *name, npfvar_t *procs)
1.1       rmind     403: {
                    404:        nl_rproc_t *rp;
1.4       rmind     405:        size_t i;
1.1       rmind     406:
                    407:        rp = npf_rproc_create(name);
                    408:        if (rp == NULL) {
1.23      christos  409:                errx(EXIT_FAILURE, "%s failed", __func__);
1.1       rmind     410:        }
                    411:        npf_rproc_insert(npf_conf, rp);
1.4       rmind     412:
                    413:        for (i = 0; i < npfvar_get_count(procs); i++) {
1.14      rmind     414:                proc_call_t *pc = npfvar_get_data(procs, NPFVAR_PROC, i);
                    415:                npfctl_build_rpcall(rp, pc->pc_name, pc->pc_opts);
1.4       rmind     416:        }
1.1       rmind     417: }
                    418:
1.22      rmind     419: void
                    420: npfctl_build_maprset(const char *name, int attr, u_int if_idx)
                    421: {
                    422:        const int attr_di = (NPF_RULE_IN | NPF_RULE_OUT);
                    423:        nl_rule_t *rl;
                    424:
                    425:        /* If no direction is not specified, then both. */
                    426:        if ((attr & attr_di) == 0) {
                    427:                attr |= attr_di;
                    428:        }
                    429:        /* Allow only "in/out" attributes. */
                    430:        attr = NPF_RULE_GROUP | NPF_RULE_GROUP | (attr & attr_di);
                    431:        rl = npf_rule_create(name, attr, if_idx);
                    432:        npf_nat_insert(npf_conf, rl, NPF_PRI_LAST);
                    433: }
                    434:
1.1       rmind     435: /*
1.18      rmind     436:  * npfctl_build_group: create a group, insert into the global ruleset,
                    437:  * update the current group pointer and increase the nesting level.
1.1       rmind     438:  */
                    439: void
1.18      rmind     440: npfctl_build_group(const char *name, int attr, u_int if_idx, bool def)
1.1       rmind     441: {
                    442:        const int attr_di = (NPF_RULE_IN | NPF_RULE_OUT);
                    443:        nl_rule_t *rl;
                    444:
1.18      rmind     445:        if (def || (attr & attr_di) == 0) {
                    446:                attr |= attr_di;
                    447:        }
                    448:
                    449:        rl = npf_rule_create(name, attr | NPF_RULE_GROUP, if_idx);
                    450:        npf_rule_setprio(rl, NPF_PRI_LAST);
                    451:        if (def) {
                    452:                if (defgroup) {
1.1       rmind     453:                        yyerror("multiple default groups are not valid");
                    454:                }
1.18      rmind     455:                if (rule_nesting_level) {
                    456:                        yyerror("default group can only be at the top level");
                    457:                }
                    458:                defgroup = rl;
                    459:        } else {
                    460:                nl_rule_t *cg = current_group[rule_nesting_level];
                    461:                npf_rule_insert(npf_conf, cg, rl);
                    462:        }
1.1       rmind     463:
1.18      rmind     464:        /* Set the current group and increase the nesting level. */
                    465:        if (rule_nesting_level >= MAX_RULE_NESTING) {
                    466:                yyerror("rule nesting limit reached");
1.1       rmind     467:        }
1.18      rmind     468:        current_group[++rule_nesting_level] = rl;
                    469: }
1.1       rmind     470:
1.18      rmind     471: void
                    472: npfctl_build_group_end(void)
                    473: {
                    474:        assert(rule_nesting_level > 0);
                    475:        current_group[rule_nesting_level--] = NULL;
1.1       rmind     476: }
                    477:
                    478: /*
1.26      rmind     479:  * npfctl_build_rule: create a rule, build byte-code from filter options,
1.18      rmind     480:  * if any, and insert into the ruleset of current group, or set the rule.
1.1       rmind     481:  */
                    482: void
1.21      rmind     483: npfctl_build_rule(uint32_t attr, u_int if_idx, sa_family_t family,
1.27    ! rmind     484:     const opt_proto_t *op, const filt_opts_t *fopts,
        !           485:     const char *pcap_filter, const char *rproc)
1.1       rmind     486: {
                    487:        nl_rule_t *rl;
                    488:
1.19      rmind     489:        attr |= (npf_conf ? 0 : NPF_RULE_DYNAMIC);
1.21      rmind     490:
1.1       rmind     491:        rl = npf_rule_create(NULL, attr, if_idx);
1.27    ! rmind     492:        if (pcap_filter) {
        !           493:                npfctl_build_pcap(rl, pcap_filter);
        !           494:        } else {
        !           495:                npfctl_build_code(rl, family, op, fopts);
        !           496:        }
        !           497:
1.18      rmind     498:        if (rproc) {
                    499:                npf_rule_setproc(rl, rproc);
                    500:        }
                    501:
                    502:        if (npf_conf) {
                    503:                nl_rule_t *cg = current_group[rule_nesting_level];
                    504:
                    505:                if (rproc && !npf_rproc_exists_p(npf_conf, rproc)) {
                    506:                        yyerror("rule procedure '%s' is not defined", rproc);
                    507:                }
                    508:                assert(cg != NULL);
                    509:                npf_rule_setprio(rl, NPF_PRI_LAST);
                    510:                npf_rule_insert(npf_conf, cg, rl);
                    511:        } else {
                    512:                /* We have parsed a single rule - set it. */
                    513:                the_rule = rl;
1.1       rmind     514:        }
                    515: }
                    516:
                    517: /*
1.14      rmind     518:  * npfctl_build_nat: create a single NAT policy of a specified
1.13      rmind     519:  * type with a given filter options.
                    520:  */
                    521: static void
                    522: npfctl_build_nat(int type, u_int if_idx, sa_family_t family,
                    523:     const addr_port_t *ap, const filt_opts_t *fopts, bool binat)
                    524: {
                    525:        const opt_proto_t op = { .op_proto = -1, .op_opts = NULL };
                    526:        fam_addr_mask_t *am;
                    527:        in_port_t port;
                    528:        nl_nat_t *nat;
                    529:
                    530:        if (!ap->ap_netaddr) {
                    531:                yyerror("%s network segment is not specified",
                    532:                    type == NPF_NATIN ? "inbound" : "outbound");
                    533:        }
                    534:        am = npfctl_get_singlefam(ap->ap_netaddr);
                    535:        if (am->fam_family != family) {
                    536:                yyerror("IPv6 NAT is not supported");
                    537:        }
                    538:
                    539:        switch (type) {
                    540:        case NPF_NATOUT:
                    541:                /*
                    542:                 * Outbound NAT (or source NAT) policy, usually used for the
                    543:                 * traditional NAPT.  If it is a half for bi-directional NAT,
                    544:                 * then no port translation with mapping.
                    545:                 */
                    546:                nat = npf_nat_create(NPF_NATOUT, !binat ?
                    547:                    (NPF_NAT_PORTS | NPF_NAT_PORTMAP) : 0,
                    548:                    if_idx, &am->fam_addr, am->fam_family, 0);
                    549:                break;
                    550:        case NPF_NATIN:
                    551:                /*
                    552:                 * Inbound NAT (or destination NAT).  Unless bi-NAT, a port
                    553:                 * must be specified, since it has to be redirection.
                    554:                 */
                    555:                port = 0;
                    556:                if (!binat) {
                    557:                        if (!ap->ap_portrange) {
                    558:                                yyerror("inbound port is not specified");
                    559:                        }
                    560:                        port = npfctl_get_singleport(ap->ap_portrange);
                    561:                }
                    562:                nat = npf_nat_create(NPF_NATIN, !binat ? NPF_NAT_PORTS : 0,
                    563:                    if_idx, &am->fam_addr, am->fam_family, port);
                    564:                break;
                    565:        default:
                    566:                assert(false);
                    567:        }
                    568:
1.27    ! rmind     569:        npfctl_build_code(nat, family, &op, fopts);
1.18      rmind     570:        npf_nat_insert(npf_conf, nat, NPF_PRI_LAST);
1.13      rmind     571: }
                    572:
                    573: /*
1.14      rmind     574:  * npfctl_build_natseg: validate and create NAT policies.
1.1       rmind     575:  */
                    576: void
1.13      rmind     577: npfctl_build_natseg(int sd, int type, u_int if_idx, const addr_port_t *ap1,
1.7       rmind     578:     const addr_port_t *ap2, const filt_opts_t *fopts)
1.1       rmind     579: {
1.13      rmind     580:        sa_family_t af = AF_INET;
1.7       rmind     581:        filt_opts_t imfopts;
1.13      rmind     582:        bool binat;
1.1       rmind     583:
1.7       rmind     584:        if (sd == NPFCTL_NAT_STATIC) {
                    585:                yyerror("static NAT is not yet supported");
                    586:        }
                    587:        assert(sd == NPFCTL_NAT_DYNAMIC);
                    588:        assert(if_idx != 0);
                    589:
1.13      rmind     590:        /*
                    591:         * Bi-directional NAT is a combination of inbound NAT and outbound
                    592:         * NAT policies.  Note that the translation address is local IP and
                    593:         * the filter criteria is inverted accordingly.
                    594:         */
                    595:        binat = (NPF_NATIN | NPF_NATOUT) == type;
1.7       rmind     596:
                    597:        /*
1.13      rmind     598:         * If the filter criteria is not specified explicitly, apply implicit
1.14      rmind     599:         * filtering according to the given network segments.
1.13      rmind     600:         *
                    601:         * Note: filled below, depending on the type.
1.7       rmind     602:         */
1.14      rmind     603:        if (__predict_true(!fopts)) {
1.7       rmind     604:                fopts = &imfopts;
1.1       rmind     605:        }
                    606:
1.13      rmind     607:        if (type & NPF_NATIN) {
                    608:                memset(&imfopts, 0, sizeof(filt_opts_t));
                    609:                memcpy(&imfopts.fo_to, ap2, sizeof(addr_port_t));
                    610:                npfctl_build_nat(NPF_NATIN, if_idx, af, ap1, fopts, binat);
                    611:        }
                    612:        if (type & NPF_NATOUT) {
                    613:                memset(&imfopts, 0, sizeof(filt_opts_t));
                    614:                memcpy(&imfopts.fo_from, ap1, sizeof(addr_port_t));
                    615:                npfctl_build_nat(NPF_NATOUT, if_idx, af, ap2, fopts, binat);
1.1       rmind     616:        }
                    617: }
                    618:
                    619: /*
                    620:  * npfctl_fill_table: fill NPF table with entries from a specified file.
                    621:  */
                    622: static void
1.11      rmind     623: npfctl_fill_table(nl_table_t *tl, u_int type, const char *fname)
1.1       rmind     624: {
                    625:        char *buf = NULL;
                    626:        int l = 0;
                    627:        FILE *fp;
                    628:        size_t n;
                    629:
                    630:        fp = fopen(fname, "r");
                    631:        if (fp == NULL) {
                    632:                err(EXIT_FAILURE, "open '%s'", fname);
                    633:        }
                    634:        while (l++, getline(&buf, &n, fp) != -1) {
1.11      rmind     635:                fam_addr_mask_t fam;
                    636:                int alen;
1.1       rmind     637:
                    638:                if (*buf == '\n' || *buf == '#') {
                    639:                        continue;
                    640:                }
1.11      rmind     641:
                    642:                if (!npfctl_parse_cidr(buf, &fam, &alen)) {
                    643:                        errx(EXIT_FAILURE,
                    644:                            "%s:%d: invalid table entry", fname, l);
                    645:                }
                    646:                if (type == NPF_TABLE_HASH && fam.fam_mask != NPF_NO_NETMASK) {
                    647:                        errx(EXIT_FAILURE,
                    648:                            "%s:%d: mask used with the hash table", fname, l);
1.1       rmind     649:                }
                    650:
                    651:                /* Create and add a table entry. */
1.17      rmind     652:                npf_table_add_entry(tl, fam.fam_family,
                    653:                    &fam.fam_addr, fam.fam_mask);
1.1       rmind     654:        }
                    655:        if (buf != NULL) {
                    656:                free(buf);
                    657:        }
                    658: }
                    659:
                    660: /*
                    661:  * npfctl_build_table: create an NPF table, add to the configuration and,
                    662:  * if required, fill with contents from a file.
                    663:  */
                    664: void
                    665: npfctl_build_table(const char *tid, u_int type, const char *fname)
                    666: {
                    667:        nl_table_t *tl;
                    668:        u_int id;
                    669:
                    670:        id = atoi(tid);
                    671:        tl = npf_table_create(id, type);
                    672:        assert(tl != NULL);
                    673:
                    674:        if (npf_table_insert(npf_conf, tl)) {
                    675:                errx(EXIT_FAILURE, "table '%d' is already defined\n", id);
                    676:        }
                    677:
                    678:        if (fname) {
1.11      rmind     679:                npfctl_fill_table(tl, type, fname);
1.1       rmind     680:        }
                    681: }
1.23      christos  682:
                    683: /*
1.25      rmind     684:  * npfctl_build_alg: create an NPF application level gateway and add it
1.23      christos  685:  * to the configuration.
                    686:  */
                    687: void
                    688: npfctl_build_alg(const char *al_name)
                    689: {
                    690:        if (_npf_alg_load(npf_conf, al_name) != 0) {
                    691:                errx(EXIT_FAILURE, "ALG '%s' already loaded", al_name);
                    692:        }
                    693: }
1.27    ! rmind     694:
        !           695: static void
        !           696: npfctl_dump_bpf(struct bpf_program *bf)
        !           697: {
        !           698:        if (npf_debug) {
        !           699:                extern char *yytext;
        !           700:                extern int yylineno;
        !           701:
        !           702:                int rule_line = yylineno - (int)(*yytext == '\n');
        !           703:                printf("\nRULE AT LINE %d\n", rule_line);
        !           704:                bpf_dump(bf, 0);
        !           705:        }
        !           706: }

CVSweb <webmaster@jp.NetBSD.org>