1 /* $NetBSD: npf_build.c,v 1.36 2014/02/13 03:34:40 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2011-2014 The NetBSD Foundation, Inc. 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> 37 __RCSID("$NetBSD: npf_build.c,v 1.36 2014/02/13 03:34:40 rmind Exp $"); 38 39 #include <sys/types.h> 40 #include <sys/mman.h> 41 #include <sys/stat.h> 42 43 #include <stdlib.h> 44 #include <inttypes.h> 45 #include <string.h> 46 #include <ctype.h> 47 #include <unistd.h> 48 #include <errno.h> 49 #include <err.h> 50 51 #include <pcap/pcap.h> 52 #include <cdbw.h> 53 54 #include "npfctl.h" 55 56 #define MAX_RULE_NESTING 16 57 58 static nl_config_t * npf_conf = NULL; 59 static bool npf_debug = false; 60 static nl_rule_t * the_rule = NULL; 61 62 static nl_rule_t * current_group[MAX_RULE_NESTING]; 63 static unsigned rule_nesting_level = 0; 64 static nl_rule_t * defgroup = NULL; 65 66 static void npfctl_dump_bpf(struct bpf_program *); 67 68 void 69 npfctl_config_init(bool debug) 70 { 71 npf_conf = npf_config_create(); 72 if (npf_conf == NULL) { 73 errx(EXIT_FAILURE, "npf_config_create failed"); 74 } 75 npf_debug = debug; 76 memset(current_group, 0, sizeof(current_group)); 77 } 78 79 int 80 npfctl_config_send(int fd, const char *out) 81 { 82 int error; 83 84 if (out) { 85 _npf_config_setsubmit(npf_conf, out); 86 printf("\nSaving to %s\n", out); 87 } 88 if (!defgroup) { 89 errx(EXIT_FAILURE, "default group was not defined"); 90 } 91 npf_rule_insert(npf_conf, NULL, defgroup); 92 error = npf_config_submit(npf_conf, fd); 93 if (error) { 94 nl_error_t ne; 95 _npf_config_error(npf_conf, &ne); 96 npfctl_print_error(&ne); 97 } 98 if (fd) { 99 npf_config_destroy(npf_conf); 100 } 101 return error; 102 } 103 104 nl_config_t * 105 npfctl_config_ref(void) 106 { 107 return npf_conf; 108 } 109 110 nl_rule_t * 111 npfctl_rule_ref(void) 112 { 113 return the_rule; 114 } 115 116 bool 117 npfctl_debug_addif(const char *ifname) 118 { 119 const char tname[] = "npftest"; 120 const size_t tnamelen = sizeof(tname) - 1; 121 122 if (npf_debug) { 123 _npf_debug_addif(npf_conf, ifname); 124 return strncmp(ifname, tname, tnamelen) == 0; 125 } 126 return 0; 127 } 128 129 unsigned 130 npfctl_table_getid(const char *name) 131 { 132 unsigned tid = (unsigned)-1; 133 nl_table_t *tl; 134 135 /* XXX dynamic ruleset */ 136 if (!npf_conf) { 137 return (unsigned)-1; 138 } 139 140 /* XXX: Iterating all as we need to rewind for the next call. */ 141 while ((tl = npf_table_iterate(npf_conf)) != NULL) { 142 const char *tname = npf_table_getname(tl); 143 if (strcmp(tname, name) == 0) { 144 tid = npf_table_getid(tl); 145 } 146 } 147 return tid; 148 } 149 150 static in_port_t 151 npfctl_get_singleport(const npfvar_t *vp) 152 { 153 port_range_t *pr; 154 in_port_t *port; 155 156 if (npfvar_get_count(vp) > 1) { 157 yyerror("multiple ports are not valid"); 158 } 159 pr = npfvar_get_data(vp, NPFVAR_PORT_RANGE, 0); 160 if (pr->pr_start != pr->pr_end) { 161 yyerror("port range is not valid"); 162 } 163 port = &pr->pr_start; 164 return *port; 165 } 166 167 static fam_addr_mask_t * 168 npfctl_get_singlefam(const npfvar_t *vp) 169 { 170 if (npfvar_get_count(vp) > 1) { 171 yyerror("multiple addresses are not valid"); 172 } 173 return npfvar_get_data(vp, NPFVAR_FAM, 0); 174 } 175 176 static bool 177 npfctl_build_fam(npf_bpf_t *ctx, sa_family_t family, 178 fam_addr_mask_t *fam, int opts) 179 { 180 /* 181 * If family is specified, address does not match it and the 182 * address is extracted from the interface, then simply ignore. 183 * Otherwise, address of invalid family was passed manually. 184 */ 185 if (family != AF_UNSPEC && family != fam->fam_family) { 186 if (!fam->fam_ifindex) { 187 yyerror("specified address is not of the required " 188 "family %d", family); 189 } 190 return false; 191 } 192 193 family = fam->fam_family; 194 if (family != AF_INET && family != AF_INET6) { 195 yyerror("family %d is not supported", family); 196 } 197 198 /* 199 * Optimise 0.0.0.0/0 case to be NOP. Otherwise, address with 200 * zero mask would never match and therefore is not valid. 201 */ 202 if (fam->fam_mask == 0) { 203 static const npf_addr_t zero; /* must be static */ 204 205 if (memcmp(&fam->fam_addr, &zero, sizeof(npf_addr_t))) { 206 yyerror("filter criterion would never match"); 207 } 208 return false; 209 } 210 211 npfctl_bpf_cidr(ctx, opts, family, &fam->fam_addr, fam->fam_mask); 212 return true; 213 } 214 215 static void 216 npfctl_build_vars(npf_bpf_t *ctx, sa_family_t family, npfvar_t *vars, int opts) 217 { 218 const int type = npfvar_get_type(vars, 0); 219 size_t i; 220 221 npfctl_bpf_group(ctx); 222 for (i = 0; i < npfvar_get_count(vars); i++) { 223 void *data = npfvar_get_data(vars, type, i); 224 assert(data != NULL); 225 226 switch (type) { 227 case NPFVAR_FAM: { 228 fam_addr_mask_t *fam = data; 229 npfctl_build_fam(ctx, family, fam, opts); 230 break; 231 } 232 case NPFVAR_PORT_RANGE: { 233 port_range_t *pr = data; 234 npfctl_bpf_ports(ctx, opts, pr->pr_start, pr->pr_end); 235 break; 236 } 237 case NPFVAR_TABLE: { 238 u_int tid; 239 memcpy(&tid, data, sizeof(u_int)); 240 npfctl_bpf_table(ctx, opts, tid); 241 break; 242 } 243 default: 244 assert(false); 245 } 246 } 247 npfctl_bpf_endgroup(ctx); 248 } 249 250 static void 251 npfctl_build_proto(npf_bpf_t *ctx, sa_family_t family, const opt_proto_t *op) 252 { 253 const npfvar_t *popts = op->op_opts; 254 const int proto = op->op_proto; 255 256 /* IP version and/or L4 protocol matching. */ 257 if (family != AF_UNSPEC || proto != -1) { 258 npfctl_bpf_proto(ctx, family, proto); 259 } 260 261 switch (proto) { 262 case IPPROTO_TCP: 263 /* Build TCP flags matching (optional). */ 264 if (popts) { 265 uint8_t *tf, *tf_mask; 266 267 assert(npfvar_get_count(popts) == 2); 268 tf = npfvar_get_data(popts, NPFVAR_TCPFLAG, 0); 269 tf_mask = npfvar_get_data(popts, NPFVAR_TCPFLAG, 1); 270 npfctl_bpf_tcpfl(ctx, *tf, *tf_mask); 271 } 272 break; 273 case IPPROTO_ICMP: 274 case IPPROTO_ICMPV6: 275 /* Build ICMP/ICMPv6 type and/or code matching. */ 276 if (popts) { 277 int *icmp_type, *icmp_code; 278 279 assert(npfvar_get_count(popts) == 2); 280 icmp_type = npfvar_get_data(popts, NPFVAR_ICMP, 0); 281 icmp_code = npfvar_get_data(popts, NPFVAR_ICMP, 1); 282 npfctl_bpf_icmp(ctx, *icmp_type, *icmp_code); 283 } 284 break; 285 default: 286 /* No options for other protocols. */ 287 break; 288 } 289 } 290 291 static bool 292 npfctl_build_code(nl_rule_t *rl, sa_family_t family, const opt_proto_t *op, 293 const filt_opts_t *fopts) 294 { 295 const addr_port_t *apfrom = &fopts->fo_from; 296 const addr_port_t *apto = &fopts->fo_to; 297 const int proto = op->op_proto; 298 bool noproto, noaddrs, noports; 299 npf_bpf_t *bc; 300 size_t len; 301 302 /* If none specified, then no byte-code. */ 303 noproto = family == AF_UNSPEC && proto == -1 && !op->op_opts; 304 noaddrs = !apfrom->ap_netaddr && !apto->ap_netaddr; 305 noports = !apfrom->ap_portrange && !apto->ap_portrange; 306 if (noproto && noaddrs && noports) { 307 return false; 308 } 309 310 /* 311 * Sanity check: ports can only be used with TCP or UDP protocol. 312 * No filter options are supported for other protocols, only the 313 * IP addresses are allowed. 314 */ 315 if (!noports) { 316 switch (proto) { 317 case IPPROTO_TCP: 318 case IPPROTO_UDP: 319 case -1: 320 break; 321 default: 322 yyerror("invalid filter options for protocol %d", proto); 323 } 324 } 325 326 bc = npfctl_bpf_create(); 327 328 /* Build layer 4 protocol blocks. */ 329 npfctl_build_proto(bc, family, op); 330 331 /* Build IP address blocks. */ 332 npfctl_build_vars(bc, family, apfrom->ap_netaddr, MATCH_SRC); 333 npfctl_build_vars(bc, family, apto->ap_netaddr, MATCH_DST); 334 335 /* Build port-range blocks. */ 336 npfctl_build_vars(bc, family, apfrom->ap_portrange, MATCH_SRC); 337 npfctl_build_vars(bc, family, apto->ap_portrange, MATCH_DST); 338 339 /* Set the byte-code marks, if any. */ 340 const void *bmarks = npfctl_bpf_bmarks(bc, &len); 341 if (npf_rule_setinfo(rl, bmarks, len) == -1) { 342 errx(EXIT_FAILURE, "npf_rule_setinfo failed"); 343 } 344 345 /* Complete BPF byte-code and pass to the rule. */ 346 struct bpf_program *bf = npfctl_bpf_complete(bc); 347 len = bf->bf_len * sizeof(struct bpf_insn); 348 349 if (npf_rule_setcode(rl, NPF_CODE_BPF, bf->bf_insns, len) == -1) { 350 errx(EXIT_FAILURE, "npf_rule_setcode failed"); 351 } 352 npfctl_dump_bpf(bf); 353 npfctl_bpf_destroy(bc); 354 355 return true; 356 } 357 358 static void 359 npfctl_build_pcap(nl_rule_t *rl, const char *filter) 360 { 361 const size_t maxsnaplen = 64 * 1024; 362 struct bpf_program bf; 363 size_t len; 364 365 if (pcap_compile_nopcap(maxsnaplen, DLT_RAW, &bf, 366 filter, 1, PCAP_NETMASK_UNKNOWN) == -1) { 367 yyerror("invalid pcap-filter(7) syntax"); 368 } 369 len = bf.bf_len * sizeof(struct bpf_insn); 370 371 if (npf_rule_setcode(rl, NPF_CODE_BPF, bf.bf_insns, len) == -1) { 372 errx(EXIT_FAILURE, "npf_rule_setcode failed"); 373 } 374 npfctl_dump_bpf(&bf); 375 pcap_freecode(&bf); 376 } 377 378 static void 379 npfctl_build_rpcall(nl_rproc_t *rp, const char *name, npfvar_t *args) 380 { 381 npf_extmod_t *extmod; 382 nl_ext_t *extcall; 383 int error; 384 385 extmod = npf_extmod_get(name, &extcall); 386 if (extmod == NULL) { 387 yyerror("unknown rule procedure '%s'", name); 388 } 389 390 for (size_t i = 0; i < npfvar_get_count(args); i++) { 391 const char *param, *value; 392 proc_param_t *p; 393 394 p = npfvar_get_data(args, NPFVAR_PROC_PARAM, i); 395 param = p->pp_param; 396 value = p->pp_value; 397 398 error = npf_extmod_param(extmod, extcall, param, value); 399 switch (error) { 400 case EINVAL: 401 yyerror("invalid parameter '%s'", param); 402 default: 403 break; 404 } 405 } 406 error = npf_rproc_extcall(rp, extcall); 407 if (error) { 408 yyerror(error == EEXIST ? 409 "duplicate procedure call" : "unexpected error"); 410 } 411 } 412 413 /* 414 * npfctl_build_rproc: create and insert a rule procedure. 415 */ 416 void 417 npfctl_build_rproc(const char *name, npfvar_t *procs) 418 { 419 nl_rproc_t *rp; 420 size_t i; 421 422 rp = npf_rproc_create(name); 423 if (rp == NULL) { 424 errx(EXIT_FAILURE, "%s failed", __func__); 425 } 426 npf_rproc_insert(npf_conf, rp); 427 428 for (i = 0; i < npfvar_get_count(procs); i++) { 429 proc_call_t *pc = npfvar_get_data(procs, NPFVAR_PROC, i); 430 npfctl_build_rpcall(rp, pc->pc_name, pc->pc_opts); 431 } 432 } 433 434 void 435 npfctl_build_maprset(const char *name, int attr, const char *ifname) 436 { 437 const int attr_di = (NPF_RULE_IN | NPF_RULE_OUT); 438 nl_rule_t *rl; 439 440 /* If no direction is not specified, then both. */ 441 if ((attr & attr_di) == 0) { 442 attr |= attr_di; 443 } 444 /* Allow only "in/out" attributes. */ 445 attr = NPF_RULE_GROUP | NPF_RULE_GROUP | (attr & attr_di); 446 rl = npf_rule_create(name, attr, ifname); 447 npf_nat_insert(npf_conf, rl, NPF_PRI_LAST); 448 } 449 450 /* 451 * npfctl_build_group: create a group, insert into the global ruleset, 452 * update the current group pointer and increase the nesting level. 453 */ 454 void 455 npfctl_build_group(const char *name, int attr, const char *ifname, bool def) 456 { 457 const int attr_di = (NPF_RULE_IN | NPF_RULE_OUT); 458 nl_rule_t *rl; 459 460 if (def || (attr & attr_di) == 0) { 461 attr |= attr_di; 462 } 463 464 rl = npf_rule_create(name, attr | NPF_RULE_GROUP, ifname); 465 npf_rule_setprio(rl, NPF_PRI_LAST); 466 if (def) { 467 if (defgroup) { 468 yyerror("multiple default groups are not valid"); 469 } 470 if (rule_nesting_level) { 471 yyerror("default group can only be at the top level"); 472 } 473 defgroup = rl; 474 } else { 475 nl_rule_t *cg = current_group[rule_nesting_level]; 476 npf_rule_insert(npf_conf, cg, rl); 477 } 478 479 /* Set the current group and increase the nesting level. */ 480 if (rule_nesting_level >= MAX_RULE_NESTING) { 481 yyerror("rule nesting limit reached"); 482 } 483 current_group[++rule_nesting_level] = rl; 484 } 485 486 void 487 npfctl_build_group_end(void) 488 { 489 assert(rule_nesting_level > 0); 490 current_group[rule_nesting_level--] = NULL; 491 } 492 493 /* 494 * npfctl_build_rule: create a rule, build byte-code from filter options, 495 * if any, and insert into the ruleset of current group, or set the rule. 496 */ 497 void 498 npfctl_build_rule(uint32_t attr, const char *ifname, sa_family_t family, 499 const opt_proto_t *op, const filt_opts_t *fopts, 500 const char *pcap_filter, const char *rproc) 501 { 502 nl_rule_t *rl; 503 504 attr |= (npf_conf ? 0 : NPF_RULE_DYNAMIC); 505 506 rl = npf_rule_create(NULL, attr, ifname); 507 if (pcap_filter) { 508 npfctl_build_pcap(rl, pcap_filter); 509 } else { 510 npfctl_build_code(rl, family, op, fopts); 511 } 512 513 if (rproc) { 514 npf_rule_setproc(rl, rproc); 515 } 516 517 if (npf_conf) { 518 nl_rule_t *cg = current_group[rule_nesting_level]; 519 520 if (rproc && !npf_rproc_exists_p(npf_conf, rproc)) { 521 yyerror("rule procedure '%s' is not defined", rproc); 522 } 523 assert(cg != NULL); 524 npf_rule_setprio(rl, NPF_PRI_LAST); 525 npf_rule_insert(npf_conf, cg, rl); 526 } else { 527 /* We have parsed a single rule - set it. */ 528 the_rule = rl; 529 } 530 } 531 532 /* 533 * npfctl_build_nat: create a single NAT policy of a specified 534 * type with a given filter options. 535 */ 536 static nl_nat_t * 537 npfctl_build_nat(int type, const char *ifname, const addr_port_t *ap, 538 const filt_opts_t *fopts, u_int flags) 539 { 540 const opt_proto_t op = { .op_proto = -1, .op_opts = NULL }; 541 fam_addr_mask_t *am = npfctl_get_singlefam(ap->ap_netaddr); 542 in_port_t port; 543 nl_nat_t *nat; 544 545 if (ap->ap_portrange) { 546 port = npfctl_get_singleport(ap->ap_portrange); 547 flags &= ~NPF_NAT_PORTMAP; 548 flags |= NPF_NAT_PORTS; 549 } else { 550 port = 0; 551 } 552 553 nat = npf_nat_create(type, flags, ifname, am->fam_family, 554 &am->fam_addr, am->fam_mask, port); 555 npfctl_build_code(nat, am->fam_family, &op, fopts); 556 npf_nat_insert(npf_conf, nat, NPF_PRI_LAST); 557 return nat; 558 } 559 560 /* 561 * npfctl_build_natseg: validate and create NAT policies. 562 */ 563 void 564 npfctl_build_natseg(int sd, int type, const char *ifname, 565 const addr_port_t *ap1, const addr_port_t *ap2, 566 const filt_opts_t *fopts, u_int algo) 567 { 568 fam_addr_mask_t *am1 = NULL, *am2 = NULL; 569 nl_nat_t *nt1 = NULL, *nt2 = NULL; 570 filt_opts_t imfopts; 571 uint16_t adj = 0; 572 u_int flags; 573 bool binat; 574 575 assert(ifname != NULL); 576 577 /* 578 * Bi-directional NAT is a combination of inbound NAT and outbound 579 * NAT policies with the translation segments inverted respectively. 580 */ 581 binat = (NPF_NATIN | NPF_NATOUT) == type; 582 583 switch (sd) { 584 case NPFCTL_NAT_DYNAMIC: 585 /* 586 * Dynamic NAT: traditional NAPT is expected. Unless it 587 * is bi-directional NAT, perform port mapping. 588 */ 589 flags = !binat ? (NPF_NAT_PORTS | NPF_NAT_PORTMAP) : 0; 590 break; 591 case NPFCTL_NAT_STATIC: 592 /* Static NAT: mechanic translation. */ 593 flags = NPF_NAT_STATIC; 594 break; 595 default: 596 abort(); 597 } 598 599 /* 600 * Validate the mappings and their configuration. 601 */ 602 603 if ((type & NPF_NATIN) != 0) { 604 if (!ap1->ap_netaddr) 605 yyerror("inbound network segment is not specified"); 606 am1 = npfctl_get_singlefam(ap1->ap_netaddr); 607 } 608 if ((type & NPF_NATOUT) != 0) { 609 if (!ap2->ap_netaddr) 610 yyerror("outbound network segment is not specified"); 611 am2 = npfctl_get_singlefam(ap2->ap_netaddr); 612 } 613 614 switch (algo) { 615 case NPF_ALGO_NPT66: 616 if (am1 == NULL || am2 == NULL) 617 yyerror("1:1 mapping of two segments must be " 618 "used for NPTv6"); 619 if (am1->fam_mask != am2->fam_mask) 620 yyerror("asymmetric translation is not supported"); 621 adj = npfctl_npt66_calcadj(am1->fam_mask, 622 &am1->fam_addr, &am2->fam_addr); 623 break; 624 default: 625 if ((am1 && am1->fam_mask != NPF_NO_NETMASK) || 626 (am2 && am2->fam_mask != NPF_NO_NETMASK)) 627 yyerror("net-to-net translation is not supported"); 628 break; 629 } 630 631 /* 632 * If the filter criteria is not specified explicitly, apply implicit 633 * filtering according to the given network segments. 634 * 635 * Note: filled below, depending on the type. 636 */ 637 if (__predict_true(!fopts)) { 638 fopts = &imfopts; 639 } 640 641 if (type & NPF_NATIN) { 642 memset(&imfopts, 0, sizeof(filt_opts_t)); 643 memcpy(&imfopts.fo_to, ap2, sizeof(addr_port_t)); 644 nt1 = npfctl_build_nat(NPF_NATIN, ifname, ap1, fopts, flags); 645 } 646 if (type & NPF_NATOUT) { 647 memset(&imfopts, 0, sizeof(filt_opts_t)); 648 memcpy(&imfopts.fo_from, ap1, sizeof(addr_port_t)); 649 nt2 = npfctl_build_nat(NPF_NATOUT, ifname, ap2, fopts, flags); 650 } 651 652 if (algo == NPF_ALGO_NPT66) { 653 npf_nat_setnpt66(nt1, ~adj); 654 npf_nat_setnpt66(nt2, adj); 655 } 656 } 657 658 /* 659 * npfctl_fill_table: fill NPF table with entries from a specified file. 660 */ 661 static void 662 npfctl_fill_table(nl_table_t *tl, u_int type, const char *fname) 663 { 664 struct cdbw *cdbw = NULL; /* XXX: gcc */ 665 char *buf = NULL; 666 int l = 0; 667 FILE *fp; 668 size_t n; 669 670 if (type == NPF_TABLE_CDB && (cdbw = cdbw_open()) == NULL) { 671 err(EXIT_FAILURE, "cdbw_open"); 672 } 673 fp = fopen(fname, "r"); 674 if (fp == NULL) { 675 err(EXIT_FAILURE, "open '%s'", fname); 676 } 677 while (l++, getline(&buf, &n, fp) != -1) { 678 fam_addr_mask_t fam; 679 int alen; 680 681 if (*buf == '\n' || *buf == '#') { 682 continue; 683 } 684 685 if (!npfctl_parse_cidr(buf, &fam, &alen)) { 686 errx(EXIT_FAILURE, 687 "%s:%d: invalid table entry", fname, l); 688 } 689 if (type != NPF_TABLE_TREE && fam.fam_mask != NPF_NO_NETMASK) { 690 errx(EXIT_FAILURE, "%s:%d: mask used with the " 691 "non-tree table", fname, l); 692 } 693 694 /* 695 * Create and add a table entry. 696 */ 697 if (type == NPF_TABLE_CDB) { 698 const npf_addr_t *addr = &fam.fam_addr; 699 if (cdbw_put(cdbw, addr, alen, addr, alen) == -1) { 700 err(EXIT_FAILURE, "cdbw_put"); 701 } 702 } else { 703 npf_table_add_entry(tl, fam.fam_family, 704 &fam.fam_addr, fam.fam_mask); 705 } 706 } 707 if (buf != NULL) { 708 free(buf); 709 } 710 711 if (type == NPF_TABLE_CDB) { 712 struct stat sb; 713 char sfn[32]; 714 void *cdb; 715 int fd; 716 717 strlcpy(sfn, "/tmp/npfcdb.XXXXXX", sizeof(sfn)); 718 if ((fd = mkstemp(sfn)) == -1) { 719 err(EXIT_FAILURE, "mkstemp"); 720 } 721 unlink(sfn); 722 723 if (cdbw_output(cdbw, fd, "npf-table-cdb", NULL) == -1) { 724 err(EXIT_FAILURE, "cdbw_output"); 725 } 726 cdbw_close(cdbw); 727 728 if (fstat(fd, &sb) == -1) { 729 err(EXIT_FAILURE, "fstat"); 730 } 731 if ((cdb = mmap(NULL, sb.st_size, PROT_READ, 732 MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) { 733 err(EXIT_FAILURE, "mmap"); 734 } 735 npf_table_setdata(tl, cdb, sb.st_size); 736 737 close(fd); 738 } 739 } 740 741 /* 742 * npfctl_build_table: create an NPF table, add to the configuration and, 743 * if required, fill with contents from a file. 744 */ 745 void 746 npfctl_build_table(const char *tname, u_int type, const char *fname) 747 { 748 static unsigned tid = 0; 749 nl_table_t *tl; 750 751 tl = npf_table_create(tname, tid++, type); 752 assert(tl != NULL); 753 754 if (npf_table_insert(npf_conf, tl)) { 755 yyerror("table '%s' is already defined", tname); 756 } 757 758 if (fname) { 759 npfctl_fill_table(tl, type, fname); 760 } else if (type == NPF_TABLE_CDB) { 761 errx(EXIT_FAILURE, "tables of cdb type must be static"); 762 } 763 } 764 765 /* 766 * npfctl_build_alg: create an NPF application level gateway and add it 767 * to the configuration. 768 */ 769 void 770 npfctl_build_alg(const char *al_name) 771 { 772 if (_npf_alg_load(npf_conf, al_name) != 0) { 773 errx(EXIT_FAILURE, "ALG '%s' already loaded", al_name); 774 } 775 } 776 777 static void 778 npfctl_dump_bpf(struct bpf_program *bf) 779 { 780 if (npf_debug) { 781 extern char *yytext; 782 extern int yylineno; 783 784 int rule_line = yylineno - (int)(*yytext == '\n'); 785 printf("\nRULE AT LINE %d\n", rule_line); 786 bpf_dump(bf, 0); 787 } 788 } 789