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>