npfctl.c revision 1.67 1 1.1 rmind /*-
2 1.66 joe * Copyright (c) 2009-2025 The NetBSD Foundation, Inc.
3 1.1 rmind * All rights reserved.
4 1.1 rmind *
5 1.1 rmind * This material is based upon work partially supported by The
6 1.1 rmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
7 1.1 rmind *
8 1.1 rmind * Redistribution and use in source and binary forms, with or without
9 1.1 rmind * modification, are permitted provided that the following conditions
10 1.1 rmind * are met:
11 1.1 rmind * 1. Redistributions of source code must retain the above copyright
12 1.1 rmind * notice, this list of conditions and the following disclaimer.
13 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 rmind * notice, this list of conditions and the following disclaimer in the
15 1.1 rmind * documentation and/or other materials provided with the distribution.
16 1.1 rmind *
17 1.1 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 1.1 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 1.1 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 1.1 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 1.1 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 1.1 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 1.1 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 1.1 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 1.1 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 1.1 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1.1 rmind * POSSIBILITY OF SUCH DAMAGE.
28 1.1 rmind */
29 1.1 rmind
30 1.2 rmind #include <sys/cdefs.h>
31 1.67 joe __RCSID("$NetBSD: npfctl.c,v 1.67 2025/07/01 19:55:16 joe Exp $");
32 1.2 rmind
33 1.64 rmind #include <sys/types.h>
34 1.1 rmind #include <sys/stat.h>
35 1.64 rmind #include <sys/socket.h>
36 1.48 christos #include <sys/mman.h>
37 1.64 rmind #include <sys/un.h>
38 1.48 christos #ifdef __NetBSD__
39 1.44 rmind #include <sys/module.h>
40 1.48 christos #endif
41 1.1 rmind
42 1.1 rmind #include <stdio.h>
43 1.64 rmind #include <string.h>
44 1.1 rmind #include <stdlib.h>
45 1.64 rmind #include <unistd.h>
46 1.1 rmind #include <fcntl.h>
47 1.15 rmind #include <errno.h>
48 1.64 rmind #include <err.h>
49 1.29 rmind
50 1.1 rmind #include "npfctl.h"
51 1.1 rmind
52 1.11 rmind enum {
53 1.11 rmind NPFCTL_START,
54 1.11 rmind NPFCTL_STOP,
55 1.11 rmind NPFCTL_RELOAD,
56 1.11 rmind NPFCTL_SHOWCONF,
57 1.11 rmind NPFCTL_FLUSH,
58 1.25 rmind NPFCTL_VALIDATE,
59 1.11 rmind NPFCTL_TABLE,
60 1.29 rmind NPFCTL_RULE,
61 1.11 rmind NPFCTL_STATS,
62 1.41 rmind NPFCTL_SAVE,
63 1.41 rmind NPFCTL_LOAD,
64 1.52 rmind NPFCTL_DEBUG,
65 1.50 christos NPFCTL_CONN_LIST,
66 1.11 rmind };
67 1.1 rmind
68 1.38 rmind bool
69 1.38 rmind join(char *buf, size_t buflen, int count, char **args, const char *sep)
70 1.29 rmind {
71 1.64 rmind const unsigned seplen = strlen(sep);
72 1.29 rmind char *s = buf, *p = NULL;
73 1.29 rmind
74 1.29 rmind for (int i = 0; i < count; i++) {
75 1.29 rmind size_t len;
76 1.29 rmind
77 1.29 rmind p = stpncpy(s, args[i], buflen);
78 1.38 rmind len = p - s + seplen;
79 1.29 rmind if (len >= buflen) {
80 1.29 rmind return false;
81 1.29 rmind }
82 1.29 rmind buflen -= len;
83 1.38 rmind strcpy(p, sep);
84 1.38 rmind s = p + seplen;
85 1.29 rmind }
86 1.29 rmind *p = '\0';
87 1.29 rmind return true;
88 1.29 rmind }
89 1.29 rmind
90 1.64 rmind __dead void
91 1.1 rmind usage(void)
92 1.1 rmind {
93 1.1 rmind const char *progname = getprogname();
94 1.1 rmind
95 1.1 rmind fprintf(stderr,
96 1.37 rmind "Usage:\t%s start | stop | flush | show | stats\n",
97 1.33 christos progname);
98 1.33 christos fprintf(stderr,
99 1.33 christos "\t%s validate | reload [<rule-file>]\n",
100 1.3 rmind progname);
101 1.3 rmind fprintf(stderr,
102 1.29 rmind "\t%s rule \"rule-name\" { add | rem } <rule-syntax>\n",
103 1.29 rmind progname);
104 1.29 rmind fprintf(stderr,
105 1.29 rmind "\t%s rule \"rule-name\" rem-id <rule-id>\n",
106 1.1 rmind progname);
107 1.1 rmind fprintf(stderr,
108 1.31 rmind "\t%s rule \"rule-name\" { list | flush }\n",
109 1.31 rmind progname);
110 1.31 rmind fprintf(stderr,
111 1.62 rmind "\t%s table \"table-name\" { add | rem | test } <address/mask>\n",
112 1.1 rmind progname);
113 1.1 rmind fprintf(stderr,
114 1.62 rmind "\t%s table \"table-name\" { list | flush }\n",
115 1.62 rmind progname);
116 1.62 rmind fprintf(stderr,
117 1.62 rmind "\t%s table \"table-name\" replace [-n \"name\"]"
118 1.62 rmind " [-t <type>] <table-file>\n",
119 1.1 rmind progname);
120 1.37 rmind fprintf(stderr,
121 1.41 rmind "\t%s save | load\n",
122 1.37 rmind progname);
123 1.50 christos fprintf(stderr,
124 1.51 wiz "\t%s list [-46hNnw] [-i <ifname>]\n",
125 1.50 christos progname);
126 1.57 rmind fprintf(stderr,
127 1.64 rmind "\t%s debug { -a | -b <binary-config> | -c <config> } "
128 1.64 rmind "[ -o <outfile> ]\n",
129 1.57 rmind progname);
130 1.1 rmind exit(EXIT_FAILURE);
131 1.1 rmind }
132 1.1 rmind
133 1.3 rmind static int
134 1.3 rmind npfctl_print_stats(int fd)
135 1.3 rmind {
136 1.17 rmind static const struct stats_s {
137 1.17 rmind /* Note: -1 indicates a new section. */
138 1.17 rmind int index;
139 1.17 rmind const char * name;
140 1.17 rmind } stats[] = {
141 1.17 rmind { -1, "Packets passed" },
142 1.67 joe { NPF_ETHER_STAT_PASS, "ether pass" },
143 1.17 rmind { NPF_STAT_PASS_DEFAULT, "default pass" },
144 1.17 rmind { NPF_STAT_PASS_RULESET, "ruleset pass" },
145 1.41 rmind { NPF_STAT_PASS_CONN, "state pass" },
146 1.17 rmind
147 1.17 rmind { -1, "Packets blocked" },
148 1.67 joe { NPF_ETHER_STAT_BLOCK, "ether block" },
149 1.17 rmind { NPF_STAT_BLOCK_DEFAULT, "default block" },
150 1.17 rmind { NPF_STAT_BLOCK_RULESET, "ruleset block" },
151 1.17 rmind
152 1.41 rmind { -1, "State and NAT entries" },
153 1.41 rmind { NPF_STAT_CONN_CREATE, "state allocations"},
154 1.41 rmind { NPF_STAT_CONN_DESTROY, "state destructions"},
155 1.17 rmind { NPF_STAT_NAT_CREATE, "NAT entry allocations" },
156 1.17 rmind { NPF_STAT_NAT_DESTROY, "NAT entry destructions"},
157 1.17 rmind
158 1.27 rmind { -1, "Network buffers" },
159 1.27 rmind { NPF_STAT_NBUF_NONCONTIG, "non-contiguous cases" },
160 1.27 rmind { NPF_STAT_NBUF_CONTIG_FAIL, "contig alloc failures" },
161 1.27 rmind
162 1.17 rmind { -1, "Invalid packet state cases" },
163 1.17 rmind { NPF_STAT_INVALID_STATE, "cases in total" },
164 1.17 rmind { NPF_STAT_INVALID_STATE_TCP1, "TCP case I" },
165 1.17 rmind { NPF_STAT_INVALID_STATE_TCP2, "TCP case II" },
166 1.17 rmind { NPF_STAT_INVALID_STATE_TCP3, "TCP case III" },
167 1.17 rmind
168 1.17 rmind { -1, "Packet race cases" },
169 1.17 rmind { NPF_STAT_RACE_NAT, "NAT association race" },
170 1.41 rmind { NPF_STAT_RACE_CONN, "duplicate state race" },
171 1.17 rmind
172 1.17 rmind { -1, "Fragmentation" },
173 1.17 rmind { NPF_STAT_FRAGMENTS, "fragments" },
174 1.17 rmind { NPF_STAT_REASSEMBLY, "reassembled" },
175 1.17 rmind { NPF_STAT_REASSFAIL, "failed reassembly" },
176 1.17 rmind
177 1.17 rmind { -1, "Other" },
178 1.17 rmind { NPF_STAT_ERROR, "unexpected errors" },
179 1.17 rmind };
180 1.24 rmind uint64_t *st = ecalloc(1, NPF_STATS_SIZE);
181 1.3 rmind
182 1.3 rmind if (ioctl(fd, IOC_NPF_STATS, &st) != 0) {
183 1.3 rmind err(EXIT_FAILURE, "ioctl(IOC_NPF_STATS)");
184 1.3 rmind }
185 1.3 rmind
186 1.17 rmind for (unsigned i = 0; i < __arraycount(stats); i++) {
187 1.17 rmind const char *sname = stats[i].name;
188 1.17 rmind int sidx = stats[i].index;
189 1.17 rmind
190 1.17 rmind if (sidx == -1) {
191 1.17 rmind printf("%s:\n", sname);
192 1.17 rmind } else {
193 1.17 rmind printf("\t%"PRIu64" %s\n", st[sidx], sname);
194 1.17 rmind }
195 1.17 rmind }
196 1.4 rmind
197 1.3 rmind free(st);
198 1.3 rmind return 0;
199 1.3 rmind }
200 1.3 rmind
201 1.10 rmind void
202 1.48 christos npfctl_print_error(const npf_error_t *ne)
203 1.10 rmind {
204 1.48 christos const char *srcfile = ne->source_file;
205 1.10 rmind
206 1.59 rmind if (ne->error_msg) {
207 1.60 rmind errx(EXIT_FAILURE, "%s", ne->error_msg);
208 1.59 rmind }
209 1.10 rmind if (srcfile) {
210 1.48 christos warnx("source %s line %d", srcfile, ne->source_line);
211 1.10 rmind }
212 1.48 christos if (ne->id) {
213 1.48 christos warnx("object: %" PRIi64, ne->id);
214 1.10 rmind }
215 1.10 rmind }
216 1.10 rmind
217 1.21 rmind char *
218 1.50 christos npfctl_print_addrmask(int alen, const char *fmt, const npf_addr_t *addr,
219 1.50 christos npf_netmask_t mask)
220 1.21 rmind {
221 1.50 christos const unsigned buflen = 256;
222 1.48 christos char *buf = ecalloc(1, buflen);
223 1.21 rmind struct sockaddr_storage ss;
224 1.48 christos
225 1.48 christos memset(&ss, 0, sizeof(ss));
226 1.21 rmind
227 1.21 rmind switch (alen) {
228 1.21 rmind case 4: {
229 1.21 rmind struct sockaddr_in *sin = (void *)&ss;
230 1.21 rmind sin->sin_family = AF_INET;
231 1.21 rmind memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr));
232 1.21 rmind break;
233 1.21 rmind }
234 1.21 rmind case 16: {
235 1.21 rmind struct sockaddr_in6 *sin6 = (void *)&ss;
236 1.21 rmind sin6->sin6_family = AF_INET6;
237 1.21 rmind memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr));
238 1.21 rmind break;
239 1.21 rmind }
240 1.21 rmind default:
241 1.64 rmind abort();
242 1.21 rmind }
243 1.50 christos sockaddr_snprintf(buf, buflen, fmt, (const void *)&ss);
244 1.38 rmind if (mask && mask != NPF_NO_NETMASK) {
245 1.48 christos const unsigned len = strlen(buf);
246 1.48 christos snprintf(&buf[len], buflen - len, "/%u", mask);
247 1.21 rmind }
248 1.21 rmind return buf;
249 1.21 rmind }
250 1.21 rmind
251 1.64 rmind bool
252 1.64 rmind npfctl_addr_iszero(const npf_addr_t *addr)
253 1.29 rmind {
254 1.64 rmind static const npf_addr_t zero; /* must be static */
255 1.64 rmind return memcmp(addr, &zero, sizeof(npf_addr_t)) == 0;
256 1.29 rmind }
257 1.29 rmind
258 1.45 christos static bool bpfjit = true;
259 1.45 christos
260 1.45 christos void
261 1.45 christos npfctl_bpfjit(bool onoff)
262 1.45 christos {
263 1.45 christos bpfjit = onoff;
264 1.45 christos }
265 1.45 christos
266 1.44 rmind static void
267 1.44 rmind npfctl_preload_bpfjit(void)
268 1.44 rmind {
269 1.48 christos #ifdef __NetBSD__
270 1.44 rmind modctl_load_t args = {
271 1.44 rmind .ml_filename = "bpfjit",
272 1.44 rmind .ml_flags = MODCTL_NO_PROP,
273 1.44 rmind .ml_props = NULL,
274 1.44 rmind .ml_propslen = 0
275 1.44 rmind };
276 1.44 rmind
277 1.45 christos if (!bpfjit)
278 1.45 christos return;
279 1.45 christos
280 1.44 rmind if (modctl(MODCTL_LOAD, &args) != 0 && errno != EEXIST) {
281 1.45 christos static const char *p = "; performance will be degraded";
282 1.45 christos if (errno == ENOENT)
283 1.45 christos warnx("the bpfjit module seems to be missing%s", p);
284 1.45 christos else
285 1.45 christos warn("error loading the bpfjit module%s", p);
286 1.45 christos warnx("To disable this warning `set bpf.jit off' in "
287 1.45 christos "/etc/npf.conf");
288 1.44 rmind }
289 1.48 christos #endif
290 1.44 rmind }
291 1.44 rmind
292 1.64 rmind static nl_config_t *
293 1.64 rmind npfctl_import(const char *path)
294 1.41 rmind {
295 1.41 rmind nl_config_t *ncf;
296 1.48 christos struct stat sb;
297 1.48 christos size_t blen;
298 1.48 christos void *blob;
299 1.64 rmind int fd;
300 1.41 rmind
301 1.48 christos /*
302 1.48 christos * The file may change while reading - we are not handling this,
303 1.64 rmind * just leaving this responsibility for the caller.
304 1.48 christos */
305 1.64 rmind if ((fd = open(path, O_RDONLY)) == -1) {
306 1.65 christos err(EXIT_FAILURE, "open: '%s'", path);
307 1.64 rmind }
308 1.64 rmind if (fstat(fd, &sb) == -1) {
309 1.65 christos err(EXIT_FAILURE, "stat: '%s'", path);
310 1.48 christos }
311 1.48 christos if ((blen = sb.st_size) == 0) {
312 1.65 christos errx(EXIT_FAILURE,
313 1.65 christos "the binary configuration file '%s' is empty", path);
314 1.48 christos }
315 1.64 rmind blob = mmap(NULL, blen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
316 1.64 rmind if (blob == MAP_FAILED) {
317 1.65 christos err(EXIT_FAILURE, "mmap: '%s'", path);
318 1.48 christos }
319 1.48 christos ncf = npf_config_import(blob, blen);
320 1.48 christos munmap(blob, blen);
321 1.64 rmind return ncf;
322 1.64 rmind }
323 1.64 rmind
324 1.64 rmind static int
325 1.64 rmind npfctl_load(int fd)
326 1.64 rmind {
327 1.64 rmind nl_config_t *ncf;
328 1.64 rmind npf_error_t errinfo;
329 1.64 rmind
330 1.64 rmind /*
331 1.64 rmind * Import the configuration, submit it and destroy.
332 1.64 rmind */
333 1.64 rmind ncf = npfctl_import(NPF_DB_PATH);
334 1.41 rmind if (ncf == NULL) {
335 1.65 christos err(EXIT_FAILURE, "npf_config_import: '%s'", NPF_DB_PATH);
336 1.41 rmind }
337 1.64 rmind if ((errno = npf_config_submit(ncf, fd, &errinfo)) != 0) {
338 1.48 christos npfctl_print_error(&errinfo);
339 1.43 rmind }
340 1.41 rmind npf_config_destroy(ncf);
341 1.64 rmind return errno;
342 1.41 rmind }
343 1.41 rmind
344 1.50 christos static int
345 1.64 rmind npfctl_open_dev(const char *path)
346 1.50 christos {
347 1.64 rmind struct stat st;
348 1.64 rmind int fd;
349 1.64 rmind
350 1.64 rmind if (lstat(path, &st) == -1) {
351 1.65 christos err(EXIT_FAILURE, "fstat: '%s'", path);
352 1.64 rmind }
353 1.64 rmind if ((st.st_mode & S_IFMT) == S_IFSOCK) {
354 1.64 rmind struct sockaddr_un addr;
355 1.64 rmind
356 1.64 rmind if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
357 1.64 rmind err(EXIT_FAILURE, "socket");
358 1.64 rmind }
359 1.64 rmind memset(&addr, 0, sizeof(addr));
360 1.64 rmind addr.sun_family = AF_UNIX;
361 1.64 rmind strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
362 1.59 rmind
363 1.64 rmind if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
364 1.65 christos err(EXIT_FAILURE, "connect: '%s'", path);
365 1.64 rmind }
366 1.59 rmind } else {
367 1.64 rmind if ((fd = open(path, O_RDONLY)) == -1) {
368 1.65 christos err(EXIT_FAILURE, "open: '%s'", path);
369 1.64 rmind }
370 1.59 rmind }
371 1.64 rmind return fd;
372 1.50 christos }
373 1.50 christos
374 1.64 rmind static void
375 1.64 rmind npfctl_debug(int argc, char **argv)
376 1.50 christos {
377 1.64 rmind const char *conf = NULL, *bconf = NULL, *outfile = NULL;
378 1.64 rmind bool use_active = false;
379 1.64 rmind nl_config_t *ncf = NULL;
380 1.64 rmind int fd, c, optcount;
381 1.59 rmind
382 1.50 christos argc--;
383 1.50 christos argv++;
384 1.50 christos
385 1.64 rmind npfctl_config_init(true);
386 1.64 rmind while ((c = getopt(argc, argv, "ab:c:o:")) != -1) {
387 1.50 christos switch (c) {
388 1.64 rmind case 'a':
389 1.64 rmind use_active = true;
390 1.58 mrg break;
391 1.64 rmind case 'b':
392 1.64 rmind bconf = optarg;
393 1.50 christos break;
394 1.64 rmind case 'c':
395 1.64 rmind conf = optarg;
396 1.50 christos break;
397 1.64 rmind case 'o':
398 1.64 rmind outfile = optarg;
399 1.50 christos break;
400 1.50 christos default:
401 1.64 rmind usage();
402 1.50 christos }
403 1.50 christos }
404 1.59 rmind
405 1.64 rmind /*
406 1.64 rmind * Options -a, -b and -c are mutually exclusive, so allow only one.
407 1.64 rmind * If no options were specified, then set the defaults.
408 1.64 rmind */
409 1.64 rmind optcount = (int)!!use_active + (int)!!conf + (int)!!bconf;
410 1.64 rmind if (optcount != 1) {
411 1.64 rmind if (optcount > 1) {
412 1.64 rmind usage();
413 1.64 rmind }
414 1.64 rmind conf = NPF_CONF_PATH;
415 1.64 rmind outfile = outfile ? outfile : "npf.nvlist";
416 1.64 rmind }
417 1.64 rmind
418 1.64 rmind if (use_active) {
419 1.64 rmind puts("Loading the active configuration");
420 1.64 rmind fd = npfctl_open_dev(NPF_DEV_PATH);
421 1.64 rmind if ((ncf = npf_config_retrieve(fd)) == NULL) {
422 1.65 christos err(EXIT_FAILURE, "npf_config_retrieve: '%s'",
423 1.65 christos NPF_DEV_PATH);
424 1.64 rmind }
425 1.64 rmind }
426 1.64 rmind
427 1.64 rmind if (conf) {
428 1.64 rmind printf("Loading %s\n", conf);
429 1.64 rmind npfctl_parse_file(conf);
430 1.64 rmind npfctl_config_build();
431 1.64 rmind ncf = npfctl_config_ref();
432 1.59 rmind }
433 1.50 christos
434 1.64 rmind if (bconf) {
435 1.64 rmind printf("Importing %s\n", bconf);
436 1.64 rmind ncf = npfctl_import(bconf);
437 1.64 rmind }
438 1.1 rmind
439 1.64 rmind printf("Configuration:\n\n");
440 1.64 rmind _npf_config_dump(ncf, STDOUT_FILENO);
441 1.64 rmind if (outfile) {
442 1.64 rmind printf("\nSaving binary to %s\n", outfile);
443 1.64 rmind npfctl_config_save(ncf, outfile);
444 1.1 rmind }
445 1.64 rmind npf_config_destroy(ncf);
446 1.52 rmind }
447 1.52 rmind
448 1.52 rmind static void
449 1.52 rmind npfctl(int action, int argc, char **argv)
450 1.52 rmind {
451 1.52 rmind int fd, boolval, ret = 0;
452 1.52 rmind const char *fun = "";
453 1.52 rmind nl_config_t *ncf;
454 1.52 rmind
455 1.52 rmind switch (action) {
456 1.52 rmind case NPFCTL_VALIDATE:
457 1.52 rmind case NPFCTL_DEBUG:
458 1.52 rmind fd = 0;
459 1.52 rmind break;
460 1.52 rmind default:
461 1.52 rmind fd = npfctl_open_dev(NPF_DEV_PATH);
462 1.52 rmind }
463 1.29 rmind
464 1.1 rmind switch (action) {
465 1.1 rmind case NPFCTL_START:
466 1.1 rmind boolval = true;
467 1.1 rmind ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
468 1.32 christos fun = "ioctl(IOC_NPF_SWITCH)";
469 1.1 rmind break;
470 1.1 rmind case NPFCTL_STOP:
471 1.1 rmind boolval = false;
472 1.1 rmind ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
473 1.32 christos fun = "ioctl(IOC_NPF_SWITCH)";
474 1.1 rmind break;
475 1.1 rmind case NPFCTL_RELOAD:
476 1.8 rmind npfctl_config_init(false);
477 1.29 rmind npfctl_parse_file(argc < 3 ? NPF_CONF_PATH : argv[2]);
478 1.46 christos npfctl_preload_bpfjit();
479 1.56 rmind errno = ret = npfctl_config_send(fd);
480 1.32 christos fun = "npfctl_config_send";
481 1.1 rmind break;
482 1.11 rmind case NPFCTL_SHOWCONF:
483 1.11 rmind ret = npfctl_config_show(fd);
484 1.32 christos fun = "npfctl_config_show";
485 1.11 rmind break;
486 1.1 rmind case NPFCTL_FLUSH:
487 1.9 rmind ret = npf_config_flush(fd);
488 1.32 christos fun = "npf_config_flush";
489 1.1 rmind break;
490 1.1 rmind case NPFCTL_TABLE:
491 1.21 rmind if ((argc -= 2) < 2) {
492 1.1 rmind usage();
493 1.1 rmind }
494 1.21 rmind argv += 2;
495 1.62 rmind if (strcmp(argv[1], "replace") == 0) {
496 1.62 rmind npfctl_table_replace(fd, argc, argv);
497 1.62 rmind } else {
498 1.62 rmind npfctl_table(fd, argc, argv);
499 1.62 rmind }
500 1.1 rmind break;
501 1.29 rmind case NPFCTL_RULE:
502 1.29 rmind if ((argc -= 2) < 2) {
503 1.29 rmind usage();
504 1.29 rmind }
505 1.29 rmind argv += 2;
506 1.29 rmind npfctl_rule(fd, argc, argv);
507 1.29 rmind break;
508 1.41 rmind case NPFCTL_LOAD:
509 1.44 rmind npfctl_preload_bpfjit();
510 1.41 rmind ret = npfctl_load(fd);
511 1.41 rmind fun = "npfctl_config_load";
512 1.41 rmind break;
513 1.41 rmind case NPFCTL_SAVE:
514 1.48 christos ncf = npf_config_retrieve(fd);
515 1.48 christos if (ncf) {
516 1.64 rmind npfctl_config_save(ncf,
517 1.64 rmind argc > 2 ? argv[2] : NPF_DB_PATH);
518 1.48 christos npf_config_destroy(ncf);
519 1.48 christos } else {
520 1.48 christos ret = errno;
521 1.48 christos }
522 1.41 rmind fun = "npfctl_config_save";
523 1.41 rmind break;
524 1.3 rmind case NPFCTL_STATS:
525 1.3 rmind ret = npfctl_print_stats(fd);
526 1.32 christos fun = "npfctl_print_stats";
527 1.3 rmind break;
528 1.50 christos case NPFCTL_CONN_LIST:
529 1.50 christos ret = npfctl_conn_list(fd, argc, argv);
530 1.50 christos fun = "npfctl_conn_list";
531 1.50 christos break;
532 1.52 rmind case NPFCTL_VALIDATE:
533 1.52 rmind npfctl_config_init(false);
534 1.52 rmind npfctl_parse_file(argc > 2 ? argv[2] : NPF_CONF_PATH);
535 1.52 rmind ret = npfctl_config_show(0);
536 1.52 rmind fun = "npfctl_config_show";
537 1.52 rmind break;
538 1.52 rmind case NPFCTL_DEBUG:
539 1.64 rmind npfctl_debug(argc, argv);
540 1.52 rmind break;
541 1.1 rmind }
542 1.7 zoltan if (ret) {
543 1.32 christos err(EXIT_FAILURE, "%s", fun);
544 1.1 rmind }
545 1.52 rmind if (fd) {
546 1.52 rmind close(fd);
547 1.52 rmind }
548 1.1 rmind }
549 1.1 rmind
550 1.1 rmind int
551 1.1 rmind main(int argc, char **argv)
552 1.1 rmind {
553 1.64 rmind static const struct operations_s {
554 1.64 rmind const char * cmd;
555 1.64 rmind int action;
556 1.64 rmind } operations[] = {
557 1.64 rmind /* Start, stop, reload */
558 1.64 rmind { "start", NPFCTL_START },
559 1.64 rmind { "stop", NPFCTL_STOP },
560 1.64 rmind { "reload", NPFCTL_RELOAD },
561 1.64 rmind { "show", NPFCTL_SHOWCONF, },
562 1.64 rmind { "flush", NPFCTL_FLUSH },
563 1.64 rmind /* Table */
564 1.64 rmind { "table", NPFCTL_TABLE },
565 1.64 rmind /* Rule */
566 1.64 rmind { "rule", NPFCTL_RULE },
567 1.64 rmind /* Stats */
568 1.64 rmind { "stats", NPFCTL_STATS },
569 1.64 rmind /* Full state save/load */
570 1.64 rmind { "save", NPFCTL_SAVE },
571 1.64 rmind { "load", NPFCTL_LOAD },
572 1.64 rmind { "list", NPFCTL_CONN_LIST },
573 1.64 rmind /* Misc. */
574 1.64 rmind { "valid", NPFCTL_VALIDATE },
575 1.64 rmind { "debug", NPFCTL_DEBUG },
576 1.64 rmind /* --- */
577 1.64 rmind { NULL, 0 }
578 1.64 rmind };
579 1.1 rmind char *cmd;
580 1.1 rmind
581 1.1 rmind if (argc < 2) {
582 1.1 rmind usage();
583 1.1 rmind }
584 1.1 rmind cmd = argv[1];
585 1.1 rmind
586 1.12 rmind /* Find and call the subroutine. */
587 1.8 rmind for (int n = 0; operations[n].cmd != NULL; n++) {
588 1.25 rmind const char *opcmd = operations[n].cmd;
589 1.64 rmind
590 1.64 rmind if (strncmp(cmd, opcmd, strlen(opcmd)) != 0) {
591 1.1 rmind continue;
592 1.64 rmind }
593 1.1 rmind npfctl(operations[n].action, argc, argv);
594 1.8 rmind return EXIT_SUCCESS;
595 1.1 rmind }
596 1.3 rmind usage();
597 1.1 rmind }
598