1 /*- 2 * Copyright (c) 2013-2020 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Mindaugas Rasiukevicius. 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 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * NPF configuration printing. 32 * 33 * Each rule having BPF byte-code has a binary description. 34 */ 35 36 #include <sys/cdefs.h> 37 __RCSID("$NetBSD: npf_show.c,v 1.34 2025/01/27 07:54:30 mlelstv Exp $"); 38 39 #include <sys/socket.h> 40 #define __FAVOR_BSD 41 #include <netinet/in.h> 42 #include <netinet/tcp.h> 43 #include <net/if.h> 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <stdbool.h> 49 #include <inttypes.h> 50 #include <errno.h> 51 #include <err.h> 52 53 #include "npfctl.h" 54 55 #define SEEN_PROTO 0x01 56 57 typedef struct { 58 char ** values; 59 unsigned count; 60 } elem_list_t; 61 62 enum { 63 LIST_PROTO = 0, LIST_SADDR, LIST_DADDR, LIST_SPORT, LIST_DPORT, 64 LIST_COUNT, 65 }; 66 67 typedef struct { 68 nl_config_t * conf; 69 bool validating; 70 71 FILE * fp; 72 long fpos; 73 long fposln; 74 int glevel; 75 76 unsigned flags; 77 uint32_t curmark; 78 uint64_t seen_marks; 79 elem_list_t list[LIST_COUNT]; 80 81 } npf_conf_info_t; 82 83 static void print_linesep(npf_conf_info_t *); 84 85 static npf_conf_info_t * 86 npfctl_show_init(void) 87 { 88 static npf_conf_info_t stdout_ctx; 89 memset(&stdout_ctx, 0, sizeof(npf_conf_info_t)); 90 stdout_ctx.glevel = -1; 91 stdout_ctx.fp = stdout; 92 return &stdout_ctx; 93 } 94 95 static void 96 list_push(elem_list_t *list, char *val) 97 { 98 const unsigned n = list->count; 99 char **values; 100 101 if ((values = calloc(n + 1, sizeof(char *))) == NULL) { 102 err(EXIT_FAILURE, "calloc"); 103 } 104 for (unsigned i = 0; i < n; i++) { 105 values[i] = list->values[i]; 106 } 107 values[n] = val; 108 free(list->values); 109 list->values = values; 110 list->count++; 111 } 112 113 static char * 114 list_join_free(elem_list_t *list, const bool use_br, const char *sep) 115 { 116 char *s, buf[2048]; 117 118 if (!join(buf, sizeof(buf), list->count, list->values, sep)) { 119 errx(EXIT_FAILURE, "out of memory while parsing the rule"); 120 } 121 easprintf(&s, (use_br && list->count > 1) ? "{ %s }" : "%s", buf); 122 for (unsigned i = 0; i < list->count; i++) { 123 free(list->values[i]); 124 } 125 free(list->values); 126 list->values = NULL; 127 list->count = 0; 128 return s; 129 } 130 131 /* 132 * Helper routines to print various pieces of information. 133 */ 134 135 static void 136 print_indent(npf_conf_info_t *ctx, unsigned level) 137 { 138 if (ctx->glevel >= 0 && level <= (unsigned)ctx->glevel) { 139 /* 140 * Level decrease -- end of the group. 141 * Print the group closing curly bracket. 142 */ 143 ctx->fpos += fprintf(ctx->fp, "}\n\n"); 144 ctx->glevel = -1; 145 } 146 while (level--) { 147 ctx->fpos += fprintf(ctx->fp, "\t"); 148 } 149 } 150 151 static void 152 print_linesep(npf_conf_info_t *ctx) 153 { 154 if (ctx->fpos != ctx->fposln) { 155 ctx->fpos += fprintf(ctx->fp, "\n"); 156 ctx->fposln = ctx->fpos; 157 } 158 } 159 160 static size_t 161 tcpflags2string(char *buf, unsigned tfl) 162 { 163 unsigned i = 0; 164 165 if (tfl & TH_FIN) buf[i++] = 'F'; 166 if (tfl & TH_SYN) buf[i++] = 'S'; 167 if (tfl & TH_RST) buf[i++] = 'R'; 168 if (tfl & TH_PUSH) buf[i++] = 'P'; 169 if (tfl & TH_ACK) buf[i++] = 'A'; 170 if (tfl & TH_URG) buf[i++] = 'U'; 171 if (tfl & TH_ECE) buf[i++] = 'E'; 172 if (tfl & TH_CWR) buf[i++] = 'W'; 173 buf[i] = '\0'; 174 return i; 175 } 176 177 static char * 178 print_family(npf_conf_info_t *ctx __unused, const uint32_t *words) 179 { 180 const int af = words[0]; 181 182 switch (af) { 183 case AF_INET: 184 return estrdup("inet4"); 185 case AF_INET6: 186 return estrdup("inet6"); 187 default: 188 errx(EXIT_FAILURE, "invalid byte-code mark (family)"); 189 } 190 return NULL; 191 } 192 193 static char * 194 print_address(npf_conf_info_t *ctx __unused, const uint32_t *words) 195 { 196 const int af = *words++; 197 const unsigned mask = *words++; 198 const npf_addr_t *addr; 199 int alen = 0; 200 201 switch (af) { 202 case AF_INET: 203 alen = 4; 204 break; 205 case AF_INET6: 206 alen = 16; 207 break; 208 default: 209 errx(EXIT_FAILURE, "invalid byte-code mark (address)"); 210 } 211 addr = (const npf_addr_t *)words; 212 return npfctl_print_addrmask(alen, "%a", addr, mask); 213 } 214 215 static char * 216 print_number(npf_conf_info_t *ctx __unused, const uint32_t *words) 217 { 218 char *p; 219 easprintf(&p, "%u", words[0]); 220 return p; 221 } 222 223 static char * 224 print_table(npf_conf_info_t *ctx, const uint32_t *words) 225 { 226 const unsigned tid = words[0]; 227 const char *tname; 228 char *s = NULL; 229 bool ifaddr; 230 231 tname = npfctl_table_getname(ctx->conf, tid, &ifaddr); 232 easprintf(&s, ifaddr ? "ifaddrs(%s)" : "<%s>", tname); 233 return s; 234 } 235 236 static char * 237 print_proto(npf_conf_info_t *ctx, const uint32_t *words) 238 { 239 ctx->flags |= SEEN_PROTO; 240 switch (words[0]) { 241 case IPPROTO_TCP: 242 return estrdup("tcp"); 243 case IPPROTO_UDP: 244 return estrdup("udp"); 245 case IPPROTO_ICMP: 246 return estrdup("icmp"); 247 case IPPROTO_ICMPV6: 248 return estrdup("ipv6-icmp"); 249 } 250 return print_number(ctx, words); 251 } 252 253 static char * 254 print_tcpflags(npf_conf_info_t *ctx __unused, const uint32_t *words) 255 { 256 const unsigned tf = words[0], tf_mask = words[1]; 257 char buf[32]; 258 size_t n; 259 260 if ((ctx->flags & SEEN_PROTO) == 0) { 261 /* 262 * Note: the TCP flag matching might be without 'proto tcp' 263 * when using a plain 'stateful' rule. In such case, just 264 * skip showing of the flags as they are implicit. 265 */ 266 return NULL; 267 } 268 n = tcpflags2string(buf, tf); 269 if (tf != tf_mask) { 270 buf[n++] = '/'; 271 tcpflags2string(buf + n, tf_mask); 272 } 273 return estrdup(buf); 274 } 275 276 static char * 277 print_portrange(npf_conf_info_t *ctx __unused, const uint32_t *words) 278 { 279 unsigned fport = words[0], tport = words[1]; 280 char *p; 281 282 if (fport != tport) { 283 easprintf(&p, "%u-%u", fport, tport); 284 } else { 285 easprintf(&p, "%u", fport); 286 } 287 return p; 288 } 289 290 /* 291 * The main keyword mapping tables defining the syntax: 292 * - Mapping of rule attributes (flags) to the keywords. 293 * - Mapping of the byte-code marks to the keywords. 294 */ 295 296 #define F(name) __CONCAT(NPF_RULE_, name) 297 #define STATEFUL_ALL (NPF_RULE_STATEFUL | NPF_RULE_GSTATEFUL) 298 #define NAME_AT 2 299 300 static const struct attr_keyword_mapent { 301 uint32_t mask; 302 uint32_t flags; 303 const char * val; 304 } attr_keyword_map[] = { 305 { F(GROUP)|F(DYNAMIC), F(GROUP), "group" }, 306 { F(GROUP)|F(DYNAMIC), F(GROUP)|F(DYNAMIC), "ruleset" }, 307 { F(GROUP)|F(PASS), 0, "block" }, 308 { F(GROUP)|F(PASS), F(PASS), "pass" }, 309 { F(RETRST)|F(RETICMP), F(RETRST)|F(RETICMP), "return" }, 310 { F(RETRST)|F(RETICMP), F(RETRST), "return-rst" }, 311 { F(RETRST)|F(RETICMP), F(RETICMP), "return-icmp" }, 312 { STATEFUL_ALL, F(STATEFUL), "stateful" }, 313 { STATEFUL_ALL, STATEFUL_ALL, "stateful-all" }, 314 { F(DIMASK), F(IN), "in" }, 315 { F(DIMASK), F(OUT), "out" }, 316 { F(FINAL), F(FINAL), "final" }, 317 }; 318 319 static const struct mark_keyword_mapent { 320 unsigned mark; 321 const char * format; 322 int list_id; 323 char * (*printfn)(npf_conf_info_t *, const uint32_t *); 324 unsigned fwords; 325 } mark_keyword_map[] = { 326 { BM_IPVER, "family %s", LIST_PROTO, print_family, 1 }, 327 { BM_PROTO, "proto %s", LIST_PROTO, print_proto, 1 }, 328 { BM_TCPFL, "flags %s", LIST_PROTO, print_tcpflags, 2 }, 329 { BM_ICMP_TYPE, "icmp-type %s", LIST_PROTO, print_number, 1 }, 330 { BM_ICMP_CODE, "code %s", LIST_PROTO, print_number, 1 }, 331 332 { BM_SRC_NEG, NULL, -1, NULL, 0 }, 333 { BM_SRC_CIDR, NULL, LIST_SADDR, print_address, 6 }, 334 { BM_SRC_TABLE, NULL, LIST_SADDR, print_table, 1 }, 335 { BM_SRC_PORTS, NULL, LIST_SPORT, print_portrange,2 }, 336 337 { BM_DST_NEG, NULL, -1, NULL, 0 }, 338 { BM_DST_CIDR, NULL, LIST_DADDR, print_address, 6 }, 339 { BM_DST_TABLE, NULL, LIST_DADDR, print_table, 1 }, 340 { BM_DST_PORTS, NULL, LIST_DPORT, print_portrange,2 }, 341 }; 342 343 static const char * __attribute__((format_arg(2))) 344 verified_fmt(const char *fmt, const char *t __unused) 345 { 346 return fmt; 347 } 348 349 static void 350 scan_marks(npf_conf_info_t *ctx, const struct mark_keyword_mapent *mk, 351 const uint32_t *marks, size_t mlen) 352 { 353 elem_list_t sublist, *target_list; 354 355 /* 356 * If format is used for this mark, then collect multiple elements 357 * in into the list, merge and re-push the set into the target list. 358 * 359 * Currently, this is applicable only for 'proto { tcp, udp }'. 360 */ 361 memset(&sublist, 0, sizeof(elem_list_t)); 362 target_list = mk->format ? &sublist : &ctx->list[mk->list_id]; 363 364 /* Scan for the marks and extract the values. */ 365 mlen /= sizeof(uint32_t); 366 while (mlen > 2) { 367 const uint32_t m = *marks++; 368 const unsigned nwords = *marks++; 369 370 if ((mlen -= 2) < nwords) { 371 errx(EXIT_FAILURE, "byte-code marking inconsistency"); 372 } 373 if (m == mk->mark) { 374 /* 375 * Set the current mark and note it as seen. 376 * Value is processed by the print function, 377 * otherwise we just need to note the mark. 378 */ 379 ctx->curmark = m; 380 assert(BM_COUNT < (sizeof(uint64_t) * CHAR_BIT)); 381 ctx->seen_marks |= UINT64_C(1) << m; 382 assert(mk->fwords == nwords); 383 384 if (mk->printfn) { 385 char *val; 386 387 if ((val = mk->printfn(ctx, marks)) != NULL) { 388 list_push(target_list, val); 389 } 390 } 391 } 392 marks += nwords; 393 mlen -= nwords; 394 } 395 396 if (sublist.count) { 397 char *val, *elements; 398 399 elements = list_join_free(&sublist, true, ", "); 400 easprintf(&val, verified_fmt(mk->format, "%s"), elements ); 401 list_push(&ctx->list[mk->list_id], val); 402 free(elements); 403 } 404 } 405 406 static void 407 npfctl_print_id(npf_conf_info_t *ctx, nl_rule_t *rl) 408 { 409 const uint64_t id = npf_rule_getid(rl); 410 411 if (id) { 412 ctx->fpos += fprintf(ctx->fp, "# id=\"%" PRIx64 "\" ", id); 413 } 414 } 415 416 static void 417 npfctl_print_filter_generic(npf_conf_info_t *ctx) 418 { 419 elem_list_t *list = &ctx->list[LIST_PROTO]; 420 421 if (list->count) { 422 char *elements = list_join_free(list, false, " "); 423 ctx->fpos += fprintf(ctx->fp, "%s ", elements); 424 free(elements); 425 } 426 } 427 428 static bool 429 npfctl_print_filter_seg(npf_conf_info_t *ctx, unsigned which) 430 { 431 static const struct { 432 const char * keyword; 433 unsigned alist; 434 unsigned plist; 435 unsigned negbm; 436 } refs[] = { 437 [NPF_SRC] = { 438 .keyword = "from", 439 .alist = LIST_SADDR, 440 .plist = LIST_SPORT, 441 .negbm = UINT64_C(1) << BM_SRC_NEG, 442 }, 443 [NPF_DST] = { 444 .keyword = "to", 445 .alist = LIST_DADDR, 446 .plist = LIST_DPORT, 447 .negbm = UINT64_C(1) << BM_DST_NEG, 448 } 449 }; 450 const char *neg = !!(ctx->seen_marks & refs[which].negbm) ? "! " : ""; 451 const char *kwd = refs[which].keyword; 452 bool seen_filter = false; 453 elem_list_t *list; 454 char *elements; 455 456 list = &ctx->list[refs[which].alist]; 457 if (list->count != 0) { 458 seen_filter = true; 459 elements = list_join_free(list, true, ", "); 460 ctx->fpos += fprintf(ctx->fp, "%s %s%s ", kwd, neg, elements); 461 free(elements); 462 } 463 464 list = &ctx->list[refs[which].plist]; 465 if (list->count != 0) { 466 if (!seen_filter) { 467 ctx->fpos += fprintf(ctx->fp, "%s any ", kwd); 468 seen_filter = true; 469 } 470 elements = list_join_free(list, true, ", "); 471 ctx->fpos += fprintf(ctx->fp, "port %s ", elements); 472 free(elements); 473 } 474 return seen_filter; 475 } 476 477 static bool 478 npfctl_print_filter(npf_conf_info_t *ctx, nl_rule_t *rl) 479 { 480 const void *marks; 481 size_t mlen, len; 482 const void *code; 483 bool seenf = false; 484 int type; 485 486 marks = npf_rule_getinfo(rl, &mlen); 487 if (!marks && (code = npf_rule_getcode(rl, &type, &len)) != NULL) { 488 /* 489 * No marks, but the byte-code is present. This must 490 * have been filled by libpcap(3) or possibly an unknown 491 * to us byte-code. 492 */ 493 ctx->fpos += fprintf(ctx->fp, "%s ", type == NPF_CODE_BPF ? 494 "pcap-filter \"...\"" : "unrecognized-bytecode"); 495 return true; 496 } 497 ctx->flags = 0; 498 499 /* 500 * BPF filter criteria described by the byte-code marks. 501 */ 502 ctx->seen_marks = 0; 503 for (unsigned i = 0; i < __arraycount(mark_keyword_map); i++) { 504 const struct mark_keyword_mapent *mk = &mark_keyword_map[i]; 505 scan_marks(ctx, mk, marks, mlen); 506 } 507 npfctl_print_filter_generic(ctx); 508 seenf |= npfctl_print_filter_seg(ctx, NPF_SRC); 509 seenf |= npfctl_print_filter_seg(ctx, NPF_DST); 510 return seenf; 511 } 512 513 static void 514 npfctl_print_rule(npf_conf_info_t *ctx, nl_rule_t *rl, unsigned level) 515 { 516 const uint32_t attr = npf_rule_getattr(rl); 517 const char *rproc, *ifname, *name; 518 bool dyn_ruleset; 519 520 /* Rule attributes/flags. */ 521 for (unsigned i = 0; i < __arraycount(attr_keyword_map); i++) { 522 const struct attr_keyword_mapent *ak = &attr_keyword_map[i]; 523 524 if (i == NAME_AT && (name = npf_rule_getname(rl)) != NULL) { 525 ctx->fpos += fprintf(ctx->fp, "\"%s\" ", name); 526 } 527 if ((attr & ak->mask) == ak->flags) { 528 ctx->fpos += fprintf(ctx->fp, "%s ", ak->val); 529 } 530 } 531 if ((ifname = npf_rule_getinterface(rl)) != NULL) { 532 ctx->fpos += fprintf(ctx->fp, "on %s ", ifname); 533 } 534 if (attr == (NPF_RULE_GROUP | NPF_RULE_IN | NPF_RULE_OUT) && !ifname) { 535 /* The default group is a special case. */ 536 ctx->fpos += fprintf(ctx->fp, "default "); 537 } 538 if ((attr & NPF_DYNAMIC_GROUP) == NPF_RULE_GROUP) { 539 /* Group; done. */ 540 ctx->fpos += fprintf(ctx->fp, "{ "); 541 ctx->glevel = level; 542 goto out; 543 } 544 545 /* Print filter criteria. */ 546 dyn_ruleset = (attr & NPF_DYNAMIC_GROUP) == NPF_DYNAMIC_GROUP; 547 if (!npfctl_print_filter(ctx, rl) && !dyn_ruleset) { 548 ctx->fpos += fprintf(ctx->fp, "all "); 549 } 550 551 /* Rule procedure. */ 552 if ((rproc = npf_rule_getproc(rl)) != NULL) { 553 ctx->fpos += fprintf(ctx->fp, "apply \"%s\" ", rproc); 554 } 555 out: 556 npfctl_print_id(ctx, rl); 557 ctx->fpos += fprintf(ctx->fp, "\n"); 558 } 559 560 static void 561 npfctl_print_nat(npf_conf_info_t *ctx, nl_nat_t *nt) 562 { 563 const unsigned dynamic_natset = NPF_RULE_GROUP | NPF_RULE_DYNAMIC; 564 nl_rule_t *rl = (nl_nat_t *)nt; 565 const char *ifname, *algo, *seg1, *seg2, *arrow; 566 const npf_addr_t *addr; 567 npf_netmask_t mask; 568 in_port_t port; 569 size_t alen; 570 unsigned flags; 571 char *seg; 572 573 /* Get flags and the interface. */ 574 flags = npf_nat_getflags(nt); 575 ifname = npf_rule_getinterface(rl); 576 assert(ifname != NULL); 577 578 if ((npf_rule_getattr(rl) & dynamic_natset) == dynamic_natset) { 579 const char *name = npf_rule_getname(rl); 580 ctx->fpos += fprintf(ctx->fp, 581 "map ruleset \"%s\" on %s\n", name, ifname); 582 return; 583 } 584 585 /* Get the translation address or table (and port, if used). */ 586 addr = npf_nat_getaddr(nt, &alen, &mask); 587 if (addr) { 588 seg = npfctl_print_addrmask(alen, "%a", addr, mask); 589 } else { 590 const unsigned tid = npf_nat_gettable(nt); 591 const char *tname; 592 bool ifaddr; 593 594 tname = npfctl_table_getname(ctx->conf, tid, &ifaddr); 595 easprintf(&seg, ifaddr ? "ifaddrs(%s)" : "<%s>", tname); 596 } 597 598 if ((port = npf_nat_getport(nt)) != 0) { 599 char *p; 600 easprintf(&p, "%s port %u", seg, ntohs(port)); 601 free(seg), seg = p; 602 } 603 seg1 = seg2 = "any"; 604 605 /* Get the NAT type and determine the translation segment. */ 606 switch (npf_nat_gettype(nt)) { 607 case NPF_NATIN: 608 arrow = "<-"; 609 seg1 = seg; 610 break; 611 case NPF_NATOUT: 612 arrow = "->"; 613 seg2 = seg; 614 break; 615 default: 616 abort(); 617 } 618 619 /* NAT algorithm. */ 620 switch (npf_nat_getalgo(nt)) { 621 case NPF_ALGO_NETMAP: 622 algo = "algo netmap "; 623 break; 624 case NPF_ALGO_IPHASH: 625 algo = "algo ip-hash "; 626 break; 627 case NPF_ALGO_RR: 628 algo = "algo round-robin "; 629 break; 630 case NPF_ALGO_NPT66: 631 algo = "algo npt66 "; 632 break; 633 default: 634 algo = ""; 635 break; 636 } 637 638 /* XXX also handle "any" */ 639 640 /* Print out the NAT policy with the filter criteria. */ 641 ctx->fpos += fprintf(ctx->fp, "map %s %s %s%s%s %s %s pass ", 642 ifname, (flags & NPF_NAT_STATIC) ? "static" : "dynamic", 643 algo, (flags & NPF_NAT_PORTS) ? "" : "no-ports ", 644 seg1, arrow, seg2); 645 npfctl_print_filter(ctx, rl); 646 npfctl_print_id(ctx, rl); 647 ctx->fpos += fprintf(ctx->fp, "\n"); 648 free(seg); 649 } 650 651 static void 652 npfctl_print_table(npf_conf_info_t *ctx, nl_table_t *tl) 653 { 654 const char *name = npf_table_getname(tl); 655 const unsigned type = npf_table_gettype(tl); 656 const char *table_types[] = { 657 [NPF_TABLE_IPSET] = "ipset", 658 [NPF_TABLE_LPM] = "lpm", 659 [NPF_TABLE_CONST] = "const", 660 }; 661 662 if (name[0] == '.') { 663 /* Internal tables use dot and are hidden. */ 664 return; 665 } 666 assert(type < __arraycount(table_types)); 667 ctx->fpos += fprintf(ctx->fp, 668 "table <%s> type %s\n", name, table_types[type]); 669 } 670 671 static void 672 npfctl_print_params(npf_conf_info_t *ctx, nl_config_t *ncf) 673 { 674 nl_iter_t i = NPF_ITER_BEGIN; 675 int val, defval, *dval; 676 const char *name; 677 678 dval = ctx->validating ? NULL : &defval; 679 while ((name = npf_param_iterate(ncf, &i, &val, dval)) != NULL) { 680 if (dval && val == *dval) { 681 continue; 682 } 683 ctx->fpos += fprintf(ctx->fp, "set %s %d\n", name, val); 684 } 685 print_linesep(ctx); 686 } 687 688 int 689 npfctl_config_show(int fd) 690 { 691 npf_conf_info_t *ctx = npfctl_show_init(); 692 nl_config_t *ncf; 693 bool loaded; 694 695 if (fd) { 696 ncf = npf_config_retrieve(fd); 697 if (ncf == NULL) { 698 return errno; 699 } 700 loaded = npf_config_loaded_p(ncf); 701 ctx->validating = false; 702 ctx->fpos += fprintf(ctx->fp, 703 "# filtering:\t%s\n# config:\t%s\n", 704 npf_config_active_p(ncf) ? "active" : "inactive", 705 loaded ? "loaded" : "empty"); 706 print_linesep(ctx); 707 } else { 708 ncf = npfctl_config_ref(); 709 npfctl_config_build(); 710 ctx->validating = true; 711 loaded = true; 712 } 713 ctx->conf = ncf; 714 715 if (loaded) { 716 nl_rule_t *rl; 717 nl_rproc_t *rp; 718 nl_nat_t *nt; 719 nl_table_t *tl; 720 nl_iter_t i; 721 unsigned level; 722 723 npfctl_print_params(ctx, ncf); 724 725 i = NPF_ITER_BEGIN; 726 while ((tl = npf_table_iterate(ncf, &i)) != NULL) { 727 npfctl_print_table(ctx, tl); 728 } 729 print_linesep(ctx); 730 731 i = NPF_ITER_BEGIN; 732 while ((rp = npf_rproc_iterate(ncf, &i)) != NULL) { 733 const char *rpname = npf_rproc_getname(rp); 734 ctx->fpos += fprintf(ctx->fp, 735 "procedure \"%s\"\n", rpname); 736 } 737 print_linesep(ctx); 738 739 i = NPF_ITER_BEGIN; 740 while ((nt = npf_nat_iterate(ncf, &i)) != NULL) { 741 npfctl_print_nat(ctx, nt); 742 } 743 print_linesep(ctx); 744 745 i = NPF_ITER_BEGIN; 746 while ((rl = npf_rule_iterate(ncf, &i, &level)) != NULL) { 747 print_indent(ctx, level); 748 npfctl_print_rule(ctx, rl, level); 749 } 750 print_indent(ctx, 0); 751 } 752 npf_config_destroy(ncf); 753 return 0; 754 } 755 756 int 757 npfctl_ruleset_show(int fd, const char *ruleset_name) 758 { 759 npf_conf_info_t *ctx = npfctl_show_init(); 760 nl_config_t *ncf; 761 nl_rule_t *rl; 762 unsigned level; 763 nl_iter_t i; 764 int error; 765 766 ncf = npf_config_create(); 767 ctx->conf = ncf; 768 769 if ((error = _npf_ruleset_list(fd, ruleset_name, ncf)) != 0) { 770 return error; 771 } 772 i = NPF_ITER_BEGIN; 773 while ((rl = npf_rule_iterate(ncf, &i, &level)) != NULL) { 774 npfctl_print_rule(ctx, rl, 0); 775 } 776 npf_config_destroy(ncf); 777 return error; 778 } 779