npfctl.c revision 1.60.2.3 1 1.1 rmind /*-
2 1.41 rmind * Copyright (c) 2009-2014 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.60.2.3 martin __RCSID("$NetBSD: npfctl.c,v 1.60.2.3 2020/06/20 15:46:48 martin Exp $");
32 1.2 rmind
33 1.1 rmind #include <sys/types.h>
34 1.60.2.3 martin #include <sys/stat.h>
35 1.60.2.3 martin #include <sys/socket.h>
36 1.48 christos #include <sys/mman.h>
37 1.60.2.3 martin #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.1 rmind #include <string.h>
44 1.60.2.3 martin #include <stdlib.h>
45 1.1 rmind #include <unistd.h>
46 1.60.2.3 martin #include <fcntl.h>
47 1.15 rmind #include <errno.h>
48 1.60.2.3 martin #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.60.2.3 martin 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.60.2.3 martin __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.60.2.2 martin "\t%s table \"table-name\" { add | rem | test } <address/mask>\n",
112 1.60.2.2 martin progname);
113 1.60.2.2 martin fprintf(stderr,
114 1.60.2.2 martin "\t%s table \"table-name\" { list | flush }\n",
115 1.1 rmind progname);
116 1.1 rmind fprintf(stderr,
117 1.60.2.2 martin "\t%s table \"table-name\" replace [-n \"name\"]"
118 1.60.2.2 martin " [-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.60.2.3 martin "\t%s debug { -a | -b <binary-config> | -c <config> } "
128 1.60.2.3 martin "[ -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.17 rmind { NPF_STAT_PASS_DEFAULT, "default pass" },
143 1.17 rmind { NPF_STAT_PASS_RULESET, "ruleset pass" },
144 1.41 rmind { NPF_STAT_PASS_CONN, "state pass" },
145 1.17 rmind
146 1.17 rmind { -1, "Packets blocked" },
147 1.17 rmind { NPF_STAT_BLOCK_DEFAULT, "default block" },
148 1.17 rmind { NPF_STAT_BLOCK_RULESET, "ruleset block" },
149 1.17 rmind
150 1.41 rmind { -1, "State and NAT entries" },
151 1.41 rmind { NPF_STAT_CONN_CREATE, "state allocations"},
152 1.41 rmind { NPF_STAT_CONN_DESTROY, "state destructions"},
153 1.17 rmind { NPF_STAT_NAT_CREATE, "NAT entry allocations" },
154 1.17 rmind { NPF_STAT_NAT_DESTROY, "NAT entry destructions"},
155 1.17 rmind
156 1.27 rmind { -1, "Network buffers" },
157 1.27 rmind { NPF_STAT_NBUF_NONCONTIG, "non-contiguous cases" },
158 1.27 rmind { NPF_STAT_NBUF_CONTIG_FAIL, "contig alloc failures" },
159 1.27 rmind
160 1.17 rmind { -1, "Invalid packet state cases" },
161 1.17 rmind { NPF_STAT_INVALID_STATE, "cases in total" },
162 1.17 rmind { NPF_STAT_INVALID_STATE_TCP1, "TCP case I" },
163 1.17 rmind { NPF_STAT_INVALID_STATE_TCP2, "TCP case II" },
164 1.17 rmind { NPF_STAT_INVALID_STATE_TCP3, "TCP case III" },
165 1.17 rmind
166 1.17 rmind { -1, "Packet race cases" },
167 1.17 rmind { NPF_STAT_RACE_NAT, "NAT association race" },
168 1.41 rmind { NPF_STAT_RACE_CONN, "duplicate state race" },
169 1.17 rmind
170 1.17 rmind { -1, "Fragmentation" },
171 1.17 rmind { NPF_STAT_FRAGMENTS, "fragments" },
172 1.17 rmind { NPF_STAT_REASSEMBLY, "reassembled" },
173 1.17 rmind { NPF_STAT_REASSFAIL, "failed reassembly" },
174 1.17 rmind
175 1.17 rmind { -1, "Other" },
176 1.17 rmind { NPF_STAT_ERROR, "unexpected errors" },
177 1.17 rmind };
178 1.24 rmind uint64_t *st = ecalloc(1, NPF_STATS_SIZE);
179 1.3 rmind
180 1.3 rmind if (ioctl(fd, IOC_NPF_STATS, &st) != 0) {
181 1.3 rmind err(EXIT_FAILURE, "ioctl(IOC_NPF_STATS)");
182 1.3 rmind }
183 1.3 rmind
184 1.17 rmind for (unsigned i = 0; i < __arraycount(stats); i++) {
185 1.17 rmind const char *sname = stats[i].name;
186 1.17 rmind int sidx = stats[i].index;
187 1.17 rmind
188 1.17 rmind if (sidx == -1) {
189 1.17 rmind printf("%s:\n", sname);
190 1.17 rmind } else {
191 1.17 rmind printf("\t%"PRIu64" %s\n", st[sidx], sname);
192 1.17 rmind }
193 1.17 rmind }
194 1.4 rmind
195 1.3 rmind free(st);
196 1.3 rmind return 0;
197 1.3 rmind }
198 1.3 rmind
199 1.10 rmind void
200 1.48 christos npfctl_print_error(const npf_error_t *ne)
201 1.10 rmind {
202 1.48 christos const char *srcfile = ne->source_file;
203 1.10 rmind
204 1.59 rmind if (ne->error_msg) {
205 1.60 rmind errx(EXIT_FAILURE, "%s", ne->error_msg);
206 1.59 rmind }
207 1.10 rmind if (srcfile) {
208 1.48 christos warnx("source %s line %d", srcfile, ne->source_line);
209 1.10 rmind }
210 1.48 christos if (ne->id) {
211 1.48 christos warnx("object: %" PRIi64, ne->id);
212 1.10 rmind }
213 1.10 rmind }
214 1.10 rmind
215 1.21 rmind char *
216 1.50 christos npfctl_print_addrmask(int alen, const char *fmt, const npf_addr_t *addr,
217 1.50 christos npf_netmask_t mask)
218 1.21 rmind {
219 1.50 christos const unsigned buflen = 256;
220 1.48 christos char *buf = ecalloc(1, buflen);
221 1.21 rmind struct sockaddr_storage ss;
222 1.48 christos
223 1.48 christos memset(&ss, 0, sizeof(ss));
224 1.21 rmind
225 1.21 rmind switch (alen) {
226 1.21 rmind case 4: {
227 1.21 rmind struct sockaddr_in *sin = (void *)&ss;
228 1.21 rmind sin->sin_family = AF_INET;
229 1.21 rmind memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr));
230 1.21 rmind break;
231 1.21 rmind }
232 1.21 rmind case 16: {
233 1.21 rmind struct sockaddr_in6 *sin6 = (void *)&ss;
234 1.21 rmind sin6->sin6_family = AF_INET6;
235 1.21 rmind memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr));
236 1.21 rmind break;
237 1.21 rmind }
238 1.21 rmind default:
239 1.60.2.3 martin abort();
240 1.21 rmind }
241 1.50 christos sockaddr_snprintf(buf, buflen, fmt, (const void *)&ss);
242 1.38 rmind if (mask && mask != NPF_NO_NETMASK) {
243 1.48 christos const unsigned len = strlen(buf);
244 1.48 christos snprintf(&buf[len], buflen - len, "/%u", mask);
245 1.21 rmind }
246 1.21 rmind return buf;
247 1.21 rmind }
248 1.21 rmind
249 1.60.2.3 martin bool
250 1.60.2.3 martin npfctl_addr_iszero(const npf_addr_t *addr)
251 1.29 rmind {
252 1.60.2.3 martin static const npf_addr_t zero; /* must be static */
253 1.60.2.3 martin return memcmp(addr, &zero, sizeof(npf_addr_t)) == 0;
254 1.29 rmind }
255 1.29 rmind
256 1.45 christos static bool bpfjit = true;
257 1.45 christos
258 1.45 christos void
259 1.45 christos npfctl_bpfjit(bool onoff)
260 1.45 christos {
261 1.45 christos bpfjit = onoff;
262 1.45 christos }
263 1.45 christos
264 1.44 rmind static void
265 1.44 rmind npfctl_preload_bpfjit(void)
266 1.44 rmind {
267 1.48 christos #ifdef __NetBSD__
268 1.44 rmind modctl_load_t args = {
269 1.44 rmind .ml_filename = "bpfjit",
270 1.44 rmind .ml_flags = MODCTL_NO_PROP,
271 1.44 rmind .ml_props = NULL,
272 1.44 rmind .ml_propslen = 0
273 1.44 rmind };
274 1.44 rmind
275 1.45 christos if (!bpfjit)
276 1.45 christos return;
277 1.45 christos
278 1.44 rmind if (modctl(MODCTL_LOAD, &args) != 0 && errno != EEXIST) {
279 1.45 christos static const char *p = "; performance will be degraded";
280 1.45 christos if (errno == ENOENT)
281 1.45 christos warnx("the bpfjit module seems to be missing%s", p);
282 1.45 christos else
283 1.45 christos warn("error loading the bpfjit module%s", p);
284 1.45 christos warnx("To disable this warning `set bpf.jit off' in "
285 1.45 christos "/etc/npf.conf");
286 1.44 rmind }
287 1.48 christos #endif
288 1.44 rmind }
289 1.44 rmind
290 1.60.2.3 martin static nl_config_t *
291 1.60.2.3 martin npfctl_import(const char *path)
292 1.41 rmind {
293 1.41 rmind nl_config_t *ncf;
294 1.48 christos struct stat sb;
295 1.48 christos size_t blen;
296 1.48 christos void *blob;
297 1.60.2.3 martin int fd;
298 1.41 rmind
299 1.48 christos /*
300 1.48 christos * The file may change while reading - we are not handling this,
301 1.60.2.3 martin * just leaving this responsibility for the caller.
302 1.48 christos */
303 1.60.2.3 martin if ((fd = open(path, O_RDONLY)) == -1) {
304 1.60.2.3 martin err(EXIT_FAILURE, "could not open `%s'", path);
305 1.60.2.3 martin }
306 1.60.2.3 martin if (fstat(fd, &sb) == -1) {
307 1.48 christos err(EXIT_FAILURE, "stat");
308 1.48 christos }
309 1.48 christos if ((blen = sb.st_size) == 0) {
310 1.60.2.3 martin err(EXIT_FAILURE, "the binary configuration file is empty");
311 1.48 christos }
312 1.60.2.3 martin blob = mmap(NULL, blen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
313 1.60.2.3 martin if (blob == MAP_FAILED) {
314 1.48 christos err(EXIT_FAILURE, "mmap");
315 1.48 christos }
316 1.48 christos ncf = npf_config_import(blob, blen);
317 1.48 christos munmap(blob, blen);
318 1.60.2.3 martin return ncf;
319 1.60.2.3 martin }
320 1.60.2.3 martin
321 1.60.2.3 martin static int
322 1.60.2.3 martin npfctl_load(int fd)
323 1.60.2.3 martin {
324 1.60.2.3 martin nl_config_t *ncf;
325 1.60.2.3 martin npf_error_t errinfo;
326 1.41 rmind
327 1.48 christos /*
328 1.60.2.3 martin * Import the configuration, submit it and destroy.
329 1.60.2.3 martin */
330 1.60.2.3 martin ncf = npfctl_import(NPF_DB_PATH);
331 1.60.2.3 martin if (ncf == NULL) {
332 1.60.2.3 martin err(EXIT_FAILURE, "npf_config_import");
333 1.60.2.3 martin }
334 1.60.2.3 martin if ((errno = npf_config_submit(ncf, fd, &errinfo)) != 0) {
335 1.48 christos npfctl_print_error(&errinfo);
336 1.43 rmind }
337 1.41 rmind npf_config_destroy(ncf);
338 1.60.2.3 martin return errno;
339 1.41 rmind }
340 1.41 rmind
341 1.50 christos static int
342 1.60.2.3 martin npfctl_open_dev(const char *path)
343 1.50 christos {
344 1.60.2.3 martin struct stat st;
345 1.60.2.3 martin int fd;
346 1.59 rmind
347 1.60.2.3 martin if (lstat(path, &st) == -1) {
348 1.60.2.3 martin err(EXIT_FAILURE, "fstat");
349 1.59 rmind }
350 1.60.2.3 martin if ((st.st_mode & S_IFMT) == S_IFSOCK) {
351 1.60.2.3 martin struct sockaddr_un addr;
352 1.60.2.3 martin
353 1.60.2.3 martin if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
354 1.60.2.3 martin err(EXIT_FAILURE, "socket");
355 1.60.2.3 martin }
356 1.60.2.3 martin memset(&addr, 0, sizeof(addr));
357 1.60.2.3 martin addr.sun_family = AF_UNIX;
358 1.60.2.3 martin strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
359 1.60.2.3 martin
360 1.60.2.3 martin if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
361 1.60.2.3 martin err(EXIT_FAILURE, "connect");
362 1.60.2.3 martin }
363 1.60.2.3 martin } else {
364 1.60.2.3 martin if ((fd = open(path, O_RDONLY)) == -1) {
365 1.60.2.3 martin err(EXIT_FAILURE, "cannot open '%s'", path);
366 1.60.2.3 martin }
367 1.50 christos }
368 1.60.2.3 martin return fd;
369 1.50 christos }
370 1.50 christos
371 1.60.2.3 martin static void
372 1.60.2.3 martin npfctl_debug(int argc, char **argv)
373 1.50 christos {
374 1.60.2.3 martin const char *conf = NULL, *bconf = NULL, *outfile = NULL;
375 1.60.2.3 martin bool use_active = false;
376 1.60.2.3 martin nl_config_t *ncf = NULL;
377 1.60.2.3 martin int fd, c, optcount;
378 1.59 rmind
379 1.50 christos argc--;
380 1.50 christos argv++;
381 1.50 christos
382 1.60.2.3 martin npfctl_config_init(true);
383 1.60.2.3 martin while ((c = getopt(argc, argv, "ab:c:o:")) != -1) {
384 1.50 christos switch (c) {
385 1.60.2.3 martin case 'a':
386 1.60.2.3 martin use_active = true;
387 1.58 mrg break;
388 1.60.2.3 martin case 'b':
389 1.60.2.3 martin bconf = optarg;
390 1.50 christos break;
391 1.60.2.3 martin case 'c':
392 1.60.2.3 martin conf = optarg;
393 1.50 christos break;
394 1.60.2.3 martin case 'o':
395 1.60.2.3 martin outfile = optarg;
396 1.50 christos break;
397 1.50 christos default:
398 1.60.2.3 martin usage();
399 1.50 christos }
400 1.50 christos }
401 1.59 rmind
402 1.60.2.3 martin /*
403 1.60.2.3 martin * Options -a, -b and -c are mutually exclusive, so allow only one.
404 1.60.2.3 martin * If no options were specified, then set the defaults.
405 1.60.2.3 martin */
406 1.60.2.3 martin optcount = (int)!!use_active + (int)!!conf + (int)!!bconf;
407 1.60.2.3 martin if (optcount != 1) {
408 1.60.2.3 martin if (optcount > 1) {
409 1.60.2.3 martin usage();
410 1.60.2.3 martin }
411 1.60.2.3 martin conf = NPF_CONF_PATH;
412 1.60.2.3 martin outfile = outfile ? outfile : "npf.nvlist";
413 1.59 rmind }
414 1.50 christos
415 1.60.2.3 martin if (use_active) {
416 1.60.2.3 martin puts("Loading the active configuration");
417 1.60.2.3 martin fd = npfctl_open_dev(NPF_DEV_PATH);
418 1.60.2.3 martin if ((ncf = npf_config_retrieve(fd)) == NULL) {
419 1.60.2.3 martin err(EXIT_FAILURE, "npf_config_retrieve");
420 1.60.2.3 martin }
421 1.60.2.3 martin }
422 1.1 rmind
423 1.60.2.3 martin if (conf) {
424 1.60.2.3 martin printf("Loading %s\n", conf);
425 1.60.2.3 martin npfctl_parse_file(conf);
426 1.60.2.3 martin npfctl_config_build();
427 1.60.2.3 martin ncf = npfctl_config_ref();
428 1.1 rmind }
429 1.60.2.3 martin
430 1.60.2.3 martin if (bconf) {
431 1.60.2.3 martin printf("Importing %s\n", bconf);
432 1.60.2.3 martin ncf = npfctl_import(bconf);
433 1.60.2.3 martin }
434 1.60.2.3 martin
435 1.60.2.3 martin printf("Configuration:\n\n");
436 1.60.2.3 martin _npf_config_dump(ncf, STDOUT_FILENO);
437 1.60.2.3 martin if (outfile) {
438 1.60.2.3 martin printf("\nSaving binary to %s\n", outfile);
439 1.60.2.3 martin npfctl_config_save(ncf, outfile);
440 1.60.2.3 martin }
441 1.60.2.3 martin npf_config_destroy(ncf);
442 1.52 rmind }
443 1.52 rmind
444 1.52 rmind static void
445 1.52 rmind npfctl(int action, int argc, char **argv)
446 1.52 rmind {
447 1.52 rmind int fd, boolval, ret = 0;
448 1.52 rmind const char *fun = "";
449 1.52 rmind nl_config_t *ncf;
450 1.52 rmind
451 1.52 rmind switch (action) {
452 1.52 rmind case NPFCTL_VALIDATE:
453 1.52 rmind case NPFCTL_DEBUG:
454 1.52 rmind fd = 0;
455 1.52 rmind break;
456 1.52 rmind default:
457 1.52 rmind fd = npfctl_open_dev(NPF_DEV_PATH);
458 1.52 rmind }
459 1.29 rmind
460 1.1 rmind switch (action) {
461 1.1 rmind case NPFCTL_START:
462 1.1 rmind boolval = true;
463 1.1 rmind ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
464 1.32 christos fun = "ioctl(IOC_NPF_SWITCH)";
465 1.1 rmind break;
466 1.1 rmind case NPFCTL_STOP:
467 1.1 rmind boolval = false;
468 1.1 rmind ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
469 1.32 christos fun = "ioctl(IOC_NPF_SWITCH)";
470 1.1 rmind break;
471 1.1 rmind case NPFCTL_RELOAD:
472 1.8 rmind npfctl_config_init(false);
473 1.29 rmind npfctl_parse_file(argc < 3 ? NPF_CONF_PATH : argv[2]);
474 1.46 christos npfctl_preload_bpfjit();
475 1.56 rmind errno = ret = npfctl_config_send(fd);
476 1.32 christos fun = "npfctl_config_send";
477 1.1 rmind break;
478 1.11 rmind case NPFCTL_SHOWCONF:
479 1.11 rmind ret = npfctl_config_show(fd);
480 1.32 christos fun = "npfctl_config_show";
481 1.11 rmind break;
482 1.1 rmind case NPFCTL_FLUSH:
483 1.9 rmind ret = npf_config_flush(fd);
484 1.32 christos fun = "npf_config_flush";
485 1.1 rmind break;
486 1.1 rmind case NPFCTL_TABLE:
487 1.21 rmind if ((argc -= 2) < 2) {
488 1.1 rmind usage();
489 1.1 rmind }
490 1.21 rmind argv += 2;
491 1.60.2.2 martin if (strcmp(argv[1], "replace") == 0) {
492 1.60.2.2 martin npfctl_table_replace(fd, argc, argv);
493 1.60.2.2 martin } else {
494 1.60.2.2 martin npfctl_table(fd, argc, argv);
495 1.60.2.2 martin }
496 1.1 rmind break;
497 1.29 rmind case NPFCTL_RULE:
498 1.29 rmind if ((argc -= 2) < 2) {
499 1.29 rmind usage();
500 1.29 rmind }
501 1.29 rmind argv += 2;
502 1.29 rmind npfctl_rule(fd, argc, argv);
503 1.29 rmind break;
504 1.41 rmind case NPFCTL_LOAD:
505 1.44 rmind npfctl_preload_bpfjit();
506 1.41 rmind ret = npfctl_load(fd);
507 1.41 rmind fun = "npfctl_config_load";
508 1.41 rmind break;
509 1.41 rmind case NPFCTL_SAVE:
510 1.48 christos ncf = npf_config_retrieve(fd);
511 1.48 christos if (ncf) {
512 1.60.2.3 martin npfctl_config_save(ncf,
513 1.60.2.3 martin argc > 2 ? argv[2] : NPF_DB_PATH);
514 1.48 christos npf_config_destroy(ncf);
515 1.48 christos } else {
516 1.48 christos ret = errno;
517 1.48 christos }
518 1.41 rmind fun = "npfctl_config_save";
519 1.41 rmind break;
520 1.3 rmind case NPFCTL_STATS:
521 1.3 rmind ret = npfctl_print_stats(fd);
522 1.32 christos fun = "npfctl_print_stats";
523 1.3 rmind break;
524 1.50 christos case NPFCTL_CONN_LIST:
525 1.50 christos ret = npfctl_conn_list(fd, argc, argv);
526 1.50 christos fun = "npfctl_conn_list";
527 1.50 christos break;
528 1.52 rmind case NPFCTL_VALIDATE:
529 1.52 rmind npfctl_config_init(false);
530 1.52 rmind npfctl_parse_file(argc > 2 ? argv[2] : NPF_CONF_PATH);
531 1.52 rmind ret = npfctl_config_show(0);
532 1.52 rmind fun = "npfctl_config_show";
533 1.52 rmind break;
534 1.52 rmind case NPFCTL_DEBUG:
535 1.60.2.3 martin npfctl_debug(argc, argv);
536 1.52 rmind break;
537 1.1 rmind }
538 1.7 zoltan if (ret) {
539 1.32 christos err(EXIT_FAILURE, "%s", fun);
540 1.1 rmind }
541 1.52 rmind if (fd) {
542 1.52 rmind close(fd);
543 1.52 rmind }
544 1.1 rmind }
545 1.1 rmind
546 1.1 rmind int
547 1.1 rmind main(int argc, char **argv)
548 1.1 rmind {
549 1.60.2.3 martin static const struct operations_s {
550 1.60.2.3 martin const char * cmd;
551 1.60.2.3 martin int action;
552 1.60.2.3 martin } operations[] = {
553 1.60.2.3 martin /* Start, stop, reload */
554 1.60.2.3 martin { "start", NPFCTL_START },
555 1.60.2.3 martin { "stop", NPFCTL_STOP },
556 1.60.2.3 martin { "reload", NPFCTL_RELOAD },
557 1.60.2.3 martin { "show", NPFCTL_SHOWCONF, },
558 1.60.2.3 martin { "flush", NPFCTL_FLUSH },
559 1.60.2.3 martin /* Table */
560 1.60.2.3 martin { "table", NPFCTL_TABLE },
561 1.60.2.3 martin /* Rule */
562 1.60.2.3 martin { "rule", NPFCTL_RULE },
563 1.60.2.3 martin /* Stats */
564 1.60.2.3 martin { "stats", NPFCTL_STATS },
565 1.60.2.3 martin /* Full state save/load */
566 1.60.2.3 martin { "save", NPFCTL_SAVE },
567 1.60.2.3 martin { "load", NPFCTL_LOAD },
568 1.60.2.3 martin { "list", NPFCTL_CONN_LIST },
569 1.60.2.3 martin /* Misc. */
570 1.60.2.3 martin { "valid", NPFCTL_VALIDATE },
571 1.60.2.3 martin { "debug", NPFCTL_DEBUG },
572 1.60.2.3 martin /* --- */
573 1.60.2.3 martin { NULL, 0 }
574 1.60.2.3 martin };
575 1.1 rmind char *cmd;
576 1.1 rmind
577 1.1 rmind if (argc < 2) {
578 1.1 rmind usage();
579 1.1 rmind }
580 1.1 rmind cmd = argv[1];
581 1.1 rmind
582 1.12 rmind /* Find and call the subroutine. */
583 1.8 rmind for (int n = 0; operations[n].cmd != NULL; n++) {
584 1.25 rmind const char *opcmd = operations[n].cmd;
585 1.60.2.3 martin
586 1.60.2.3 martin if (strncmp(cmd, opcmd, strlen(opcmd)) != 0) {
587 1.1 rmind continue;
588 1.60.2.3 martin }
589 1.1 rmind npfctl(operations[n].action, argc, argv);
590 1.8 rmind return EXIT_SUCCESS;
591 1.1 rmind }
592 1.3 rmind usage();
593 1.1 rmind }
594