npfctl.c revision 1.54.2.2 1 /*-
2 * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This material is based upon work partially supported by The
6 * NetBSD Foundation under a contract with 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 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: npfctl.c,v 1.54.2.2 2018/09/30 01:46:01 pgoyette Exp $");
32
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/mman.h>
36 #ifdef __NetBSD__
37 #include <sha1.h>
38 #include <sys/ioctl.h>
39 #include <sys/module.h>
40 #define SHA_DIGEST_LENGTH SHA1_DIGEST_LENGTH
41 #else
42 #include <openssl/sha.h>
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <err.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <errno.h>
52
53 #include <arpa/inet.h>
54
55 #include "npfctl.h"
56
57 extern void npf_yyparse_string(const char *);
58
59 enum {
60 NPFCTL_START,
61 NPFCTL_STOP,
62 NPFCTL_RELOAD,
63 NPFCTL_SHOWCONF,
64 NPFCTL_FLUSH,
65 NPFCTL_VALIDATE,
66 NPFCTL_TABLE,
67 NPFCTL_RULE,
68 NPFCTL_STATS,
69 NPFCTL_SAVE,
70 NPFCTL_LOAD,
71 NPFCTL_DEBUG,
72 NPFCTL_CONN_LIST,
73 };
74
75 static const struct operations_s {
76 const char * cmd;
77 int action;
78 } operations[] = {
79 /* Start, stop, reload */
80 { "start", NPFCTL_START },
81 { "stop", NPFCTL_STOP },
82 { "reload", NPFCTL_RELOAD },
83 { "show", NPFCTL_SHOWCONF, },
84 { "flush", NPFCTL_FLUSH },
85 /* Table */
86 { "table", NPFCTL_TABLE },
87 /* Rule */
88 { "rule", NPFCTL_RULE },
89 /* Stats */
90 { "stats", NPFCTL_STATS },
91 /* Full state save/load */
92 { "save", NPFCTL_SAVE },
93 { "load", NPFCTL_LOAD },
94 { "list", NPFCTL_CONN_LIST },
95 /* Misc. */
96 { "valid", NPFCTL_VALIDATE },
97 { "debug", NPFCTL_DEBUG },
98 /* --- */
99 { NULL, 0 }
100 };
101
102 bool
103 join(char *buf, size_t buflen, int count, char **args, const char *sep)
104 {
105 const u_int seplen = strlen(sep);
106 char *s = buf, *p = NULL;
107
108 for (int i = 0; i < count; i++) {
109 size_t len;
110
111 p = stpncpy(s, args[i], buflen);
112 len = p - s + seplen;
113 if (len >= buflen) {
114 return false;
115 }
116 buflen -= len;
117 strcpy(p, sep);
118 s = p + seplen;
119 }
120 *p = '\0';
121 return true;
122 }
123
124 __dead static void
125 usage(void)
126 {
127 const char *progname = getprogname();
128
129 fprintf(stderr,
130 "Usage:\t%s start | stop | flush | show | stats\n",
131 progname);
132 fprintf(stderr,
133 "\t%s validate | reload [<rule-file>]\n",
134 progname);
135 fprintf(stderr,
136 "\t%s rule \"rule-name\" { add | rem } <rule-syntax>\n",
137 progname);
138 fprintf(stderr,
139 "\t%s rule \"rule-name\" rem-id <rule-id>\n",
140 progname);
141 fprintf(stderr,
142 "\t%s rule \"rule-name\" { list | flush }\n",
143 progname);
144 fprintf(stderr,
145 "\t%s table <tid> { add | rem | test } <address/mask>\n",
146 progname);
147 fprintf(stderr,
148 "\t%s table <tid> { list | flush }\n",
149 progname);
150 fprintf(stderr,
151 "\t%s save | load\n",
152 progname);
153 fprintf(stderr,
154 "\t%s list [-46hNnw] [-i <ifname>]\n",
155 progname);
156 exit(EXIT_FAILURE);
157 }
158
159 static int
160 npfctl_print_stats(int fd)
161 {
162 static const struct stats_s {
163 /* Note: -1 indicates a new section. */
164 int index;
165 const char * name;
166 } stats[] = {
167 { -1, "Packets passed" },
168 { NPF_STAT_PASS_DEFAULT, "default pass" },
169 { NPF_STAT_PASS_RULESET, "ruleset pass" },
170 { NPF_STAT_PASS_CONN, "state pass" },
171
172 { -1, "Packets blocked" },
173 { NPF_STAT_BLOCK_DEFAULT, "default block" },
174 { NPF_STAT_BLOCK_RULESET, "ruleset block" },
175
176 { -1, "State and NAT entries" },
177 { NPF_STAT_CONN_CREATE, "state allocations"},
178 { NPF_STAT_CONN_DESTROY, "state destructions"},
179 { NPF_STAT_NAT_CREATE, "NAT entry allocations" },
180 { NPF_STAT_NAT_DESTROY, "NAT entry destructions"},
181
182 { -1, "Network buffers" },
183 { NPF_STAT_NBUF_NONCONTIG, "non-contiguous cases" },
184 { NPF_STAT_NBUF_CONTIG_FAIL, "contig alloc failures" },
185
186 { -1, "Invalid packet state cases" },
187 { NPF_STAT_INVALID_STATE, "cases in total" },
188 { NPF_STAT_INVALID_STATE_TCP1, "TCP case I" },
189 { NPF_STAT_INVALID_STATE_TCP2, "TCP case II" },
190 { NPF_STAT_INVALID_STATE_TCP3, "TCP case III" },
191
192 { -1, "Packet race cases" },
193 { NPF_STAT_RACE_NAT, "NAT association race" },
194 { NPF_STAT_RACE_CONN, "duplicate state race" },
195
196 { -1, "Fragmentation" },
197 { NPF_STAT_FRAGMENTS, "fragments" },
198 { NPF_STAT_REASSEMBLY, "reassembled" },
199 { NPF_STAT_REASSFAIL, "failed reassembly" },
200
201 { -1, "Other" },
202 { NPF_STAT_ERROR, "unexpected errors" },
203 };
204 uint64_t *st = ecalloc(1, NPF_STATS_SIZE);
205
206 if (ioctl(fd, IOC_NPF_STATS, &st) != 0) {
207 err(EXIT_FAILURE, "ioctl(IOC_NPF_STATS)");
208 }
209
210 for (unsigned i = 0; i < __arraycount(stats); i++) {
211 const char *sname = stats[i].name;
212 int sidx = stats[i].index;
213
214 if (sidx == -1) {
215 printf("%s:\n", sname);
216 } else {
217 printf("\t%"PRIu64" %s\n", st[sidx], sname);
218 }
219 }
220
221 free(st);
222 return 0;
223 }
224
225 void
226 npfctl_print_error(const npf_error_t *ne)
227 {
228 const char *srcfile = ne->source_file;
229
230 if (srcfile) {
231 warnx("source %s line %d", srcfile, ne->source_line);
232 }
233 if (ne->id) {
234 warnx("object: %" PRIi64, ne->id);
235 }
236 }
237
238 char *
239 npfctl_print_addrmask(int alen, const char *fmt, const npf_addr_t *addr,
240 npf_netmask_t mask)
241 {
242 const unsigned buflen = 256;
243 char *buf = ecalloc(1, buflen);
244 struct sockaddr_storage ss;
245
246 memset(&ss, 0, sizeof(ss));
247
248 switch (alen) {
249 case 4: {
250 struct sockaddr_in *sin = (void *)&ss;
251 sin->sin_family = AF_INET;
252 memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr));
253 break;
254 }
255 case 16: {
256 struct sockaddr_in6 *sin6 = (void *)&ss;
257 sin6->sin6_family = AF_INET6;
258 memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr));
259 break;
260 }
261 default:
262 assert(false);
263 }
264 sockaddr_snprintf(buf, buflen, fmt, (const void *)&ss);
265 if (mask && mask != NPF_NO_NETMASK) {
266 const unsigned len = strlen(buf);
267 snprintf(&buf[len], buflen - len, "/%u", mask);
268 }
269 return buf;
270 }
271
272 __dead static void
273 npfctl_table(int fd, int argc, char **argv)
274 {
275 static const struct tblops_s {
276 const char * cmd;
277 int action;
278 } tblops[] = {
279 { "add", NPF_CMD_TABLE_ADD },
280 { "rem", NPF_CMD_TABLE_REMOVE },
281 { "del", NPF_CMD_TABLE_REMOVE },
282 { "test", NPF_CMD_TABLE_LOOKUP },
283 { "list", NPF_CMD_TABLE_LIST },
284 { "flush", NPF_CMD_TABLE_FLUSH },
285 { NULL, 0 }
286 };
287 npf_ioctl_table_t nct;
288 fam_addr_mask_t fam;
289 size_t buflen = 512;
290 char *cmd, *arg;
291 int n, alen;
292
293 /* Default action is list. */
294 memset(&nct, 0, sizeof(npf_ioctl_table_t));
295 nct.nct_name = argv[0];
296 cmd = argv[1];
297
298 for (n = 0; tblops[n].cmd != NULL; n++) {
299 if (strcmp(cmd, tblops[n].cmd) != 0) {
300 continue;
301 }
302 nct.nct_cmd = tblops[n].action;
303 break;
304 }
305 if (tblops[n].cmd == NULL) {
306 errx(EXIT_FAILURE, "invalid command '%s'", cmd);
307 }
308
309 switch (nct.nct_cmd) {
310 case NPF_CMD_TABLE_LIST:
311 case NPF_CMD_TABLE_FLUSH:
312 arg = NULL;
313 break;
314 default:
315 if (argc < 3) {
316 usage();
317 }
318 arg = argv[2];
319 }
320
321 again:
322 switch (nct.nct_cmd) {
323 case NPF_CMD_TABLE_LIST:
324 nct.nct_data.buf.buf = ecalloc(1, buflen);
325 nct.nct_data.buf.len = buflen;
326 break;
327 case NPF_CMD_TABLE_FLUSH:
328 break;
329 default:
330 if (!npfctl_parse_cidr(arg, &fam, &alen)) {
331 errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
332 }
333 nct.nct_data.ent.alen = alen;
334 memcpy(&nct.nct_data.ent.addr, &fam.fam_addr, alen);
335 nct.nct_data.ent.mask = fam.fam_mask;
336 }
337
338 if (ioctl(fd, IOC_NPF_TABLE, &nct) != -1) {
339 errno = 0;
340 }
341 switch (errno) {
342 case 0:
343 break;
344 case EEXIST:
345 errx(EXIT_FAILURE, "entry already exists or is conflicting");
346 case ENOENT:
347 errx(EXIT_FAILURE, "no matching entry was not found");
348 case EINVAL:
349 errx(EXIT_FAILURE, "invalid address, mask or table ID");
350 case ENOMEM:
351 if (nct.nct_cmd == NPF_CMD_TABLE_LIST) {
352 /* XXX */
353 free(nct.nct_data.buf.buf);
354 buflen <<= 1;
355 goto again;
356 }
357 /* FALLTHROUGH */
358 default:
359 err(EXIT_FAILURE, "ioctl(IOC_NPF_TABLE)");
360 }
361
362 if (nct.nct_cmd == NPF_CMD_TABLE_LIST) {
363 npf_ioctl_ent_t *ent = nct.nct_data.buf.buf;
364 char *buf;
365
366 while (nct.nct_data.buf.len--) {
367 if (!ent->alen)
368 break;
369 buf = npfctl_print_addrmask(ent->alen, "%a",
370 &ent->addr, ent->mask);
371 puts(buf);
372 ent++;
373 }
374 free(nct.nct_data.buf.buf);
375 } else {
376 printf("%s: %s\n", getprogname(),
377 nct.nct_cmd == NPF_CMD_TABLE_LOOKUP ?
378 "matching entry found" : "success");
379 }
380 exit(EXIT_SUCCESS);
381 }
382
383 static nl_rule_t *
384 npfctl_parse_rule(int argc, char **argv)
385 {
386 char rule_string[1024];
387 nl_rule_t *rl;
388
389 /* Get the rule string and parse it. */
390 if (!join(rule_string, sizeof(rule_string), argc, argv, " ")) {
391 errx(EXIT_FAILURE, "command too long");
392 }
393 npfctl_parse_string(rule_string);
394 if ((rl = npfctl_rule_ref()) == NULL) {
395 errx(EXIT_FAILURE, "could not parse the rule");
396 }
397 return rl;
398 }
399
400 #ifdef __NetBSD__
401 static unsigned char *
402 SHA1(const unsigned char *d, size_t l, unsigned char *md)
403 {
404 SHA1_CTX c;
405
406 SHA1Init(&c);
407 SHA1Update(&c, d, l);
408 SHA1Final(md, &c);
409 return md;
410 }
411 #endif
412
413 static void
414 npfctl_generate_key(nl_rule_t *rl, void *key)
415 {
416 void *meta;
417 size_t len;
418
419 if ((meta = npf_rule_export(rl, &len)) == NULL) {
420 errx(EXIT_FAILURE, "error generating rule key");
421 }
422 __CTASSERT(NPF_RULE_MAXKEYLEN >= SHA_DIGEST_LENGTH);
423 memset(key, 0, NPF_RULE_MAXKEYLEN);
424 SHA1(meta, len, key);
425 free(meta);
426 }
427
428 __dead static void
429 npfctl_rule(int fd, int argc, char **argv)
430 {
431 static const struct ruleops_s {
432 const char * cmd;
433 int action;
434 bool extra_arg;
435 } ruleops[] = {
436 { "add", NPF_CMD_RULE_ADD, true },
437 { "rem", NPF_CMD_RULE_REMKEY, true },
438 { "del", NPF_CMD_RULE_REMKEY, true },
439 { "rem-id", NPF_CMD_RULE_REMOVE, true },
440 { "list", NPF_CMD_RULE_LIST, false },
441 { "flush", NPF_CMD_RULE_FLUSH, false },
442 { NULL, 0, 0 }
443 };
444 uint8_t key[NPF_RULE_MAXKEYLEN];
445 const char *ruleset_name = argv[0];
446 const char *cmd = argv[1];
447 int error, action = 0;
448 uint64_t rule_id;
449 bool extra_arg;
450 nl_rule_t *rl;
451
452 for (int n = 0; ruleops[n].cmd != NULL; n++) {
453 if (strcmp(cmd, ruleops[n].cmd) == 0) {
454 action = ruleops[n].action;
455 extra_arg = ruleops[n].extra_arg;
456 break;
457 }
458 }
459 argc -= 2;
460 argv += 2;
461
462 if (!action || (extra_arg && argc == 0)) {
463 usage();
464 }
465
466 switch (action) {
467 case NPF_CMD_RULE_ADD:
468 rl = npfctl_parse_rule(argc, argv);
469 npfctl_generate_key(rl, key);
470 npf_rule_setkey(rl, key, sizeof(key));
471 error = npf_ruleset_add(fd, ruleset_name, rl, &rule_id);
472 break;
473 case NPF_CMD_RULE_REMKEY:
474 rl = npfctl_parse_rule(argc, argv);
475 npfctl_generate_key(rl, key);
476 error = npf_ruleset_remkey(fd, ruleset_name, key, sizeof(key));
477 break;
478 case NPF_CMD_RULE_REMOVE:
479 rule_id = strtoull(argv[0], NULL, 16);
480 error = npf_ruleset_remove(fd, ruleset_name, rule_id);
481 break;
482 case NPF_CMD_RULE_LIST:
483 error = npfctl_ruleset_show(fd, ruleset_name);
484 break;
485 case NPF_CMD_RULE_FLUSH:
486 error = npf_ruleset_flush(fd, ruleset_name);
487 break;
488 default:
489 abort();
490 }
491
492 switch (error) {
493 case 0:
494 /* Success. */
495 break;
496 case ESRCH:
497 errx(EXIT_FAILURE, "ruleset \"%s\" not found", ruleset_name);
498 case ENOENT:
499 errx(EXIT_FAILURE, "rule was not found");
500 default:
501 errx(EXIT_FAILURE, "rule operation: %s", strerror(error));
502 }
503 if (action == NPF_CMD_RULE_ADD) {
504 printf("OK %" PRIx64 "\n", rule_id);
505 }
506 exit(EXIT_SUCCESS);
507 }
508
509 static bool bpfjit = true;
510
511 void
512 npfctl_bpfjit(bool onoff)
513 {
514 bpfjit = onoff;
515 }
516
517 static void
518 npfctl_preload_bpfjit(void)
519 {
520 #ifdef __NetBSD__
521 modctl_load_t args = {
522 .ml_filename = "bpfjit",
523 .ml_flags = MODCTL_NO_PROP,
524 .ml_props = NULL,
525 .ml_propslen = 0
526 };
527
528 if (!bpfjit)
529 return;
530
531 if (modctl(MODCTL_LOAD, &args) != 0 && errno != EEXIST) {
532 static const char *p = "; performance will be degraded";
533 if (errno == ENOENT)
534 warnx("the bpfjit module seems to be missing%s", p);
535 else
536 warn("error loading the bpfjit module%s", p);
537 warnx("To disable this warning `set bpf.jit off' in "
538 "/etc/npf.conf");
539 }
540 #endif
541 }
542
543 static int
544 npfctl_load(int fd)
545 {
546 nl_config_t *ncf;
547 npf_error_t errinfo;
548 struct stat sb;
549 size_t blen;
550 void *blob;
551 int error;
552
553 /*
554 * The file may change while reading - we are not handling this,
555 * leaving this responsibility for the caller.
556 */
557 if (stat(NPF_DB_PATH, &sb) == -1) {
558 err(EXIT_FAILURE, "stat");
559 }
560 if ((blen = sb.st_size) == 0) {
561 err(EXIT_FAILURE, "saved configuration file is empty");
562 }
563 if ((blob = mmap(NULL, blen, PROT_READ,
564 MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
565 err(EXIT_FAILURE, "mmap");
566 }
567 ncf = npf_config_import(blob, blen);
568 munmap(blob, blen);
569 if (ncf == NULL) {
570 return errno;
571 }
572
573 /*
574 * Configuration imported - submit it now.
575 **/
576 errno = error = npf_config_submit(ncf, fd, &errinfo);
577 if (error) {
578 npfctl_print_error(&errinfo);
579 }
580 npf_config_destroy(ncf);
581 return error;
582 }
583
584 struct npf_conn_filter {
585 uint16_t alen;
586 const char *ifname;
587 bool nat;
588 bool wide;
589 bool name;
590 int width;
591 FILE *fp;
592 };
593
594 static int
595 npfctl_conn_print(unsigned alen, const npf_addr_t *a, const in_port_t *p,
596 const char *ifname, void *v)
597 {
598 struct npf_conn_filter *fil = v;
599 FILE *fp = fil->fp;
600 char *src, *dst;
601
602 if (fil->ifname && strcmp(ifname, fil->ifname) != 0)
603 return 0;
604 if (fil->alen && alen != fil->alen)
605 return 0;
606 if (fil->nat && !p[2])
607 return 0;
608
609 int w = fil->width;
610 const char *fmt = fil->name ? "%A" :
611 (alen == sizeof(struct in_addr) ? "%a" : "[%a]");
612 src = npfctl_print_addrmask(alen, fmt, &a[0], NPF_NO_NETMASK);
613 dst = npfctl_print_addrmask(alen, fmt, &a[1], NPF_NO_NETMASK);
614 if (fil->wide)
615 fprintf(fp, "%s:%d %s:%d", src, p[0], dst, p[1]);
616 else
617 fprintf(fp, "%*.*s:%-5d %*.*s:%-5d", w, w, src, p[0],
618 w, w, dst, p[1]);
619 free(src);
620 free(dst);
621 if (!p[2]) {
622 fputc('\n', fp);
623 return 1;
624 }
625 fprintf(fp, " via %s:%d\n", ifname, p[2]);
626 return 1;
627 }
628
629
630 static int
631 npfctl_conn_list(int fd, int argc, char **argv)
632 {
633 struct npf_conn_filter f;
634 int c;
635 int header = true;
636 memset(&f, 0, sizeof(f));
637
638 argc--;
639 argv++;
640
641 while ((c = getopt(argc, argv, "46hi:nNw")) != -1) {
642 switch (c) {
643 case '4':
644 f.alen = sizeof(struct in_addr);
645 break;
646 case '6':
647 f.alen = sizeof(struct in6_addr);
648 break;
649 case 'h':
650 header = false;
651 case 'i':
652 f.ifname = optarg;
653 break;
654 case 'n':
655 f.nat = true;
656 break;
657 case 'N':
658 f.name = true;
659 break;
660 case 'w':
661 f.wide = true;
662 break;
663 default:
664 fprintf(stderr,
665 "Usage: %s list [-46hnNw] [-i <ifname>]\n",
666 getprogname());
667 exit(EXIT_FAILURE);
668 }
669 }
670 f.width = f.alen == sizeof(struct in_addr) ? 25 : 41;
671 int w = f.width + 6;
672 f.fp = stdout;
673 if (header)
674 fprintf(f.fp, "%*.*s %*.*s\n",
675 w, w, "From address:port ", w, w, "To address:port ");
676
677 npf_conn_list(fd, npfctl_conn_print, &f);
678 return 0;
679 }
680
681 static int
682 npfctl_open_dev(const char *path)
683 {
684 int fd, kernver;
685
686 fd = open(path, O_RDONLY);
687 if (fd == -1) {
688 err(EXIT_FAILURE, "cannot open '%s'", path);
689 }
690 if (ioctl(fd, IOC_NPF_VERSION, &kernver) == -1) {
691 err(EXIT_FAILURE, "ioctl(IOC_NPF_VERSION)");
692 }
693 if (kernver != NPF_VERSION) {
694 errx(EXIT_FAILURE,
695 "incompatible NPF interface version (%d, kernel %d)\n"
696 "Hint: update %s?", NPF_VERSION, kernver,
697 kernver > NPF_VERSION ? "userland" : "kernel");
698 }
699 return fd;
700 }
701
702 static void
703 npfctl(int action, int argc, char **argv)
704 {
705 int fd, boolval, ret = 0;
706 const char *fun = "";
707 nl_config_t *ncf;
708
709 switch (action) {
710 case NPFCTL_VALIDATE:
711 case NPFCTL_DEBUG:
712 fd = 0;
713 break;
714 default:
715 fd = npfctl_open_dev(NPF_DEV_PATH);
716 }
717
718 switch (action) {
719 case NPFCTL_START:
720 boolval = true;
721 ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
722 fun = "ioctl(IOC_NPF_SWITCH)";
723 break;
724 case NPFCTL_STOP:
725 boolval = false;
726 ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
727 fun = "ioctl(IOC_NPF_SWITCH)";
728 break;
729 case NPFCTL_RELOAD:
730 npfctl_config_init(false);
731 npfctl_parse_file(argc < 3 ? NPF_CONF_PATH : argv[2]);
732 npfctl_preload_bpfjit();
733 errno = ret = npfctl_config_send(fd);
734 fun = "npfctl_config_send";
735 break;
736 case NPFCTL_SHOWCONF:
737 ret = npfctl_config_show(fd);
738 fun = "npfctl_config_show";
739 break;
740 case NPFCTL_FLUSH:
741 ret = npf_config_flush(fd);
742 fun = "npf_config_flush";
743 break;
744 case NPFCTL_TABLE:
745 if ((argc -= 2) < 2) {
746 usage();
747 }
748 argv += 2;
749 npfctl_table(fd, argc, argv);
750 break;
751 case NPFCTL_RULE:
752 if ((argc -= 2) < 2) {
753 usage();
754 }
755 argv += 2;
756 npfctl_rule(fd, argc, argv);
757 break;
758 case NPFCTL_LOAD:
759 npfctl_preload_bpfjit();
760 ret = npfctl_load(fd);
761 fun = "npfctl_config_load";
762 break;
763 case NPFCTL_SAVE:
764 ncf = npf_config_retrieve(fd);
765 if (ncf) {
766 npfctl_config_save(ncf, NPF_DB_PATH);
767 npf_config_destroy(ncf);
768 } else {
769 ret = errno;
770 }
771 fun = "npfctl_config_save";
772 break;
773 case NPFCTL_STATS:
774 ret = npfctl_print_stats(fd);
775 fun = "npfctl_print_stats";
776 break;
777 case NPFCTL_CONN_LIST:
778 ret = npfctl_conn_list(fd, argc, argv);
779 fun = "npfctl_conn_list";
780 break;
781 case NPFCTL_VALIDATE:
782 npfctl_config_init(false);
783 npfctl_parse_file(argc > 2 ? argv[2] : NPF_CONF_PATH);
784 ret = npfctl_config_show(0);
785 fun = "npfctl_config_show";
786 break;
787 case NPFCTL_DEBUG:
788 npfctl_config_init(true);
789 npfctl_parse_file(argc > 2 ? argv[2] : NPF_CONF_PATH);
790 npfctl_config_debug(argc > 3 ? argv[3] : "/tmp/npf.nvlist");
791 break;
792 }
793 if (ret) {
794 err(EXIT_FAILURE, "%s", fun);
795 }
796 if (fd) {
797 close(fd);
798 }
799 }
800
801 int
802 main(int argc, char **argv)
803 {
804 char *cmd;
805
806 if (argc < 2) {
807 usage();
808 }
809 npfctl_show_init();
810 cmd = argv[1];
811
812 /* Find and call the subroutine. */
813 for (int n = 0; operations[n].cmd != NULL; n++) {
814 const char *opcmd = operations[n].cmd;
815 if (strncmp(cmd, opcmd, strlen(opcmd)) != 0)
816 continue;
817 npfctl(operations[n].action, argc, argv);
818 return EXIT_SUCCESS;
819 }
820 usage();
821 }
822