1 /* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2001 Daniel Hartmeier
7 * Copyright (c) 2002,2003 Henning Brauer
8 * All rights reserved.
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 *
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36 #include <sys/cdefs.h>
37 #define PFIOC_USE_LATEST
38
39 #include <sys/types.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <sys/endian.h>
44
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <net/pfvar.h>
48 #include <arpa/inet.h>
49 #include <net/altq/altq.h>
50
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <libpfctl.h>
55 #include <limits.h>
56 #include <netdb.h>
57 #include <stdint.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62 #include <stdarg.h>
63 #include <libgen.h>
64
65 #include "pfctl_parser.h"
66 #include "pfctl.h"
67
68 void usage(void);
69 int pfctl_enable(int, int);
70 int pfctl_disable(int, int);
71 void pfctl_clear_stats(struct pfctl_handle *, int);
72 void pfctl_get_skip_ifaces(void);
73 void pfctl_check_skip_ifaces(char *);
74 void pfctl_adjust_skip_ifaces(struct pfctl *);
75 void pfctl_clear_interface_flags(int, int);
76 void pfctl_flush_eth_rules(int, int, char *);
77 int pfctl_flush_rules(int, int, char *);
78 void pfctl_flush_nat(int, int, char *);
79 int pfctl_clear_altq(int, int);
80 void pfctl_clear_src_nodes(int, int);
81 void pfctl_clear_iface_states(int, const char *, int);
82 struct addrinfo *
83 pfctl_addrprefix(char *, struct pf_addr *, int);
84 void pfctl_kill_src_nodes(int, int);
85 void pfctl_net_kill_states(int, const char *, int);
86 void pfctl_gateway_kill_states(int, const char *, int);
87 void pfctl_label_kill_states(int, const char *, int);
88 void pfctl_id_kill_states(int, const char *, int);
89 void pfctl_key_kill_states(int, const char *, int);
90 int pfctl_parse_host(char *, struct pf_rule_addr *);
91 void pfctl_init_options(struct pfctl *);
92 int pfctl_load_options(struct pfctl *);
93 int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
94 int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
95 int pfctl_load_debug(struct pfctl *, unsigned int);
96 int pfctl_load_logif(struct pfctl *, char *);
97 int pfctl_load_hostid(struct pfctl *, u_int32_t);
98 int pfctl_load_reassembly(struct pfctl *, u_int32_t);
99 int pfctl_load_syncookies(struct pfctl *, u_int8_t);
100 int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int,
101 const char *, int);
102 void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int);
103 void pfctl_print_rule_counters(struct pfctl_rule *, int);
104 int pfctl_show_eth_rules(int, char *, int, enum pfctl_show, char *, int, int);
105 int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int, int);
106 int pfctl_show_nat(int, const char *, int, char *, int, int);
107 int pfctl_show_src_nodes(int, int);
108 int pfctl_show_states(int, const char *, int);
109 int pfctl_show_status(int, int);
110 int pfctl_show_running(int);
111 int pfctl_show_timeouts(int, int);
112 int pfctl_show_limits(int, int);
113 void pfctl_debug(int, u_int32_t, int);
114 int pfctl_test_altqsupport(int, int);
115 int pfctl_show_anchors(int, int, char *);
116 int pfctl_show_eth_anchors(int, int, char *);
117 int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *, bool);
118 int pfctl_eth_ruleset_trans(struct pfctl *, char *,
119 struct pfctl_eth_anchor *);
120 int pfctl_load_eth_ruleset(struct pfctl *, char *,
121 struct pfctl_eth_ruleset *, int);
122 int pfctl_load_eth_rule(struct pfctl *, char *, struct pfctl_eth_rule *,
123 int);
124 int pfctl_load_ruleset(struct pfctl *, char *,
125 struct pfctl_ruleset *, int, int);
126 int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int);
127 const char *pfctl_lookup_option(char *, const char * const *);
128 void pfctl_reset(int, int);
129 int pfctl_walk_show(int, struct pfioc_ruleset *, void *);
130 int pfctl_walk_get(int, struct pfioc_ruleset *, void *);
131 int pfctl_walk_anchors(int, int, const char *,
132 int(*)(int, struct pfioc_ruleset *, void *), void *);
133 struct pfr_anchors *
134 pfctl_get_anchors(int, const char *, int);
135 int pfctl_recurse(int, int, const char *,
136 int(*)(int, int, struct pfr_anchoritem *));
137 int pfctl_call_clearrules(int, int, struct pfr_anchoritem *);
138 int pfctl_call_cleartables(int, int, struct pfr_anchoritem *);
139 int pfctl_call_clearanchors(int, int, struct pfr_anchoritem *);
140 int pfctl_call_showtables(int, int, struct pfr_anchoritem *);
141
142 static struct pfctl_anchor_global pf_anchors;
143 struct pfctl_anchor pf_main_anchor;
144 struct pfctl_eth_anchor pf_eth_main_anchor;
145 static struct pfr_buffer skip_b;
146
147 static const char *clearopt;
148 static char *rulesopt;
149 static const char *showopt;
150 static const char *debugopt;
151 static char *anchoropt;
152 static const char *optiopt = NULL;
153 static const char *pf_device = PF_DEVICE;
154 static char *ifaceopt;
155 static char *tableopt;
156 static const char *tblcmdopt;
157 static int src_node_killers;
158 static char *src_node_kill[2];
159 static int state_killers;
160 static char *state_kill[2];
161 int loadopt;
162 int altqsupport;
163
164 int dev = -1;
165 struct pfctl_handle *pfh = NULL;
166 static int first_title = 1;
167 static int labels = 0;
168 static int exit_val = 0;
169
170 #define INDENT(d, o) do { \
171 if (o) { \
172 int i; \
173 for (i=0; i < d; i++) \
174 printf(" "); \
175 } \
176 } while (0); \
177
178
179 static const struct {
180 const char *name;
181 int index;
182 } pf_limits[] = {
183 { "states", PF_LIMIT_STATES },
184 { "src-nodes", PF_LIMIT_SRC_NODES },
185 { "frags", PF_LIMIT_FRAGS },
186 { "table-entries", PF_LIMIT_TABLE_ENTRIES },
187 { "anchors", PF_LIMIT_ANCHORS },
188 { "eth-anchors", PF_LIMIT_ETH_ANCHORS },
189 { NULL, 0 }
190 };
191
192 struct pf_hint {
193 const char *name;
194 int timeout;
195 };
196 static const struct pf_hint pf_hint_normal[] = {
197 { "tcp.first", 2 * 60 },
198 { "tcp.opening", 30 },
199 { "tcp.established", 24 * 60 * 60 },
200 { "tcp.closing", 15 * 60 },
201 { "tcp.finwait", 45 },
202 { "tcp.closed", 90 },
203 { "tcp.tsdiff", 30 },
204 { NULL, 0 }
205 };
206 static const struct pf_hint pf_hint_satellite[] = {
207 { "tcp.first", 3 * 60 },
208 { "tcp.opening", 30 + 5 },
209 { "tcp.established", 24 * 60 * 60 },
210 { "tcp.closing", 15 * 60 + 5 },
211 { "tcp.finwait", 45 + 5 },
212 { "tcp.closed", 90 + 5 },
213 { "tcp.tsdiff", 60 },
214 { NULL, 0 }
215 };
216 static const struct pf_hint pf_hint_conservative[] = {
217 { "tcp.first", 60 * 60 },
218 { "tcp.opening", 15 * 60 },
219 { "tcp.established", 5 * 24 * 60 * 60 },
220 { "tcp.closing", 60 * 60 },
221 { "tcp.finwait", 10 * 60 },
222 { "tcp.closed", 3 * 60 },
223 { "tcp.tsdiff", 60 },
224 { NULL, 0 }
225 };
226 static const struct pf_hint pf_hint_aggressive[] = {
227 { "tcp.first", 30 },
228 { "tcp.opening", 5 },
229 { "tcp.established", 5 * 60 * 60 },
230 { "tcp.closing", 60 },
231 { "tcp.finwait", 30 },
232 { "tcp.closed", 30 },
233 { "tcp.tsdiff", 10 },
234 { NULL, 0 }
235 };
236
237 static const struct {
238 const char *name;
239 const struct pf_hint *hint;
240 } pf_hints[] = {
241 { "normal", pf_hint_normal },
242 { "satellite", pf_hint_satellite },
243 { "high-latency", pf_hint_satellite },
244 { "conservative", pf_hint_conservative },
245 { "aggressive", pf_hint_aggressive },
246 { NULL, NULL }
247 };
248
249 static const char * const clearopt_list[] = {
250 "nat", "queue", "rules", "Sources",
251 "states", "info", "Tables", "osfp", "all",
252 "ethernet", "Reset", NULL
253 };
254
255 static const char * const showopt_list[] = {
256 "ether", "nat", "queue", "rules", "Anchors", "Sources", "states",
257 "info", "Interfaces", "labels", "timeouts", "memory", "Tables",
258 "osfp", "Running", "all", "creatorids", NULL
259 };
260
261 static const char * const tblcmdopt_list[] = {
262 "kill", "flush", "add", "delete", "load", "replace", "show",
263 "test", "zero", "expire", "reset", NULL
264 };
265
266 static const char * const debugopt_list[] = {
267 "none", "urgent", "misc", "loud", NULL
268 };
269
270 static const char * const optiopt_list[] = {
271 "none", "basic", "profile", NULL
272 };
273
274 void
usage(void)275 usage(void)
276 {
277 extern char *__progname;
278
279 fprintf(stderr,
280 "usage: %s [-AdeghMmNnOPqRSrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
281 "\t[-f file] [-i interface] [-K host | network]\n"
282 "\t[-k host | network | gateway | label | id] [-o level] [-p device]\n"
283 "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
284 __progname);
285
286 exit(1);
287 }
288
289 void
pfctl_err(int opts,int eval,const char * fmt,...)290 pfctl_err(int opts, int eval, const char *fmt, ...)
291 {
292 va_list ap;
293
294 va_start(ap, fmt);
295
296 if ((opts & PF_OPT_IGNFAIL) == 0)
297 verr(eval, fmt, ap);
298 else
299 vwarn(fmt, ap);
300
301 va_end(ap);
302
303 exit_val = eval;
304 }
305
306 void
pfctl_errx(int opts,int eval,const char * fmt,...)307 pfctl_errx(int opts, int eval, const char *fmt, ...)
308 {
309 va_list ap;
310
311 va_start(ap, fmt);
312
313 if ((opts & PF_OPT_IGNFAIL) == 0)
314 verrx(eval, fmt, ap);
315 else
316 vwarnx(fmt, ap);
317
318 va_end(ap);
319
320 exit_val = eval;
321 }
322
323 /*
324 * Cache protocol number to name translations.
325 *
326 * Translation is performed a lot e.g., when dumping states and
327 * getprotobynumber is incredibly expensive.
328 *
329 * Note from the getprotobynumber(3) manpage:
330 * <quote>
331 * These functions use a thread-specific data space; if the data is needed
332 * for future use, it should be copied before any subsequent calls overwrite
333 * it. Only the Internet protocols are currently understood.
334 * </quote>
335 *
336 * Consequently we only cache the name and strdup it for safety.
337 *
338 * At the time of writing this comment the last entry in /etc/protocols is:
339 * divert 258 DIVERT # Divert pseudo-protocol [non IANA]
340 */
341 const char *
pfctl_proto2name(int proto)342 pfctl_proto2name(int proto)
343 {
344 static const char *pfctl_proto_cache[259];
345 struct protoent *p;
346
347 if (proto >= nitems(pfctl_proto_cache)) {
348 p = getprotobynumber(proto);
349 if (p == NULL) {
350 return (NULL);
351 }
352 return (p->p_name);
353 }
354
355 if (pfctl_proto_cache[proto] == NULL) {
356 p = getprotobynumber(proto);
357 if (p == NULL) {
358 return (NULL);
359 }
360 pfctl_proto_cache[proto] = strdup(p->p_name);
361 }
362
363 return (pfctl_proto_cache[proto]);
364 }
365
366 int
pfctl_enable(int dev,int opts)367 pfctl_enable(int dev, int opts)
368 {
369 int ret;
370
371 if ((ret = pfctl_startstop(pfh, 1)) != 0) {
372 if (ret == EEXIST)
373 errx(1, "pf already enabled");
374 else if (ret == ESRCH)
375 errx(1, "pfil registeration failed");
376 else
377 errc(1, ret, "DIOCSTART");
378 }
379 if ((opts & PF_OPT_QUIET) == 0)
380 fprintf(stderr, "pf enabled\n");
381
382 if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
383 if (errno != EEXIST)
384 err(1, "DIOCSTARTALTQ");
385
386 return (0);
387 }
388
389 int
pfctl_disable(int dev,int opts)390 pfctl_disable(int dev, int opts)
391 {
392 int ret;
393
394 if ((ret = pfctl_startstop(pfh, 0)) != 0) {
395 if (ret == ENOENT)
396 errx(1, "pf not enabled");
397 else
398 errc(1, ret, "DIOCSTOP");
399 }
400 if ((opts & PF_OPT_QUIET) == 0)
401 fprintf(stderr, "pf disabled\n");
402
403 if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
404 if (errno != ENOENT)
405 err(1, "DIOCSTOPALTQ");
406
407 return (0);
408 }
409
410 void
pfctl_clear_stats(struct pfctl_handle * h,int opts)411 pfctl_clear_stats(struct pfctl_handle *h, int opts)
412 {
413 int ret;
414 if ((ret = pfctl_clear_status(h)) != 0)
415 pfctl_err(opts, 1, "DIOCCLRSTATUS");
416 if ((opts & PF_OPT_QUIET) == 0)
417 fprintf(stderr, "pf: statistics cleared\n");
418 }
419
420 void
pfctl_get_skip_ifaces(void)421 pfctl_get_skip_ifaces(void)
422 {
423 bzero(&skip_b, sizeof(skip_b));
424 skip_b.pfrb_type = PFRB_IFACES;
425 for (;;) {
426 pfr_buf_grow(&skip_b, skip_b.pfrb_size);
427 skip_b.pfrb_size = skip_b.pfrb_msize;
428 if (pfi_get_ifaces(NULL, skip_b.pfrb_caddr, &skip_b.pfrb_size))
429 err(1, "pfi_get_ifaces");
430 if (skip_b.pfrb_size <= skip_b.pfrb_msize)
431 break;
432 }
433 }
434
435 void
pfctl_check_skip_ifaces(char * ifname)436 pfctl_check_skip_ifaces(char *ifname)
437 {
438 struct pfi_kif *p;
439 struct node_host *h = NULL, *n = NULL;
440
441 PFRB_FOREACH(p, &skip_b) {
442 if (!strcmp(ifname, p->pfik_name) &&
443 (p->pfik_flags & PFI_IFLAG_SKIP))
444 p->pfik_flags &= ~PFI_IFLAG_SKIP;
445 if (!strcmp(ifname, p->pfik_name) && p->pfik_group != NULL) {
446 if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL)
447 continue;
448
449 for (n = h; n != NULL; n = n->next) {
450 if (strncmp(p->pfik_name, ifname, IFNAMSIZ))
451 continue;
452
453 p->pfik_flags &= ~PFI_IFLAG_SKIP;
454 }
455 }
456 }
457 }
458
459 void
pfctl_adjust_skip_ifaces(struct pfctl * pf)460 pfctl_adjust_skip_ifaces(struct pfctl *pf)
461 {
462 struct pfi_kif *p, *pp;
463 struct node_host *h = NULL, *n = NULL;
464
465 PFRB_FOREACH(p, &skip_b) {
466 if (p->pfik_group == NULL || !(p->pfik_flags & PFI_IFLAG_SKIP))
467 continue;
468
469 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0);
470 if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL)
471 continue;
472
473 for (n = h; n != NULL; n = n->next)
474 PFRB_FOREACH(pp, &skip_b) {
475 if (strncmp(pp->pfik_name, n->ifname, IFNAMSIZ))
476 continue;
477
478 if (!(pp->pfik_flags & PFI_IFLAG_SKIP))
479 pfctl_set_interface_flags(pf,
480 pp->pfik_name, PFI_IFLAG_SKIP, 1);
481 if (pp->pfik_flags & PFI_IFLAG_SKIP)
482 pp->pfik_flags &= ~PFI_IFLAG_SKIP;
483 }
484 }
485
486 PFRB_FOREACH(p, &skip_b) {
487 if (! (p->pfik_flags & PFI_IFLAG_SKIP))
488 continue;
489
490 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0);
491 }
492 }
493
494 void
pfctl_clear_interface_flags(int dev,int opts)495 pfctl_clear_interface_flags(int dev, int opts)
496 {
497 struct pfioc_iface pi;
498
499 if ((opts & PF_OPT_NOACTION) == 0) {
500 bzero(&pi, sizeof(pi));
501 pi.pfiio_flags = PFI_IFLAG_SKIP;
502
503 if (ioctl(dev, DIOCCLRIFFLAG, &pi))
504 err(1, "DIOCCLRIFFLAG");
505 if ((opts & PF_OPT_QUIET) == 0)
506 fprintf(stderr, "pf: interface flags reset\n");
507 }
508 }
509
510 void
pfctl_flush_eth_rules(int dev,int opts,char * anchorname)511 pfctl_flush_eth_rules(int dev, int opts, char *anchorname)
512 {
513 int ret;
514
515 ret = pfctl_clear_eth_rules(dev, anchorname);
516 if (ret != 0)
517 err(1, "pfctl_clear_eth_rules");
518
519 if ((opts & PF_OPT_QUIET) == 0)
520 fprintf(stderr, "Ethernet rules cleared\n");
521 }
522
523 int
pfctl_flush_rules(int dev,int opts,char * anchorname)524 pfctl_flush_rules(int dev, int opts, char *anchorname)
525 {
526 int ret;
527
528 ret = pfctl_clear_rules(dev, anchorname);
529 if (ret != 0) {
530 pfctl_err(opts, 1, "%s", __func__);
531 return (1);
532 } else if ((opts & PF_OPT_QUIET) == 0)
533 fprintf(stderr, "rules cleared\n");
534
535 return (0);
536 }
537
538 void
pfctl_flush_nat(int dev,int opts,char * anchorname)539 pfctl_flush_nat(int dev, int opts, char *anchorname)
540 {
541 int ret;
542
543 ret = pfctl_clear_nat(dev, anchorname);
544 if (ret != 0)
545 err(1, "pfctl_clear_nat");
546 if ((opts & PF_OPT_QUIET) == 0)
547 fprintf(stderr, "nat cleared\n");
548 }
549
550 int
pfctl_clear_altq(int dev,int opts)551 pfctl_clear_altq(int dev, int opts)
552 {
553 struct pfr_buffer t;
554
555 if (!altqsupport)
556 return (-1);
557 memset(&t, 0, sizeof(t));
558 t.pfrb_type = PFRB_TRANS;
559 if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
560 pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
561 pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
562 err(1, "pfctl_clear_altq");
563 if ((opts & PF_OPT_QUIET) == 0)
564 fprintf(stderr, "altq cleared\n");
565 return (0);
566 }
567
568 void
pfctl_clear_src_nodes(int dev,int opts)569 pfctl_clear_src_nodes(int dev, int opts)
570 {
571 if (ioctl(dev, DIOCCLRSRCNODES))
572 pfctl_err(opts, 1, "DIOCCLRSRCNODES");
573 if ((opts & PF_OPT_QUIET) == 0)
574 fprintf(stderr, "source tracking entries cleared\n");
575 }
576
577 void
pfctl_clear_iface_states(int dev,const char * iface,int opts)578 pfctl_clear_iface_states(int dev, const char *iface, int opts)
579 {
580 struct pfctl_kill kill;
581 unsigned int killed;
582 int ret;
583
584 memset(&kill, 0, sizeof(kill));
585 if (iface != NULL && strlcpy(kill.ifname, iface,
586 sizeof(kill.ifname)) >= sizeof(kill.ifname))
587 pfctl_errx(opts, 1, "invalid interface: %s", iface);
588
589 if (opts & PF_OPT_KILLMATCH)
590 kill.kill_match = true;
591
592 if ((ret = pfctl_clear_states_h(pfh, &kill, &killed)) != 0)
593 pfctl_err(opts, 1, "DIOCCLRSTATUS");
594 if ((opts & PF_OPT_QUIET) == 0)
595 fprintf(stderr, "%d states cleared\n", killed);
596 }
597
598 struct addrinfo *
pfctl_addrprefix(char * addr,struct pf_addr * mask,int numeric)599 pfctl_addrprefix(char *addr, struct pf_addr *mask, int numeric)
600 {
601 char *p;
602 const char *errstr;
603 int prefix, ret_ga, q, r;
604 struct addrinfo hints, *res;
605
606 bzero(&hints, sizeof(hints));
607 hints.ai_socktype = SOCK_DGRAM; /* dummy */
608 if (numeric)
609 hints.ai_flags = AI_NUMERICHOST;
610
611 if ((p = strchr(addr, '/')) != NULL) {
612 *p++ = '\0';
613 /* prefix only with numeric addresses */
614 hints.ai_flags |= AI_NUMERICHOST;
615 }
616
617 if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
618 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
619 /* NOTREACHED */
620 }
621
622 if (p == NULL)
623 return (res);
624
625 prefix = strtonum(p, 0, res->ai_family == AF_INET6 ? 128 : 32, &errstr);
626 if (errstr)
627 errx(1, "prefix is %s: %s", errstr, p);
628
629 q = prefix >> 3;
630 r = prefix & 7;
631 switch (res->ai_family) {
632 case AF_INET:
633 bzero(&mask->v4, sizeof(mask->v4));
634 mask->v4.s_addr = htonl((u_int32_t)
635 (0xffffffffffULL << (32 - prefix)));
636 break;
637 case AF_INET6:
638 bzero(&mask->v6, sizeof(mask->v6));
639 if (q > 0)
640 memset((void *)&mask->v6, 0xff, q);
641 if (r > 0)
642 *((u_char *)&mask->v6 + q) =
643 (0xff00 >> r) & 0xff;
644 break;
645 }
646
647 return (res);
648 }
649
650 void
pfctl_kill_src_nodes(int dev,int opts)651 pfctl_kill_src_nodes(int dev, int opts)
652 {
653 struct pfioc_src_node_kill psnk;
654 struct addrinfo *res[2], *resp[2];
655 struct sockaddr last_src, last_dst;
656 int killed, sources, dests;
657
658 killed = sources = dests = 0;
659
660 memset(&psnk, 0, sizeof(psnk));
661 memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
662 sizeof(psnk.psnk_src.addr.v.a.mask));
663 memset(&last_src, 0xff, sizeof(last_src));
664 memset(&last_dst, 0xff, sizeof(last_dst));
665
666 res[0] = pfctl_addrprefix(src_node_kill[0],
667 &psnk.psnk_src.addr.v.a.mask, (opts & PF_OPT_NODNS));
668
669 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
670 if (resp[0]->ai_addr == NULL)
671 continue;
672 /* We get lots of duplicates. Catch the easy ones */
673 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
674 continue;
675 last_src = *(struct sockaddr *)resp[0]->ai_addr;
676
677 psnk.psnk_af = resp[0]->ai_family;
678 sources++;
679
680 copy_satopfaddr(&psnk.psnk_src.addr.v.a.addr, resp[0]->ai_addr);
681
682 if (src_node_killers > 1) {
683 dests = 0;
684 memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
685 sizeof(psnk.psnk_dst.addr.v.a.mask));
686 memset(&last_dst, 0xff, sizeof(last_dst));
687 res[1] = pfctl_addrprefix(src_node_kill[1],
688 &psnk.psnk_dst.addr.v.a.mask,
689 (opts & PF_OPT_NODNS));
690 for (resp[1] = res[1]; resp[1];
691 resp[1] = resp[1]->ai_next) {
692 if (resp[1]->ai_addr == NULL)
693 continue;
694 if (psnk.psnk_af != resp[1]->ai_family)
695 continue;
696
697 if (memcmp(&last_dst, resp[1]->ai_addr,
698 sizeof(last_dst)) == 0)
699 continue;
700 last_dst = *(struct sockaddr *)resp[1]->ai_addr;
701
702 dests++;
703
704 copy_satopfaddr(&psnk.psnk_dst.addr.v.a.addr,
705 resp[1]->ai_addr);
706 if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
707 err(1, "DIOCKILLSRCNODES");
708 killed += psnk.psnk_killed;
709 }
710 freeaddrinfo(res[1]);
711 } else {
712 if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
713 err(1, "DIOCKILLSRCNODES");
714 killed += psnk.psnk_killed;
715 }
716 }
717
718 freeaddrinfo(res[0]);
719
720 if ((opts & PF_OPT_QUIET) == 0)
721 fprintf(stderr, "killed %d src nodes from %d sources and %d "
722 "destinations\n", killed, sources, dests);
723 }
724
725 void
pfctl_net_kill_states(int dev,const char * iface,int opts)726 pfctl_net_kill_states(int dev, const char *iface, int opts)
727 {
728 struct pfctl_kill kill;
729 struct addrinfo *res[2], *resp[2];
730 struct sockaddr last_src, last_dst;
731 unsigned int newkilled;
732 int killed, sources, dests;
733 int ret;
734
735 killed = sources = dests = 0;
736
737 memset(&kill, 0, sizeof(kill));
738 memset(&kill.src.addr.v.a.mask, 0xff,
739 sizeof(kill.src.addr.v.a.mask));
740 memset(&last_src, 0xff, sizeof(last_src));
741 memset(&last_dst, 0xff, sizeof(last_dst));
742 if (iface != NULL && strlcpy(kill.ifname, iface,
743 sizeof(kill.ifname)) >= sizeof(kill.ifname))
744 pfctl_errx(opts, 1, "invalid interface: %s", iface);
745
746 if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) {
747 kill.nat = true;
748 state_kill[0] = state_kill[1];
749 state_killers = 1;
750 }
751
752 res[0] = pfctl_addrprefix(state_kill[0],
753 &kill.src.addr.v.a.mask, (opts & PF_OPT_NODNS));
754
755 if (opts & PF_OPT_KILLMATCH)
756 kill.kill_match = true;
757
758 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
759 if (resp[0]->ai_addr == NULL)
760 continue;
761 /* We get lots of duplicates. Catch the easy ones */
762 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
763 continue;
764 last_src = *(struct sockaddr *)resp[0]->ai_addr;
765
766 kill.af = resp[0]->ai_family;
767 sources++;
768
769 copy_satopfaddr(&kill.src.addr.v.a.addr, resp[0]->ai_addr);
770
771 if (state_killers > 1) {
772 dests = 0;
773 memset(&kill.dst.addr.v.a.mask, 0xff,
774 sizeof(kill.dst.addr.v.a.mask));
775 memset(&last_dst, 0xff, sizeof(last_dst));
776 res[1] = pfctl_addrprefix(state_kill[1],
777 &kill.dst.addr.v.a.mask,
778 (opts & PF_OPT_NODNS));
779 for (resp[1] = res[1]; resp[1];
780 resp[1] = resp[1]->ai_next) {
781 if (resp[1]->ai_addr == NULL)
782 continue;
783 if (kill.af != resp[1]->ai_family)
784 continue;
785
786 if (memcmp(&last_dst, resp[1]->ai_addr,
787 sizeof(last_dst)) == 0)
788 continue;
789 last_dst = *(struct sockaddr *)resp[1]->ai_addr;
790
791 dests++;
792
793 copy_satopfaddr(&kill.dst.addr.v.a.addr,
794 resp[1]->ai_addr);
795
796 if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
797 pfctl_errx(opts, 1, "DIOCKILLSTATES");
798 killed += newkilled;
799 }
800 freeaddrinfo(res[1]);
801 } else {
802 if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
803 pfctl_errx(opts, 1, "DIOCKILLSTATES");
804 killed += newkilled;
805 }
806 }
807
808 freeaddrinfo(res[0]);
809
810 if ((opts & PF_OPT_QUIET) == 0)
811 fprintf(stderr, "killed %d states from %d sources and %d "
812 "destinations\n", killed, sources, dests);
813 }
814
815 void
pfctl_gateway_kill_states(int dev,const char * iface,int opts)816 pfctl_gateway_kill_states(int dev, const char *iface, int opts)
817 {
818 struct pfctl_kill kill;
819 struct addrinfo *res, *resp;
820 struct sockaddr last_src;
821 unsigned int newkilled;
822 int killed = 0;
823
824 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
825 warnx("no gateway specified");
826 usage();
827 }
828
829 memset(&kill, 0, sizeof(kill));
830 memset(&kill.rt_addr.addr.v.a.mask, 0xff,
831 sizeof(kill.rt_addr.addr.v.a.mask));
832 memset(&last_src, 0xff, sizeof(last_src));
833 if (iface != NULL && strlcpy(kill.ifname, iface,
834 sizeof(kill.ifname)) >= sizeof(kill.ifname))
835 pfctl_errx(opts, 1, "invalid interface: %s", iface);
836
837 if (opts & PF_OPT_KILLMATCH)
838 kill.kill_match = true;
839
840 res = pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask,
841 (opts & PF_OPT_NODNS));
842
843 for (resp = res; resp; resp = resp->ai_next) {
844 if (resp->ai_addr == NULL)
845 continue;
846 /* We get lots of duplicates. Catch the easy ones */
847 if (memcmp(&last_src, resp->ai_addr, sizeof(last_src)) == 0)
848 continue;
849 last_src = *(struct sockaddr *)resp->ai_addr;
850
851 kill.af = resp->ai_family;
852
853 copy_satopfaddr(&kill.rt_addr.addr.v.a.addr,
854 resp->ai_addr);
855 if (pfctl_kill_states_h(pfh, &kill, &newkilled))
856 pfctl_errx(opts, 1, "DIOCKILLSTATES");
857 killed += newkilled;
858 }
859
860 freeaddrinfo(res);
861
862 if ((opts & PF_OPT_QUIET) == 0)
863 fprintf(stderr, "killed %d states\n", killed);
864 }
865
866 void
pfctl_label_kill_states(int dev,const char * iface,int opts)867 pfctl_label_kill_states(int dev, const char *iface, int opts)
868 {
869 struct pfctl_kill kill;
870 unsigned int killed;
871 int ret;
872
873 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
874 warnx("no label specified");
875 usage();
876 }
877 memset(&kill, 0, sizeof(kill));
878 if (iface != NULL && strlcpy(kill.ifname, iface,
879 sizeof(kill.ifname)) >= sizeof(kill.ifname))
880 pfctl_errx(opts, 1, "invalid interface: %s", iface);
881
882 if (opts & PF_OPT_KILLMATCH)
883 kill.kill_match = true;
884
885 if (strlcpy(kill.label, state_kill[1], sizeof(kill.label)) >=
886 sizeof(kill.label))
887 errx(1, "label too long: %s", state_kill[1]);
888
889 if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
890 pfctl_errx(opts, 1, "DIOCKILLSTATES");
891
892 if ((opts & PF_OPT_QUIET) == 0)
893 fprintf(stderr, "killed %d states\n", killed);
894 }
895
896 void
pfctl_id_kill_states(int dev,const char * iface,int opts)897 pfctl_id_kill_states(int dev, const char *iface, int opts)
898 {
899 struct pfctl_kill kill;
900 unsigned int killed;
901 int ret;
902
903 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
904 warnx("no id specified");
905 usage();
906 }
907
908 memset(&kill, 0, sizeof(kill));
909
910 if (opts & PF_OPT_KILLMATCH)
911 kill.kill_match = true;
912
913 if ((sscanf(state_kill[1], "%jx/%x",
914 &kill.cmp.id, &kill.cmp.creatorid)) == 2) {
915 }
916 else if ((sscanf(state_kill[1], "%jx", &kill.cmp.id)) == 1) {
917 kill.cmp.creatorid = 0;
918 } else {
919 warnx("wrong id format specified");
920 usage();
921 }
922 if (kill.cmp.id == 0) {
923 warnx("cannot kill id 0");
924 usage();
925 }
926
927 if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
928 pfctl_errx(opts, 1, "DIOCKILLSTATES");
929
930 if ((opts & PF_OPT_QUIET) == 0)
931 fprintf(stderr, "killed %d states\n", killed);
932 }
933
934 void
pfctl_key_kill_states(int dev,const char * iface,int opts)935 pfctl_key_kill_states(int dev, const char *iface, int opts)
936 {
937 struct pfctl_kill kill;
938 char *s, *token, *tokens[4];
939 struct protoent *p;
940 u_int i, sidx, didx;
941 int ret, killed;
942
943 if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
944 warnx("no key specified");
945 usage();
946 }
947 memset(&kill, 0, sizeof(kill));
948
949 if (iface != NULL &&
950 strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >=
951 sizeof(kill.ifname))
952 pfctl_errx(opts, 1, "invalid interface: %s", iface);
953
954 s = strdup(state_kill[1]);
955 if (!s)
956 errx(1, "%s: strdup", __func__);
957 i = 0;
958 while ((token = strsep(&s, " \t")) != NULL)
959 if (*token != '\0') {
960 if (i < 4)
961 tokens[i] = token;
962 i++;
963 }
964 if (i != 4)
965 errx(1, "%s: key must be "
966 "\"protocol host1:port1 direction host2:port2\" format",
967 __func__);
968
969 if ((p = getprotobyname(tokens[0])) == NULL)
970 errx(1, "invalid protocol: %s", tokens[0]);
971 kill.proto = p->p_proto;
972
973 if (strcmp(tokens[2], "->") == 0) {
974 sidx = 1;
975 didx = 3;
976 } else if (strcmp(tokens[2], "<-") == 0) {
977 sidx = 3;
978 didx = 1;
979 } else
980 errx(1, "invalid direction: %s", tokens[2]);
981
982 if (pfctl_parse_host(tokens[sidx], &kill.src) == -1)
983 errx(1, "invalid host: %s", tokens[sidx]);
984 if (pfctl_parse_host(tokens[didx], &kill.dst) == -1)
985 errx(1, "invalid host: %s", tokens[didx]);
986
987 if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
988 pfctl_errx(opts, 1, "DIOCKILLSTATES");
989
990 if ((opts & PF_OPT_QUIET) == 0)
991 fprintf(stderr, "killed %d states\n", killed);
992 }
993
994 int
pfctl_parse_host(char * str,struct pf_rule_addr * addr)995 pfctl_parse_host(char *str, struct pf_rule_addr *addr)
996 {
997 char *s = NULL, *sbs, *sbe;
998 struct addrinfo hints, *ai;
999
1000 s = strdup(str);
1001 if (!s)
1002 errx(1, "pfctl_parse_host: strdup");
1003
1004 memset(&hints, 0, sizeof(hints));
1005 hints.ai_socktype = SOCK_DGRAM; /* dummy */
1006 hints.ai_flags = AI_NUMERICHOST;
1007
1008 if ((sbs = strchr(s, '[')) != NULL && (sbe = strrchr(s, ']')) != NULL) {
1009 hints.ai_family = AF_INET6;
1010 *(sbs++) = *sbe = '\0';
1011 } else if ((sbs = strchr(s, ':')) != NULL) {
1012 hints.ai_family = AF_INET;
1013 *(sbs++) = '\0';
1014 } else {
1015 /* Assume that no ':<number>' means port 0 */
1016 }
1017
1018 if (getaddrinfo(s, sbs, &hints, &ai) != 0)
1019 goto error;
1020
1021 copy_satopfaddr(&addr->addr.v.a.addr, ai->ai_addr);
1022 addr->port[0] = ai->ai_family == AF_INET6 ?
1023 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port :
1024 ((struct sockaddr_in *)ai->ai_addr)->sin_port;
1025 freeaddrinfo(ai);
1026 free(s);
1027
1028 memset(&addr->addr.v.a.mask, 0xff, sizeof(struct pf_addr));
1029 addr->port_op = PF_OP_EQ;
1030 addr->addr.type = PF_ADDR_ADDRMASK;
1031
1032 return (0);
1033
1034 error:
1035 free(s);
1036 return (-1);
1037 }
1038
1039 int
pfctl_get_pool(int dev,struct pfctl_pool * pool,u_int32_t nr,u_int32_t ticket,int r_action,const char * anchorname,int which)1040 pfctl_get_pool(int dev, struct pfctl_pool *pool, u_int32_t nr,
1041 u_int32_t ticket, int r_action, const char *anchorname, int which)
1042 {
1043 struct pfioc_pooladdr pp;
1044 struct pfctl_pooladdr *pa;
1045 u_int32_t pnr, mpnr;
1046 int ret;
1047
1048 memset(&pp, 0, sizeof(pp));
1049 if ((ret = pfctl_get_addrs(pfh, ticket, nr, r_action, anchorname, &mpnr, which)) != 0) {
1050 warnc(ret, "DIOCGETADDRS");
1051 return (-1);
1052 }
1053
1054 TAILQ_INIT(&pool->list);
1055 for (pnr = 0; pnr < mpnr; ++pnr) {
1056 if ((ret = pfctl_get_addr(pfh, ticket, nr, r_action, anchorname, pnr, &pp, which)) != 0) {
1057 warnc(ret, "DIOCGETADDR");
1058 return (-1);
1059 }
1060 pa = calloc(1, sizeof(struct pfctl_pooladdr));
1061 if (pa == NULL)
1062 err(1, "calloc");
1063 bcopy(&pp.addr, pa, sizeof(struct pfctl_pooladdr));
1064 pa->af = pp.af;
1065 TAILQ_INSERT_TAIL(&pool->list, pa, entries);
1066 }
1067
1068 return (0);
1069 }
1070
1071 void
pfctl_move_pool(struct pfctl_pool * src,struct pfctl_pool * dst)1072 pfctl_move_pool(struct pfctl_pool *src, struct pfctl_pool *dst)
1073 {
1074 struct pfctl_pooladdr *pa;
1075
1076 while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
1077 TAILQ_REMOVE(&src->list, pa, entries);
1078 TAILQ_INSERT_TAIL(&dst->list, pa, entries);
1079 }
1080 }
1081
1082 void
pfctl_clear_pool(struct pfctl_pool * pool)1083 pfctl_clear_pool(struct pfctl_pool *pool)
1084 {
1085 struct pfctl_pooladdr *pa;
1086
1087 while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
1088 TAILQ_REMOVE(&pool->list, pa, entries);
1089 free(pa);
1090 }
1091 }
1092
1093 void
pfctl_print_eth_rule_counters(struct pfctl_eth_rule * rule,int opts)1094 pfctl_print_eth_rule_counters(struct pfctl_eth_rule *rule, int opts)
1095 {
1096 if (opts & PF_OPT_VERBOSE) {
1097 printf(" [ Evaluations: %-8llu Packets: %-8llu "
1098 "Bytes: %-10llu]\n",
1099 (unsigned long long)rule->evaluations,
1100 (unsigned long long)(rule->packets[0] +
1101 rule->packets[1]),
1102 (unsigned long long)(rule->bytes[0] +
1103 rule->bytes[1]));
1104 }
1105 if (opts & PF_OPT_VERBOSE2) {
1106 char timestr[30];
1107
1108 if (rule->last_active_timestamp != 0) {
1109 bcopy(ctime(&rule->last_active_timestamp), timestr,
1110 sizeof(timestr));
1111 *strchr(timestr, '\n') = '\0';
1112 } else {
1113 snprintf(timestr, sizeof(timestr), "N/A");
1114 }
1115 printf(" [ Last Active Time: %s ]\n", timestr);
1116 }
1117 }
1118
1119 void
pfctl_print_rule_counters(struct pfctl_rule * rule,int opts)1120 pfctl_print_rule_counters(struct pfctl_rule *rule, int opts)
1121 {
1122 if (opts & PF_OPT_DEBUG) {
1123 const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
1124 "p", "sa", "da", "sp", "dp" };
1125 int i;
1126
1127 printf(" [ Skip steps: ");
1128 for (i = 0; i < PF_SKIP_COUNT; ++i) {
1129 if (rule->skip[i].nr == rule->nr + 1)
1130 continue;
1131 printf("%s=", t[i]);
1132 if (rule->skip[i].nr == -1)
1133 printf("end ");
1134 else
1135 printf("%u ", rule->skip[i].nr);
1136 }
1137 printf("]\n");
1138
1139 printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
1140 rule->qname, rule->qid, rule->pqname, rule->pqid);
1141 }
1142 if (opts & PF_OPT_VERBOSE) {
1143 printf(" [ Evaluations: %-8llu Packets: %-8llu "
1144 "Bytes: %-10llu States: %-6ju]\n",
1145 (unsigned long long)rule->evaluations,
1146 (unsigned long long)(rule->packets[0] +
1147 rule->packets[1]),
1148 (unsigned long long)(rule->bytes[0] +
1149 rule->bytes[1]), (uintmax_t)rule->states_cur);
1150 printf(" [ Source Nodes: %-6ju "
1151 "Limit: %-6ju "
1152 "NAT/RDR: %-6ju "
1153 "Route: %-6ju "
1154 "]\n",
1155 (uintmax_t)rule->src_nodes,
1156 (uintmax_t)rule->src_nodes_type[PF_SN_LIMIT],
1157 (uintmax_t)rule->src_nodes_type[PF_SN_NAT],
1158 (uintmax_t)rule->src_nodes_type[PF_SN_ROUTE]);
1159 if (!(opts & PF_OPT_DEBUG))
1160 printf(" [ Inserted: uid %u pid %u "
1161 "State Creations: %-6ju]\n",
1162 (unsigned)rule->cuid, (unsigned)rule->cpid,
1163 (uintmax_t)rule->states_tot);
1164 }
1165 if (opts & PF_OPT_VERBOSE2) {
1166 char timestr[30];
1167 if (rule->last_active_timestamp != 0) {
1168 bcopy(ctime(&rule->last_active_timestamp), timestr,
1169 sizeof(timestr));
1170 *strchr(timestr, '\n') = '\0';
1171 } else {
1172 snprintf(timestr, sizeof(timestr), "N/A");
1173 }
1174 printf(" [ Last Active Time: %s ]\n", timestr);
1175 }
1176 }
1177
1178 void
pfctl_print_title(char * title)1179 pfctl_print_title(char *title)
1180 {
1181 if (!first_title)
1182 printf("\n");
1183 first_title = 0;
1184 printf("%s\n", title);
1185 }
1186
1187 int
pfctl_show_eth_rules(int dev,char * path,int opts,enum pfctl_show format,char * anchorname,int depth,int wildcard)1188 pfctl_show_eth_rules(int dev, char *path, int opts, enum pfctl_show format,
1189 char *anchorname, int depth, int wildcard)
1190 {
1191 char anchor_call[MAXPATHLEN];
1192 struct pfctl_eth_rules_info info;
1193 struct pfctl_eth_rule rule;
1194 int brace;
1195 int dotitle = opts & PF_OPT_SHOWALL;
1196 int len = strlen(path);
1197 int ret;
1198 char *npath, *p;
1199
1200 /*
1201 * Truncate a trailing / and * on an anchorname before searching for
1202 * the ruleset, this is syntactic sugar that doesn't actually make it
1203 * to the kernel.
1204 */
1205 if ((p = strrchr(anchorname, '/')) != NULL &&
1206 p[1] == '*' && p[2] == '\0') {
1207 p[0] = '\0';
1208 }
1209
1210 if (anchorname[0] == '/') {
1211 if ((npath = calloc(1, MAXPATHLEN)) == NULL)
1212 errx(1, "calloc");
1213 snprintf(npath, MAXPATHLEN, "%s", anchorname);
1214 } else {
1215 if (path[0])
1216 snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
1217 else
1218 snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
1219 npath = path;
1220 }
1221
1222 /*
1223 * If this anchor was called with a wildcard path, go through
1224 * the rulesets in the anchor rather than the rules.
1225 */
1226 if (wildcard && (opts & PF_OPT_RECURSE)) {
1227 struct pfctl_eth_rulesets_info ri;
1228 u_int32_t mnr, nr;
1229
1230 if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, npath)) != 0) {
1231 if (ret == EINVAL) {
1232 fprintf(stderr, "Anchor '%s' "
1233 "not found.\n", anchorname);
1234 } else {
1235 warnc(ret, "DIOCGETETHRULESETS");
1236 return (-1);
1237 }
1238 }
1239 mnr = ri.nr;
1240
1241 pfctl_print_eth_rule_counters(&rule, opts);
1242 for (nr = 0; nr < mnr; ++nr) {
1243 struct pfctl_eth_ruleset_info rs;
1244
1245 if ((ret = pfctl_get_eth_ruleset(dev, npath, nr, &rs)) != 0)
1246 errc(1, ret, "DIOCGETETHRULESET");
1247 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1248 printf("anchor \"%s\" all {\n", rs.name);
1249 pfctl_show_eth_rules(dev, npath, opts,
1250 format, rs.name, depth + 1, 0);
1251 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1252 printf("}\n");
1253 }
1254 path[len] = '\0';
1255 return (0);
1256 }
1257
1258 if ((ret = pfctl_get_eth_rules_info(dev, &info, path)) != 0) {
1259 warnc(ret, "DIOCGETETHRULES");
1260 return (-1);
1261 }
1262 for (int nr = 0; nr < info.nr; nr++) {
1263 brace = 0;
1264 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1265 if ((ret = pfctl_get_eth_rule(dev, nr, info.ticket, path, &rule,
1266 opts & PF_OPT_CLRRULECTRS, anchor_call)) != 0) {
1267 warnc(ret, "DIOCGETETHRULE");
1268 return (-1);
1269 }
1270 if (anchor_call[0] &&
1271 ((((p = strrchr(anchor_call, '_')) != NULL) &&
1272 (p == anchor_call ||
1273 *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
1274 brace++;
1275 int aclen = strlen(anchor_call);
1276 if (anchor_call[aclen - 1] == '*')
1277 anchor_call[aclen - 2] = '\0';
1278 }
1279 p = &anchor_call[0];
1280 if (dotitle) {
1281 pfctl_print_title("ETH RULES:");
1282 dotitle = 0;
1283 }
1284 print_eth_rule(&rule, anchor_call,
1285 opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG));
1286 if (brace)
1287 printf(" {\n");
1288 else
1289 printf("\n");
1290 pfctl_print_eth_rule_counters(&rule, opts);
1291 if (brace) {
1292 pfctl_show_eth_rules(dev, path, opts, format,
1293 p, depth + 1, rule.anchor_wildcard);
1294 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1295 printf("}\n");
1296 }
1297 }
1298
1299 path[len] = '\0';
1300 return (0);
1301 }
1302
1303 int
pfctl_show_rules(int dev,char * path,int opts,enum pfctl_show format,char * anchorname,int depth,int wildcard)1304 pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
1305 char *anchorname, int depth, int wildcard)
1306 {
1307 struct pfctl_rules_info ri;
1308 struct pfctl_rule rule;
1309 char anchor_call[MAXPATHLEN];
1310 u_int32_t nr, header = 0;
1311 int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
1312 int numeric = opts & PF_OPT_NUMERIC;
1313 int len = strlen(path), ret = 0;
1314 char *npath, *p;
1315
1316 /*
1317 * Truncate a trailing / and * on an anchorname before searching for
1318 * the ruleset, this is syntactic sugar that doesn't actually make it
1319 * to the kernel.
1320 */
1321 if ((p = strrchr(anchorname, '/')) != NULL &&
1322 p[1] == '*' && p[2] == '\0') {
1323 p[0] = '\0';
1324 }
1325
1326 if (anchorname[0] == '/') {
1327 if ((npath = calloc(1, MAXPATHLEN)) == NULL)
1328 errx(1, "calloc");
1329 strlcpy(npath, anchorname, MAXPATHLEN);
1330 } else {
1331 if (path[0])
1332 snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
1333 else
1334 snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
1335 npath = path;
1336 }
1337
1338 /*
1339 * If this anchor was called with a wildcard path, go through
1340 * the rulesets in the anchor rather than the rules.
1341 */
1342 if (wildcard && (opts & PF_OPT_RECURSE)) {
1343 struct pfioc_ruleset prs;
1344 u_int32_t mnr, nr;
1345
1346 memset(&prs, 0, sizeof(prs));
1347 if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0)
1348 errx(1, "%s", pf_strerror(ret));
1349
1350 for (nr = 0; nr < mnr; ++nr) {
1351 if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0)
1352 errx(1, "%s", pf_strerror(ret));
1353 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1354 printf("anchor \"%s\" all {\n", prs.name);
1355 pfctl_show_rules(dev, npath, opts,
1356 format, prs.name, depth + 1, 0);
1357 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1358 printf("}\n");
1359 }
1360 path[len] = '\0';
1361 return (0);
1362 }
1363
1364 if (opts & PF_OPT_SHOWALL) {
1365 ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path);
1366 if (ret != 0) {
1367 warnx("%s", pf_strerror(ret));
1368 goto error;
1369 }
1370 header++;
1371 }
1372 ret = pfctl_get_rules_info_h(pfh, &ri, PF_SCRUB, path);
1373 if (ret != 0) {
1374 warnx("%s", pf_strerror(ret));
1375 goto error;
1376 }
1377 if (opts & PF_OPT_SHOWALL) {
1378 if (format == PFCTL_SHOW_RULES && (ri.nr > 0 || header))
1379 pfctl_print_title("FILTER RULES:");
1380 else if (format == PFCTL_SHOW_LABELS && labels)
1381 pfctl_print_title("LABEL COUNTERS:");
1382 }
1383
1384 for (nr = 0; nr < ri.nr; ++nr) {
1385 if ((ret = pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_SCRUB,
1386 &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) != 0) {
1387 warnc(ret, "DIOCGETRULENV");
1388 goto error;
1389 }
1390
1391 if (pfctl_get_pool(dev, &rule.rdr,
1392 nr, ri.ticket, PF_SCRUB, path, PF_RDR) != 0)
1393 goto error;
1394
1395 if (pfctl_get_pool(dev, &rule.nat,
1396 nr, ri.ticket, PF_SCRUB, path, PF_NAT) != 0)
1397 goto error;
1398
1399 if (pfctl_get_pool(dev, &rule.route,
1400 nr, ri.ticket, PF_SCRUB, path, PF_RT) != 0)
1401 goto error;
1402
1403 switch (format) {
1404 case PFCTL_SHOW_LABELS:
1405 break;
1406 case PFCTL_SHOW_RULES:
1407 if (rule.label[0][0] && (opts & PF_OPT_SHOWALL))
1408 labels = 1;
1409 print_rule(&rule, anchor_call, rule_numbers, numeric);
1410 printf("\n");
1411 pfctl_print_rule_counters(&rule, opts);
1412 break;
1413 case PFCTL_SHOW_NOTHING:
1414 break;
1415 }
1416 pfctl_clear_pool(&rule.rdr);
1417 pfctl_clear_pool(&rule.nat);
1418 pfctl_clear_pool(&rule.route);
1419 }
1420 ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path);
1421 if (ret != 0) {
1422 warnc(ret, "DIOCGETRULES");
1423 goto error;
1424 }
1425 for (nr = 0; nr < ri.nr; ++nr) {
1426 if ((ret = pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_PASS,
1427 &rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) != 0) {
1428 warnc(ret, "DIOCGETRULE");
1429 goto error;
1430 }
1431
1432 if (pfctl_get_pool(dev, &rule.rdr,
1433 nr, ri.ticket, PF_PASS, path, PF_RDR) != 0)
1434 goto error;
1435
1436 if (pfctl_get_pool(dev, &rule.nat,
1437 nr, ri.ticket, PF_PASS, path, PF_NAT) != 0)
1438 goto error;
1439
1440 if (pfctl_get_pool(dev, &rule.route,
1441 nr, ri.ticket, PF_PASS, path, PF_RT) != 0)
1442 goto error;
1443
1444 switch (format) {
1445 case PFCTL_SHOW_LABELS: {
1446 bool show = false;
1447 int i = 0;
1448
1449 while (rule.label[i][0]) {
1450 printf("%s ", rule.label[i++]);
1451 show = true;
1452 }
1453
1454 if (show) {
1455 printf("%llu %llu %llu %llu"
1456 " %llu %llu %llu %ju\n",
1457 (unsigned long long)rule.evaluations,
1458 (unsigned long long)(rule.packets[0] +
1459 rule.packets[1]),
1460 (unsigned long long)(rule.bytes[0] +
1461 rule.bytes[1]),
1462 (unsigned long long)rule.packets[0],
1463 (unsigned long long)rule.bytes[0],
1464 (unsigned long long)rule.packets[1],
1465 (unsigned long long)rule.bytes[1],
1466 (uintmax_t)rule.states_tot);
1467 }
1468
1469 if (anchor_call[0] &&
1470 (((p = strrchr(anchor_call, '/')) ?
1471 p[1] == '_' : anchor_call[0] == '_') ||
1472 opts & PF_OPT_RECURSE)) {
1473 pfctl_show_rules(dev, npath, opts, format,
1474 anchor_call, depth, rule.anchor_wildcard);
1475 }
1476 break;
1477 }
1478 case PFCTL_SHOW_RULES:
1479 if (rule.label[0][0] && (opts & PF_OPT_SHOWALL))
1480 labels = 1;
1481 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1482 print_rule(&rule, anchor_call, rule_numbers, numeric);
1483
1484 /*
1485 * If this is a 'unnamed' brace notation
1486 * anchor, OR the user has explicitly requested
1487 * recursion, print it recursively.
1488 */
1489 if (anchor_call[0] &&
1490 (((p = strrchr(anchor_call, '/')) ?
1491 p[1] == '_' : anchor_call[0] == '_') ||
1492 opts & PF_OPT_RECURSE)) {
1493 printf(" {\n");
1494 pfctl_print_rule_counters(&rule, opts);
1495 pfctl_show_rules(dev, npath, opts, format,
1496 anchor_call, depth + 1,
1497 rule.anchor_wildcard);
1498 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1499 printf("}\n");
1500 } else {
1501 printf("\n");
1502 pfctl_print_rule_counters(&rule, opts);
1503 }
1504 break;
1505 case PFCTL_SHOW_NOTHING:
1506 break;
1507 }
1508 pfctl_clear_pool(&rule.rdr);
1509 pfctl_clear_pool(&rule.nat);
1510 }
1511
1512 error:
1513 path[len] = '\0';
1514 return (ret);
1515 }
1516
1517 int
pfctl_show_nat(int dev,const char * path,int opts,char * anchorname,int depth,int wildcard)1518 pfctl_show_nat(int dev, const char *path, int opts, char *anchorname, int depth,
1519 int wildcard)
1520 {
1521 struct pfctl_rules_info ri;
1522 struct pfctl_rule rule;
1523 char anchor_call[MAXPATHLEN];
1524 u_int32_t nr;
1525 static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
1526 int i, dotitle = opts & PF_OPT_SHOWALL;
1527 int ret;
1528 int len = strlen(path);
1529 char *npath, *p;
1530
1531 /*
1532 * Truncate a trailing / and * on an anchorname before searching for
1533 * the ruleset, this is syntactic sugar that doesn't actually make it
1534 * to the kernel.
1535 */
1536 if ((p = strrchr(anchorname, '/')) != NULL &&
1537 p[1] == '*' && p[2] == '\0') {
1538 p[0] = '\0';
1539 }
1540
1541 if ((npath = calloc(1, MAXPATHLEN)) == NULL)
1542 errx(1, "calloc");
1543
1544 if (anchorname[0] == '/') {
1545 snprintf(npath, MAXPATHLEN, "%s", anchorname);
1546 } else {
1547 snprintf(npath, MAXPATHLEN, "%s", path);
1548 if (npath[0])
1549 snprintf(&npath[len], MAXPATHLEN - len, "/%s", anchorname);
1550 else
1551 snprintf(&npath[len], MAXPATHLEN - len, "%s", anchorname);
1552 }
1553
1554 /*
1555 * If this anchor was called with a wildcard path, go through
1556 * the rulesets in the anchor rather than the rules.
1557 */
1558 if (wildcard && (opts & PF_OPT_RECURSE)) {
1559 struct pfioc_ruleset prs;
1560 u_int32_t mnr, nr;
1561 memset(&prs, 0, sizeof(prs));
1562 if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0) {
1563 if (ret == EINVAL)
1564 fprintf(stderr, "NAT anchor '%s' "
1565 "not found.\n", anchorname);
1566 else
1567 errx(1, "%s", pf_strerror(ret));
1568 }
1569
1570 for (nr = 0; nr < mnr; ++nr) {
1571 if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0)
1572 errx(1, "%s", pf_strerror(ret));
1573 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1574 printf("nat-anchor \"%s\" all {\n", prs.name);
1575 pfctl_show_nat(dev, npath, opts,
1576 prs.name, depth + 1, 0);
1577 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1578 printf("}\n");
1579 }
1580 npath[len] = '\0';
1581 return (0);
1582 }
1583
1584 for (i = 0; i < 3; i++) {
1585 ret = pfctl_get_rules_info_h(pfh, &ri, nattype[i], npath);
1586 if (ret != 0) {
1587 warnc(ret, "DIOCGETRULES");
1588 return (-1);
1589 }
1590 for (nr = 0; nr < ri.nr; ++nr) {
1591 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1592
1593 if ((ret = pfctl_get_rule_h(pfh, nr, ri.ticket, npath,
1594 nattype[i], &rule, anchor_call)) != 0) {
1595 warnc(ret, "DIOCGETRULE");
1596 return (-1);
1597 }
1598 if (pfctl_get_pool(dev, &rule.rdr, nr,
1599 ri.ticket, nattype[i], npath, PF_RDR) != 0)
1600 return (-1);
1601 if (pfctl_get_pool(dev, &rule.nat, nr,
1602 ri.ticket, nattype[i], npath, PF_NAT) != 0)
1603 return (-1);
1604 if (pfctl_get_pool(dev, &rule.route, nr,
1605 ri.ticket, nattype[i], npath, PF_RT) != 0)
1606 return (-1);
1607
1608 if (dotitle) {
1609 pfctl_print_title("TRANSLATION RULES:");
1610 dotitle = 0;
1611 }
1612 print_rule(&rule, anchor_call,
1613 opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
1614 if (anchor_call[0] &&
1615 (((p = strrchr(anchor_call, '/')) ?
1616 p[1] == '_' : anchor_call[0] == '_') ||
1617 opts & PF_OPT_RECURSE)) {
1618 printf(" {\n");
1619 pfctl_print_rule_counters(&rule, opts);
1620 pfctl_show_nat(dev, npath, opts, anchor_call,
1621 depth + 1, rule.anchor_wildcard);
1622 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1623 printf("}\n");
1624 } else {
1625 printf("\n");
1626 pfctl_print_rule_counters(&rule, opts);
1627 }
1628 }
1629 }
1630 return (0);
1631 }
1632
1633 static int
pfctl_print_src_node(struct pfctl_src_node * sn,void * arg)1634 pfctl_print_src_node(struct pfctl_src_node *sn, void *arg)
1635 {
1636 int *opts = (int *)arg;
1637
1638 if (*opts & PF_OPT_SHOWALL) {
1639 pfctl_print_title("SOURCE TRACKING NODES:");
1640 *opts &= ~PF_OPT_SHOWALL;
1641 }
1642
1643 print_src_node(sn, *opts);
1644
1645 return (0);
1646 }
1647
1648 int
pfctl_show_src_nodes(int dev,int opts)1649 pfctl_show_src_nodes(int dev, int opts)
1650 {
1651 int error;
1652
1653 error = pfctl_get_srcnodes(pfh, pfctl_print_src_node, &opts);
1654
1655 return (error);
1656 }
1657
1658 struct pfctl_show_state_arg {
1659 int opts;
1660 int dotitle;
1661 const char *iface;
1662 };
1663
1664 static int
pfctl_show_state(struct pfctl_state * s,void * arg)1665 pfctl_show_state(struct pfctl_state *s, void *arg)
1666 {
1667 struct pfctl_show_state_arg *a = (struct pfctl_show_state_arg *)arg;
1668
1669 if (a->dotitle) {
1670 pfctl_print_title("STATES:");
1671 a->dotitle = 0;
1672 }
1673 print_state(s, a->opts);
1674
1675 return (0);
1676 }
1677
1678 int
pfctl_show_states(int dev,const char * iface,int opts)1679 pfctl_show_states(int dev, const char *iface, int opts)
1680 {
1681 struct pfctl_show_state_arg arg;
1682 struct pfctl_state_filter filter = {};
1683
1684 if (iface != NULL)
1685 strlcpy(filter.ifname, iface, IFNAMSIZ);
1686
1687 arg.opts = opts;
1688 arg.dotitle = opts & PF_OPT_SHOWALL;
1689 arg.iface = iface;
1690
1691 if (pfctl_get_filtered_states_iter(&filter, pfctl_show_state, &arg))
1692 return (-1);
1693
1694 return (0);
1695 }
1696
1697 int
pfctl_show_status(int dev,int opts)1698 pfctl_show_status(int dev, int opts)
1699 {
1700 struct pfctl_status *status;
1701 struct pfctl_syncookies cookies;
1702 int ret;
1703
1704 if ((status = pfctl_get_status_h(pfh)) == NULL) {
1705 warn("DIOCGETSTATUS");
1706 return (-1);
1707 }
1708 if ((ret = pfctl_get_syncookies(dev, &cookies)) != 0) {
1709 pfctl_free_status(status);
1710 warnc(ret, "DIOCGETSYNCOOKIES");
1711 return (-1);
1712 }
1713 if (opts & PF_OPT_SHOWALL)
1714 pfctl_print_title("INFO:");
1715 print_status(status, &cookies, opts);
1716 pfctl_free_status(status);
1717 return (0);
1718 }
1719
1720 int
pfctl_show_running(int dev)1721 pfctl_show_running(int dev)
1722 {
1723 struct pfctl_status *status;
1724 int running;
1725
1726 if ((status = pfctl_get_status_h(pfh)) == NULL) {
1727 warn("DIOCGETSTATUS");
1728 return (-1);
1729 }
1730
1731 running = status->running;
1732
1733 print_running(status);
1734 pfctl_free_status(status);
1735 return (!running);
1736 }
1737
1738 int
pfctl_show_timeouts(int dev,int opts)1739 pfctl_show_timeouts(int dev, int opts)
1740 {
1741 uint32_t seconds;
1742 int i;
1743 int ret;
1744
1745 if (opts & PF_OPT_SHOWALL)
1746 pfctl_print_title("TIMEOUTS:");
1747 for (i = 0; pf_timeouts[i].name; i++) {
1748 if ((ret = pfctl_get_timeout(pfh, pf_timeouts[i].timeout, &seconds)) != 0)
1749 errc(1, ret, "DIOCGETTIMEOUT");
1750 printf("%-20s %10d", pf_timeouts[i].name, seconds);
1751 if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1752 pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1753 printf(" states");
1754 else
1755 printf("s");
1756 printf("\n");
1757 }
1758 return (0);
1759
1760 }
1761
1762 int
pfctl_show_limits(int dev,int opts)1763 pfctl_show_limits(int dev, int opts)
1764 {
1765 unsigned int limit;
1766 int i;
1767 int ret;
1768
1769 if (opts & PF_OPT_SHOWALL)
1770 pfctl_print_title("LIMITS:");
1771 for (i = 0; pf_limits[i].name; i++) {
1772 if ((ret = pfctl_get_limit(pfh, pf_limits[i].index, &limit)) != 0)
1773 errc(1, ret, "DIOCGETLIMIT");
1774 printf("%-13s ", pf_limits[i].name);
1775 if (limit == UINT_MAX)
1776 printf("unlimited\n");
1777 else
1778 printf("hard limit %8u\n", limit);
1779 }
1780 return (0);
1781 }
1782
1783 void
pfctl_show_creators(int opts)1784 pfctl_show_creators(int opts)
1785 {
1786 int ret;
1787 uint32_t creators[16];
1788 size_t count = nitems(creators);
1789
1790 ret = pfctl_get_creatorids(pfh, creators, &count);
1791 if (ret != 0)
1792 errx(ret, "Failed to retrieve creators");
1793
1794 printf("Creator IDs:\n");
1795 for (size_t i = 0; i < count; i++)
1796 printf("%08x\n", creators[i]);
1797 }
1798
1799 /* callbacks for rule/nat/rdr/addr */
1800 int
pfctl_add_pool(struct pfctl * pf,struct pfctl_pool * p,int which)1801 pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, int which)
1802 {
1803 struct pfctl_pooladdr *pa;
1804 int ret;
1805
1806 TAILQ_FOREACH(pa, &p->list, entries) {
1807 memcpy(&pf->paddr.addr, pa, sizeof(struct pfctl_pooladdr));
1808 pf->paddr.af = pa->af;
1809 if ((pf->opts & PF_OPT_NOACTION) == 0) {
1810 if ((ret = pfctl_add_addr(pf->h, &pf->paddr, which)) != 0)
1811 errc(1, ret, "DIOCADDADDR");
1812 }
1813 }
1814 return (0);
1815 }
1816
1817 void
pfctl_init_rule(struct pfctl_rule * r)1818 pfctl_init_rule(struct pfctl_rule *r)
1819 {
1820 memset(r, 0, sizeof(struct pfctl_rule));
1821 TAILQ_INIT(&(r->rdr.list));
1822 TAILQ_INIT(&(r->nat.list));
1823 TAILQ_INIT(&(r->route.list));
1824 }
1825
1826 int
pfctl_append_rule(struct pfctl * pf,struct pfctl_rule * r,const char * anchor_call)1827 pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r,
1828 const char *anchor_call)
1829 {
1830 u_int8_t rs_num;
1831 struct pfctl_rule *rule;
1832 struct pfctl_ruleset *rs;
1833 char *p;
1834
1835 rs_num = pf_get_ruleset_number(r->action);
1836 if (rs_num == PF_RULESET_MAX)
1837 errx(1, "Invalid rule type %d", r->action);
1838
1839 rs = &pf->anchor->ruleset;
1840
1841 if (anchor_call[0] && r->anchor == NULL) {
1842 /*
1843 * Don't make non-brace anchors part of the main anchor pool.
1844 */
1845 if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1846 err(1, "pfctl_append_rule: calloc");
1847
1848 pf_init_ruleset(&r->anchor->ruleset);
1849 r->anchor->ruleset.anchor = r->anchor;
1850 if (strlcpy(r->anchor->path, anchor_call,
1851 sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1852 errx(1, "pfctl_append_rule: strlcpy");
1853 if ((p = strrchr(anchor_call, '/')) != NULL) {
1854 if (!strlen(p))
1855 err(1, "pfctl_append_rule: bad anchor name %s",
1856 anchor_call);
1857 } else
1858 p = (char *)anchor_call;
1859 if (strlcpy(r->anchor->name, p,
1860 sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1861 errx(1, "pfctl_append_rule: strlcpy");
1862 }
1863
1864 if ((rule = calloc(1, sizeof(*rule))) == NULL)
1865 err(1, "calloc");
1866 bcopy(r, rule, sizeof(*rule));
1867 TAILQ_INIT(&rule->rdr.list);
1868 pfctl_move_pool(&r->rdr, &rule->rdr);
1869 TAILQ_INIT(&rule->nat.list);
1870 pfctl_move_pool(&r->nat, &rule->nat);
1871 TAILQ_INIT(&rule->route.list);
1872 pfctl_move_pool(&r->route, &rule->route);
1873
1874 TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1875 return (0);
1876 }
1877
1878 int
pfctl_append_eth_rule(struct pfctl * pf,struct pfctl_eth_rule * r,const char * anchor_call)1879 pfctl_append_eth_rule(struct pfctl *pf, struct pfctl_eth_rule *r,
1880 const char *anchor_call)
1881 {
1882 struct pfctl_eth_rule *rule;
1883 struct pfctl_eth_ruleset *rs;
1884 char *p;
1885
1886 rs = &pf->eanchor->ruleset;
1887
1888 if (anchor_call[0] && r->anchor == NULL) {
1889 /*
1890 * Don't make non-brace anchors part of the main anchor pool.
1891 */
1892 if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1893 err(1, "pfctl_append_rule: calloc");
1894
1895 pf_init_eth_ruleset(&r->anchor->ruleset);
1896 r->anchor->ruleset.anchor = r->anchor;
1897 if (strlcpy(r->anchor->path, anchor_call,
1898 sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1899 errx(1, "pfctl_append_rule: strlcpy");
1900 if ((p = strrchr(anchor_call, '/')) != NULL) {
1901 if (!strlen(p))
1902 err(1, "pfctl_append_eth_rule: bad anchor name %s",
1903 anchor_call);
1904 } else
1905 p = (char *)anchor_call;
1906 if (strlcpy(r->anchor->name, p,
1907 sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1908 errx(1, "pfctl_append_eth_rule: strlcpy");
1909 }
1910
1911 if ((rule = calloc(1, sizeof(*rule))) == NULL)
1912 err(1, "calloc");
1913 bcopy(r, rule, sizeof(*rule));
1914
1915 TAILQ_INSERT_TAIL(&rs->rules, rule, entries);
1916 return (0);
1917 }
1918
1919 int
pfctl_eth_ruleset_trans(struct pfctl * pf,char * path,struct pfctl_eth_anchor * a)1920 pfctl_eth_ruleset_trans(struct pfctl *pf, char *path,
1921 struct pfctl_eth_anchor *a)
1922 {
1923 int osize = pf->trans->pfrb_size;
1924
1925 if ((pf->loadopt & PFCTL_FLAG_ETH) != 0) {
1926 if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path))
1927 return (1);
1928 }
1929 if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1930 return (5);
1931
1932 return (0);
1933 }
1934
1935 int
pfctl_ruleset_trans(struct pfctl * pf,char * path,struct pfctl_anchor * a,bool do_eth)1936 pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a, bool do_eth)
1937 {
1938 int osize = pf->trans->pfrb_size;
1939
1940 if ((pf->loadopt & PFCTL_FLAG_ETH) != 0 && do_eth) {
1941 if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path))
1942 return (1);
1943 }
1944 if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1945 if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1946 pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1947 pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1948 return (1);
1949 }
1950 if (a == pf->astack[0] && ((altqsupport &&
1951 (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1952 if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1953 return (2);
1954 }
1955 if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1956 if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1957 pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1958 return (3);
1959 }
1960 if (pf->loadopt & PFCTL_FLAG_TABLE)
1961 if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1962 return (4);
1963 if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1964 return (5);
1965
1966 return (0);
1967 }
1968
1969 int
pfctl_load_eth_ruleset(struct pfctl * pf,char * path,struct pfctl_eth_ruleset * rs,int depth)1970 pfctl_load_eth_ruleset(struct pfctl *pf, char *path,
1971 struct pfctl_eth_ruleset *rs, int depth)
1972 {
1973 struct pfctl_eth_rule *r;
1974 int error, len = strlen(path);
1975 int brace = 0;
1976
1977 pf->eanchor = rs->anchor;
1978 if (path[0])
1979 snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->eanchor->name);
1980 else
1981 snprintf(&path[len], MAXPATHLEN - len, "%s", pf->eanchor->name);
1982
1983 if (depth) {
1984 if (TAILQ_FIRST(&rs->rules) != NULL) {
1985 brace++;
1986 if (pf->opts & PF_OPT_VERBOSE)
1987 printf(" {\n");
1988 if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1989 (error = pfctl_eth_ruleset_trans(pf,
1990 path, rs->anchor))) {
1991 printf("pfctl_load_eth_rulesets: "
1992 "pfctl_eth_ruleset_trans %d\n", error);
1993 goto error;
1994 }
1995 } else if (pf->opts & PF_OPT_VERBOSE)
1996 printf("\n");
1997 }
1998
1999 while ((r = TAILQ_FIRST(&rs->rules)) != NULL) {
2000 TAILQ_REMOVE(&rs->rules, r, entries);
2001
2002 error = pfctl_load_eth_rule(pf, path, r, depth);
2003 if (error)
2004 return (error);
2005
2006 if (r->anchor) {
2007 if ((error = pfctl_load_eth_ruleset(pf, path,
2008 &r->anchor->ruleset, depth + 1)))
2009 return (error);
2010 } else if (pf->opts & PF_OPT_VERBOSE)
2011 printf("\n");
2012 free(r);
2013 }
2014 if (brace && pf->opts & PF_OPT_VERBOSE) {
2015 INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
2016 printf("}\n");
2017 }
2018 path[len] = '\0';
2019
2020 return (0);
2021 error:
2022 path[len] = '\0';
2023 return (error);
2024 }
2025
2026 int
pfctl_load_eth_rule(struct pfctl * pf,char * path,struct pfctl_eth_rule * r,int depth)2027 pfctl_load_eth_rule(struct pfctl *pf, char *path, struct pfctl_eth_rule *r,
2028 int depth)
2029 {
2030 char *name;
2031 char anchor[PF_ANCHOR_NAME_SIZE];
2032 int len = strlen(path);
2033 int ret;
2034
2035 if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor))
2036 errx(1, "pfctl_load_eth_rule: strlcpy");
2037
2038 if (r->anchor) {
2039 if (r->anchor->match) {
2040 if (path[0])
2041 snprintf(&path[len], MAXPATHLEN - len,
2042 "/%s", r->anchor->name);
2043 else
2044 snprintf(&path[len], MAXPATHLEN - len,
2045 "%s", r->anchor->name);
2046 name = r->anchor->name;
2047 } else
2048 name = r->anchor->path;
2049 } else
2050 name = "";
2051
2052 if ((pf->opts & PF_OPT_NOACTION) == 0)
2053 if ((ret = pfctl_add_eth_rule(pf->dev, r, anchor, name,
2054 pf->eth_ticket)) != 0)
2055 errc(1, ret, "DIOCADDETHRULENV");
2056
2057 if (pf->opts & PF_OPT_VERBOSE) {
2058 INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
2059 print_eth_rule(r, r->anchor ? r->anchor->name : "",
2060 pf->opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG));
2061 }
2062
2063 path[len] = '\0';
2064
2065 return (0);
2066 }
2067
2068 int
pfctl_load_ruleset(struct pfctl * pf,char * path,struct pfctl_ruleset * rs,int rs_num,int depth)2069 pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
2070 int rs_num, int depth)
2071 {
2072 struct pfctl_rule *r;
2073 int error, len = strlen(path);
2074 int brace = 0;
2075
2076 pf->anchor = rs->anchor;
2077
2078 if (path[0])
2079 snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
2080 else
2081 snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
2082
2083 if (depth) {
2084 if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
2085 brace++;
2086 if (pf->opts & PF_OPT_VERBOSE)
2087 printf(" {\n");
2088 if ((pf->opts & PF_OPT_NOACTION) == 0 &&
2089 (error = pfctl_ruleset_trans(pf,
2090 path, rs->anchor, false))) {
2091 printf("%s: "
2092 "pfctl_ruleset_trans %d\n", __func__, error);
2093 goto error;
2094 }
2095 } else if (pf->opts & PF_OPT_VERBOSE)
2096 printf("\n");
2097 }
2098
2099 if (pf->optimize && rs_num == PF_RULESET_FILTER)
2100 pfctl_optimize_ruleset(pf, rs);
2101
2102 while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
2103 TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
2104
2105 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
2106 expand_label(r->label[i], PF_RULE_LABEL_SIZE, r);
2107 expand_label(r->tagname, PF_TAG_NAME_SIZE, r);
2108 expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r);
2109
2110 if ((error = pfctl_load_rule(pf, path, r, depth)))
2111 goto error;
2112 if (r->anchor) {
2113 if ((error = pfctl_load_ruleset(pf, path,
2114 &r->anchor->ruleset, rs_num, depth + 1)))
2115 goto error;
2116 } else if (pf->opts & PF_OPT_VERBOSE)
2117 printf("\n");
2118 free(r);
2119 }
2120 if (brace && pf->opts & PF_OPT_VERBOSE) {
2121 INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
2122 printf("}\n");
2123 }
2124 path[len] = '\0';
2125 return (0);
2126
2127 error:
2128 path[len] = '\0';
2129 return (error);
2130
2131 }
2132
2133 int
pfctl_load_rule(struct pfctl * pf,char * path,struct pfctl_rule * r,int depth)2134 pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth)
2135 {
2136 u_int8_t rs_num = pf_get_ruleset_number(r->action);
2137 char *name;
2138 u_int32_t ticket;
2139 char anchor[PF_ANCHOR_NAME_SIZE];
2140 int len = strlen(path);
2141 int error;
2142 bool was_present;
2143
2144 /* set up anchor before adding to path for anchor_call */
2145 if ((pf->opts & PF_OPT_NOACTION) == 0)
2146 ticket = pfctl_get_ticket(pf->trans, rs_num, path);
2147 if (strlcpy(anchor, path, sizeof(anchor)) >= sizeof(anchor))
2148 errx(1, "pfctl_load_rule: strlcpy");
2149
2150 if (r->anchor) {
2151 if (r->anchor->match) {
2152 if (path[0])
2153 snprintf(&path[len], MAXPATHLEN - len,
2154 "/%s", r->anchor->name);
2155 else
2156 snprintf(&path[len], MAXPATHLEN - len,
2157 "%s", r->anchor->name);
2158 name = r->anchor->name;
2159 } else
2160 name = r->anchor->path;
2161 } else
2162 name = "";
2163
2164 was_present = false;
2165 if ((pf->opts & PF_OPT_NOACTION) == 0) {
2166 if ((pf->opts & PF_OPT_NOACTION) == 0) {
2167 if ((error = pfctl_begin_addrs(pf->h,
2168 &pf->paddr.ticket)) != 0)
2169 errc(1, error, "DIOCBEGINADDRS");
2170 }
2171
2172 if (pfctl_add_pool(pf, &r->rdr, PF_RDR))
2173 return (1);
2174 if (pfctl_add_pool(pf, &r->nat, PF_NAT))
2175 return (1);
2176 if (pfctl_add_pool(pf, &r->route, PF_RT))
2177 return (1);
2178 error = pfctl_add_rule_h(pf->h, r, anchor, name, ticket,
2179 pf->paddr.ticket);
2180 switch (error) {
2181 case 0:
2182 /* things worked, do nothing */
2183 break;
2184 case EEXIST:
2185 /* an identical rule is already present */
2186 was_present = true;
2187 break;
2188 default:
2189 errc(1, error, "DIOCADDRULE");
2190 }
2191 }
2192
2193 if (pf->opts & PF_OPT_VERBOSE) {
2194 INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
2195 print_rule(r, name,
2196 pf->opts & PF_OPT_VERBOSE2,
2197 pf->opts & PF_OPT_NUMERIC);
2198 if (was_present)
2199 printf(" -- rule was already present");
2200 }
2201 path[len] = '\0';
2202 pfctl_clear_pool(&r->rdr);
2203 pfctl_clear_pool(&r->nat);
2204 return (0);
2205 }
2206
2207 int
pfctl_add_altq(struct pfctl * pf,struct pf_altq * a)2208 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
2209 {
2210 if (altqsupport &&
2211 (loadopt & PFCTL_FLAG_ALTQ) != 0) {
2212 memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
2213 if ((pf->opts & PF_OPT_NOACTION) == 0) {
2214 if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
2215 if (errno == ENXIO)
2216 errx(1, "qtype not configured");
2217 else if (errno == ENODEV)
2218 errx(1, "%s: driver does not support "
2219 "altq", a->ifname);
2220 else
2221 err(1, "DIOCADDALTQ");
2222 }
2223 }
2224 pfaltq_store(&pf->paltq->altq);
2225 }
2226 return (0);
2227 }
2228
2229 int
pfctl_rules(int dev,char * filename,int opts,int optimize,char * anchorname,struct pfr_buffer * trans)2230 pfctl_rules(int dev, char *filename, int opts, int optimize,
2231 char *anchorname, struct pfr_buffer *trans)
2232 {
2233 #define ERR(...) do { warn(__VA_ARGS__); goto _error; } while(0)
2234 #define ERRX(...) do { warnx(__VA_ARGS__); goto _error; } while(0)
2235
2236 struct pfr_buffer *t, buf;
2237 struct pfioc_altq pa;
2238 struct pfctl pf;
2239 struct pfctl_ruleset *rs;
2240 struct pfctl_eth_ruleset *ethrs;
2241 struct pfr_table trs;
2242 char *path = NULL;
2243 int osize;
2244
2245 RB_INIT(&pf_anchors);
2246 memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
2247 pf_init_ruleset(&pf_main_anchor.ruleset);
2248 pf_main_anchor.ruleset.anchor = &pf_main_anchor;
2249
2250 memset(&pf_eth_main_anchor, 0, sizeof(pf_eth_main_anchor));
2251 pf_init_eth_ruleset(&pf_eth_main_anchor.ruleset);
2252 pf_eth_main_anchor.ruleset.anchor = &pf_eth_main_anchor;
2253
2254 if (trans == NULL) {
2255 bzero(&buf, sizeof(buf));
2256 buf.pfrb_type = PFRB_TRANS;
2257 t = &buf;
2258 osize = 0;
2259 } else {
2260 t = trans;
2261 osize = t->pfrb_size;
2262 }
2263
2264 memset(&pa, 0, sizeof(pa));
2265 pa.version = PFIOC_ALTQ_VERSION;
2266 memset(&pf, 0, sizeof(pf));
2267 memset(&trs, 0, sizeof(trs));
2268 if ((path = calloc(1, MAXPATHLEN)) == NULL)
2269 ERRX("%s: calloc", __func__);
2270 if (strlcpy(trs.pfrt_anchor, anchorname,
2271 sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
2272 ERRX("%s: strlcpy", __func__);
2273 pf.dev = dev;
2274 pf.h = pfh;
2275 pf.opts = opts;
2276 pf.optimize = optimize;
2277 pf.loadopt = loadopt;
2278
2279 /* non-brace anchor, create without resolving the path */
2280 if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
2281 ERRX("%s: calloc", __func__);
2282 rs = &pf.anchor->ruleset;
2283 pf_init_ruleset(rs);
2284 rs->anchor = pf.anchor;
2285 if (strlcpy(pf.anchor->path, anchorname,
2286 sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
2287 errx(1, "%s: strlcpy", __func__);
2288 if (strlcpy(pf.anchor->name, anchorname,
2289 sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
2290 errx(1, "%s: strlcpy", __func__);
2291
2292
2293 pf.astack[0] = pf.anchor;
2294 pf.asd = 0;
2295 if (anchorname[0])
2296 pf.loadopt &= ~PFCTL_FLAG_ALTQ;
2297 pf.paltq = &pa;
2298 pf.trans = t;
2299 pfctl_init_options(&pf);
2300
2301 /* Set up ethernet anchor */
2302 if ((pf.eanchor = calloc(1, sizeof(*pf.eanchor))) == NULL)
2303 ERRX("%s: calloc", __func__);
2304
2305 if (strlcpy(pf.eanchor->path, anchorname,
2306 sizeof(pf.eanchor->path)) >= sizeof(pf.eanchor->path))
2307 errx(1, "%s: strlcpy", __func__);
2308 if (strlcpy(pf.eanchor->name, anchorname,
2309 sizeof(pf.eanchor->name)) >= sizeof(pf.eanchor->name))
2310 errx(1, "%s: strlcpy", __func__);
2311
2312 ethrs = &pf.eanchor->ruleset;
2313 pf_init_eth_ruleset(ethrs);
2314 ethrs->anchor = pf.eanchor;
2315 pf.eastack[0] = pf.eanchor;
2316
2317 if ((opts & PF_OPT_NOACTION) == 0) {
2318 /*
2319 * XXX For the time being we need to open transactions for
2320 * the main ruleset before parsing, because tables are still
2321 * loaded at parse time.
2322 */
2323 if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor, true))
2324 ERRX("%s", __func__);
2325 if (pf.loadopt & PFCTL_FLAG_ETH)
2326 pf.eth_ticket = pfctl_get_ticket(t, PF_RULESET_ETH, anchorname);
2327 if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
2328 pa.ticket =
2329 pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
2330 if (pf.loadopt & PFCTL_FLAG_TABLE)
2331 pf.astack[0]->ruleset.tticket =
2332 pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
2333 }
2334
2335 if (parse_config(filename, &pf) < 0) {
2336 if ((opts & PF_OPT_NOACTION) == 0)
2337 ERRX("Syntax error in config file: "
2338 "pf rules not loaded");
2339 else
2340 goto _error;
2341 }
2342 if (loadopt & PFCTL_FLAG_OPTION)
2343 pfctl_adjust_skip_ifaces(&pf);
2344
2345 if ((pf.loadopt & PFCTL_FLAG_FILTER &&
2346 (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
2347 (pf.loadopt & PFCTL_FLAG_ETH &&
2348 (pfctl_load_eth_ruleset(&pf, path, ethrs, 0))) ||
2349 (pf.loadopt & PFCTL_FLAG_NAT &&
2350 (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
2351 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
2352 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
2353 (pf.loadopt & PFCTL_FLAG_FILTER &&
2354 pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
2355 if ((opts & PF_OPT_NOACTION) == 0)
2356 ERRX("Unable to load rules into kernel");
2357 else
2358 goto _error;
2359 }
2360
2361 if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
2362 if (check_commit_altq(dev, opts) != 0)
2363 ERRX("errors in altq config");
2364
2365 if (trans == NULL) {
2366 /* process "load anchor" directives */
2367 if (pfctl_load_anchors(dev, &pf, t) == -1)
2368 ERRX("load anchors");
2369
2370 if ((opts & PF_OPT_NOACTION) == 0) {
2371 if (!anchorname[0] && pfctl_load_options(&pf))
2372 goto _error;
2373 if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
2374 ERR("DIOCXCOMMIT");
2375 }
2376 }
2377 free(path);
2378 return (0);
2379
2380 _error:
2381 if (trans == NULL) { /* main ruleset */
2382 if ((opts & PF_OPT_NOACTION) == 0)
2383 if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
2384 err(1, "DIOCXROLLBACK");
2385 exit(1);
2386 } else { /* sub ruleset */
2387 free(path);
2388 return (-1);
2389 }
2390
2391 #undef ERR
2392 #undef ERRX
2393 }
2394
2395 FILE *
pfctl_fopen(const char * name,const char * mode)2396 pfctl_fopen(const char *name, const char *mode)
2397 {
2398 struct stat st;
2399 FILE *fp;
2400
2401 fp = fopen(name, mode);
2402 if (fp == NULL)
2403 return (NULL);
2404 if (fstat(fileno(fp), &st)) {
2405 fclose(fp);
2406 return (NULL);
2407 }
2408 if (S_ISDIR(st.st_mode)) {
2409 fclose(fp);
2410 errno = EISDIR;
2411 return (NULL);
2412 }
2413 return (fp);
2414 }
2415
2416 void
pfctl_init_options(struct pfctl * pf)2417 pfctl_init_options(struct pfctl *pf)
2418 {
2419
2420 pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
2421 pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
2422 pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
2423 pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
2424 pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
2425 pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
2426 pf->timeout[PFTM_SCTP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
2427 pf->timeout[PFTM_SCTP_OPENING] = PFTM_TCP_OPENING_VAL;
2428 pf->timeout[PFTM_SCTP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
2429 pf->timeout[PFTM_SCTP_CLOSING] = PFTM_TCP_CLOSING_VAL;
2430 pf->timeout[PFTM_SCTP_CLOSED] = PFTM_TCP_CLOSED_VAL;
2431 pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
2432 pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
2433 pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
2434 pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
2435 pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
2436 pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
2437 pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
2438 pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
2439 pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
2440 pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
2441 pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
2442 pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
2443 pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
2444 pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
2445
2446 pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
2447 pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
2448 pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
2449 pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
2450
2451 pf->debug = PF_DEBUG_URGENT;
2452 pf->reassemble = 0;
2453
2454 pf->syncookies = false;
2455 pf->syncookieswat[0] = PF_SYNCOOKIES_LOWATPCT;
2456 pf->syncookieswat[1] = PF_SYNCOOKIES_HIWATPCT;
2457 }
2458
2459 int
pfctl_load_options(struct pfctl * pf)2460 pfctl_load_options(struct pfctl *pf)
2461 {
2462 int i, error = 0;
2463
2464 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2465 return (0);
2466
2467 /* load limits */
2468 for (i = 0; i < PF_LIMIT_MAX; i++) {
2469 if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
2470 continue;
2471 if (pfctl_load_limit(pf, i, pf->limit[i]))
2472 error = 1;
2473 }
2474
2475 /*
2476 * If we've set the states limit, but haven't explicitly set adaptive
2477 * timeouts, do it now with a start of 60% and end of 120%.
2478 */
2479 if (pf->limit_set[PF_LIMIT_STATES] &&
2480 !pf->timeout_set[PFTM_ADAPTIVE_START] &&
2481 !pf->timeout_set[PFTM_ADAPTIVE_END]) {
2482 pf->timeout[PFTM_ADAPTIVE_START] =
2483 (pf->limit[PF_LIMIT_STATES] / 10) * 6;
2484 pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
2485 pf->timeout[PFTM_ADAPTIVE_END] =
2486 (pf->limit[PF_LIMIT_STATES] / 10) * 12;
2487 pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
2488 }
2489
2490 /* load timeouts */
2491 for (i = 0; i < PFTM_MAX; i++) {
2492 if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
2493 continue;
2494 if (pfctl_load_timeout(pf, i, pf->timeout[i]))
2495 error = 1;
2496 }
2497
2498 /* load debug */
2499 if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
2500 if (pfctl_load_debug(pf, pf->debug))
2501 error = 1;
2502
2503 /* load logif */
2504 if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
2505 if (pfctl_load_logif(pf, pf->ifname))
2506 error = 1;
2507
2508 /* load hostid */
2509 if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
2510 if (pfctl_load_hostid(pf, pf->hostid))
2511 error = 1;
2512
2513 /* load reassembly settings */
2514 if (!(pf->opts & PF_OPT_MERGE) || pf->reass_set)
2515 if (pfctl_load_reassembly(pf, pf->reassemble))
2516 error = 1;
2517
2518 /* load keepcounters */
2519 if (pfctl_set_keepcounters(pf->dev, pf->keep_counters))
2520 error = 1;
2521
2522 /* load syncookies settings */
2523 if (pfctl_load_syncookies(pf, pf->syncookies))
2524 error = 1;
2525
2526 return (error);
2527 }
2528
2529 int
pfctl_apply_limit(struct pfctl * pf,const char * opt,unsigned int limit)2530 pfctl_apply_limit(struct pfctl *pf, const char *opt, unsigned int limit)
2531 {
2532 int i;
2533
2534
2535 for (i = 0; pf_limits[i].name; i++) {
2536 if (strcasecmp(opt, pf_limits[i].name) == 0) {
2537 pf->limit[pf_limits[i].index] = limit;
2538 pf->limit_set[pf_limits[i].index] = 1;
2539 break;
2540 }
2541 }
2542 if (pf_limits[i].name == NULL) {
2543 warnx("Bad pool name.");
2544 return (1);
2545 }
2546
2547 if (pf->opts & PF_OPT_VERBOSE)
2548 printf("set limit %s %d\n", opt, limit);
2549
2550 return (0);
2551 }
2552
2553 int
pfctl_load_limit(struct pfctl * pf,unsigned int index,unsigned int limit)2554 pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
2555 {
2556 if (pfctl_set_limit(pf->h, index, limit)) {
2557 if (errno == EBUSY)
2558 warnx("Current pool size exceeds requested %s limit %u",
2559 pf_limits[index].name, limit);
2560 else
2561 warnx("Cannot set %s limit to %u",
2562 pf_limits[index].name, limit);
2563 return (1);
2564 }
2565 return (0);
2566 }
2567
2568 int
pfctl_apply_timeout(struct pfctl * pf,const char * opt,int seconds,int quiet)2569 pfctl_apply_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
2570 {
2571 int i;
2572
2573 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2574 return (0);
2575
2576 for (i = 0; pf_timeouts[i].name; i++) {
2577 if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
2578 pf->timeout[pf_timeouts[i].timeout] = seconds;
2579 pf->timeout_set[pf_timeouts[i].timeout] = 1;
2580 break;
2581 }
2582 }
2583
2584 if (pf_timeouts[i].name == NULL) {
2585 warnx("Bad timeout name.");
2586 return (1);
2587 }
2588
2589
2590 if (pf->opts & PF_OPT_VERBOSE && ! quiet)
2591 printf("set timeout %s %d\n", opt, seconds);
2592
2593 return (0);
2594 }
2595
2596 int
pfctl_load_timeout(struct pfctl * pf,unsigned int timeout,unsigned int seconds)2597 pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
2598 {
2599 if (pfctl_set_timeout(pf->h, timeout, seconds)) {
2600 warnx("DIOCSETTIMEOUT");
2601 return (1);
2602 }
2603 return (0);
2604 }
2605
2606 int
pfctl_set_reassembly(struct pfctl * pf,int on,int nodf)2607 pfctl_set_reassembly(struct pfctl *pf, int on, int nodf)
2608 {
2609 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2610 return (0);
2611
2612 pf->reass_set = 1;
2613 if (on) {
2614 pf->reassemble = PF_REASS_ENABLED;
2615 if (nodf)
2616 pf->reassemble |= PF_REASS_NODF;
2617 } else {
2618 pf->reassemble = 0;
2619 }
2620
2621 if (pf->opts & PF_OPT_VERBOSE)
2622 printf("set reassemble %s %s\n", on ? "yes" : "no",
2623 nodf ? "no-df" : "");
2624
2625 return (0);
2626 }
2627
2628 int
pfctl_set_optimization(struct pfctl * pf,const char * opt)2629 pfctl_set_optimization(struct pfctl *pf, const char *opt)
2630 {
2631 const struct pf_hint *hint;
2632 int i, r;
2633
2634 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2635 return (0);
2636
2637 for (i = 0; pf_hints[i].name; i++)
2638 if (strcasecmp(opt, pf_hints[i].name) == 0)
2639 break;
2640
2641 hint = pf_hints[i].hint;
2642 if (hint == NULL) {
2643 warnx("invalid state timeouts optimization");
2644 return (1);
2645 }
2646
2647 for (i = 0; hint[i].name; i++)
2648 if ((r = pfctl_apply_timeout(pf, hint[i].name,
2649 hint[i].timeout, 1)))
2650 return (r);
2651
2652 if (pf->opts & PF_OPT_VERBOSE)
2653 printf("set optimization %s\n", opt);
2654
2655 return (0);
2656 }
2657
2658 int
pfctl_set_logif(struct pfctl * pf,char * ifname)2659 pfctl_set_logif(struct pfctl *pf, char *ifname)
2660 {
2661
2662 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2663 return (0);
2664
2665 if (!strcmp(ifname, "none")) {
2666 free(pf->ifname);
2667 pf->ifname = NULL;
2668 } else {
2669 pf->ifname = strdup(ifname);
2670 if (!pf->ifname)
2671 errx(1, "pfctl_set_logif: strdup");
2672 }
2673 pf->ifname_set = 1;
2674
2675 if (pf->opts & PF_OPT_VERBOSE)
2676 printf("set loginterface %s\n", ifname);
2677
2678 return (0);
2679 }
2680
2681 int
pfctl_load_logif(struct pfctl * pf,char * ifname)2682 pfctl_load_logif(struct pfctl *pf, char *ifname)
2683 {
2684 if (ifname != NULL && strlen(ifname) >= IFNAMSIZ) {
2685 warnx("pfctl_load_logif: strlcpy");
2686 return (1);
2687 }
2688 return (pfctl_set_statusif(pfh, ifname ? ifname : ""));
2689 }
2690
2691 void
pfctl_set_hostid(struct pfctl * pf,u_int32_t hostid)2692 pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
2693 {
2694 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2695 return;
2696
2697 HTONL(hostid);
2698
2699 pf->hostid = hostid;
2700 pf->hostid_set = 1;
2701
2702 if (pf->opts & PF_OPT_VERBOSE)
2703 printf("set hostid 0x%08x\n", ntohl(hostid));
2704 }
2705
2706 int
pfctl_load_hostid(struct pfctl * pf,u_int32_t hostid)2707 pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
2708 {
2709 if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
2710 warnx("DIOCSETHOSTID");
2711 return (1);
2712 }
2713 return (0);
2714 }
2715
2716 int
pfctl_load_reassembly(struct pfctl * pf,u_int32_t reassembly)2717 pfctl_load_reassembly(struct pfctl *pf, u_int32_t reassembly)
2718 {
2719 if (ioctl(dev, DIOCSETREASS, &reassembly)) {
2720 warnx("DIOCSETREASS");
2721 return (1);
2722 }
2723 return (0);
2724 }
2725
2726 int
pfctl_load_syncookies(struct pfctl * pf,u_int8_t val)2727 pfctl_load_syncookies(struct pfctl *pf, u_int8_t val)
2728 {
2729 struct pfctl_syncookies cookies;
2730
2731 bzero(&cookies, sizeof(cookies));
2732
2733 cookies.mode = val;
2734 cookies.lowwater = pf->syncookieswat[0];
2735 cookies.highwater = pf->syncookieswat[1];
2736
2737 if (pfctl_set_syncookies(dev, &cookies)) {
2738 warnx("DIOCSETSYNCOOKIES");
2739 return (1);
2740 }
2741 return (0);
2742 }
2743
2744 int
pfctl_cfg_syncookies(struct pfctl * pf,uint8_t val,struct pfctl_watermarks * w)2745 pfctl_cfg_syncookies(struct pfctl *pf, uint8_t val, struct pfctl_watermarks *w)
2746 {
2747 if (val != PF_SYNCOOKIES_ADAPTIVE && w != NULL) {
2748 warnx("syncookies start/end only apply to adaptive");
2749 return (1);
2750 }
2751 if (val == PF_SYNCOOKIES_ADAPTIVE && w != NULL) {
2752 if (!w->hi)
2753 w->hi = PF_SYNCOOKIES_HIWATPCT;
2754 if (!w->lo)
2755 w->lo = w->hi / 2;
2756 if (w->lo >= w->hi) {
2757 warnx("start must be higher than end");
2758 return (1);
2759 }
2760 pf->syncookieswat[0] = w->lo;
2761 pf->syncookieswat[1] = w->hi;
2762 pf->syncookieswat_set = 1;
2763 }
2764
2765 if (pf->opts & PF_OPT_VERBOSE) {
2766 if (val == PF_SYNCOOKIES_NEVER)
2767 printf("set syncookies never\n");
2768 else if (val == PF_SYNCOOKIES_ALWAYS)
2769 printf("set syncookies always\n");
2770 else if (val == PF_SYNCOOKIES_ADAPTIVE) {
2771 if (pf->syncookieswat_set)
2772 printf("set syncookies adaptive (start %u%%, "
2773 "end %u%%)\n", pf->syncookieswat[1],
2774 pf->syncookieswat[0]);
2775 else
2776 printf("set syncookies adaptive\n");
2777 } else { /* cannot happen */
2778 warnx("king bula ate all syncookies");
2779 return (1);
2780 }
2781 }
2782
2783 pf->syncookies = val;
2784 return (0);
2785 }
2786
2787 int
pfctl_do_set_debug(struct pfctl * pf,char * d)2788 pfctl_do_set_debug(struct pfctl *pf, char *d)
2789 {
2790 u_int32_t level;
2791 int ret;
2792
2793 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2794 return (0);
2795
2796 if (!strcmp(d, "none"))
2797 pf->debug = PF_DEBUG_NONE;
2798 else if (!strcmp(d, "urgent"))
2799 pf->debug = PF_DEBUG_URGENT;
2800 else if (!strcmp(d, "misc"))
2801 pf->debug = PF_DEBUG_MISC;
2802 else if (!strcmp(d, "loud"))
2803 pf->debug = PF_DEBUG_NOISY;
2804 else {
2805 warnx("unknown debug level \"%s\"", d);
2806 return (-1);
2807 }
2808
2809 pf->debug_set = 1;
2810 level = pf->debug;
2811
2812 if ((pf->opts & PF_OPT_NOACTION) == 0)
2813 if ((ret = pfctl_set_debug(pfh, level)) != 0)
2814 errc(1, ret, "DIOCSETDEBUG");
2815
2816 if (pf->opts & PF_OPT_VERBOSE)
2817 printf("set debug %s\n", d);
2818
2819 return (0);
2820 }
2821
2822 int
pfctl_load_debug(struct pfctl * pf,unsigned int level)2823 pfctl_load_debug(struct pfctl *pf, unsigned int level)
2824 {
2825 if (pfctl_set_debug(pf->h, level)) {
2826 warnx("DIOCSETDEBUG");
2827 return (1);
2828 }
2829 return (0);
2830 }
2831
2832 int
pfctl_set_interface_flags(struct pfctl * pf,char * ifname,int flags,int how)2833 pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
2834 {
2835 struct pfioc_iface pi;
2836 struct node_host *h = NULL, *n = NULL;
2837
2838 if ((loadopt & PFCTL_FLAG_OPTION) == 0)
2839 return (0);
2840
2841 bzero(&pi, sizeof(pi));
2842
2843 pi.pfiio_flags = flags;
2844
2845 /* Make sure our cache matches the kernel. If we set or clear the flag
2846 * for a group this applies to all members. */
2847 h = ifa_grouplookup(ifname, 0);
2848 for (n = h; n != NULL; n = n->next)
2849 pfctl_set_interface_flags(pf, n->ifname, flags, how);
2850
2851 if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
2852 sizeof(pi.pfiio_name))
2853 errx(1, "pfctl_set_interface_flags: strlcpy");
2854
2855 if ((pf->opts & PF_OPT_NOACTION) == 0) {
2856 if (how == 0) {
2857 if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
2858 pfctl_err(pf->opts, 1, "DIOCCLRIFFLAG");
2859 } else {
2860 if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
2861 err(1, "DIOCSETIFFLAG");
2862 pfctl_check_skip_ifaces(ifname);
2863 }
2864 }
2865 return (0);
2866 }
2867
2868 void
pfctl_debug(int dev,u_int32_t level,int opts)2869 pfctl_debug(int dev, u_int32_t level, int opts)
2870 {
2871 int ret;
2872
2873 if ((ret = pfctl_set_debug(pfh, level)) != 0)
2874 errc(1, ret, "DIOCSETDEBUG");
2875 if ((opts & PF_OPT_QUIET) == 0) {
2876 fprintf(stderr, "debug level set to '");
2877 switch (level) {
2878 case PF_DEBUG_NONE:
2879 fprintf(stderr, "none");
2880 break;
2881 case PF_DEBUG_URGENT:
2882 fprintf(stderr, "urgent");
2883 break;
2884 case PF_DEBUG_MISC:
2885 fprintf(stderr, "misc");
2886 break;
2887 case PF_DEBUG_NOISY:
2888 fprintf(stderr, "loud");
2889 break;
2890 default:
2891 fprintf(stderr, "<invalid>");
2892 break;
2893 }
2894 fprintf(stderr, "'\n");
2895 }
2896 }
2897
2898 int
pfctl_test_altqsupport(int dev,int opts)2899 pfctl_test_altqsupport(int dev, int opts)
2900 {
2901 struct pfioc_altq pa;
2902
2903 pa.version = PFIOC_ALTQ_VERSION;
2904 if (ioctl(dev, DIOCGETALTQS, &pa)) {
2905 if (errno == ENODEV) {
2906 if (opts & PF_OPT_VERBOSE)
2907 fprintf(stderr, "No ALTQ support in kernel\n"
2908 "ALTQ related functions disabled\n");
2909 return (0);
2910 } else
2911 err(1, "DIOCGETALTQS");
2912 }
2913 return (1);
2914 }
2915
2916 int
pfctl_walk_show(int opts,struct pfioc_ruleset * pr,void * warg)2917 pfctl_walk_show(int opts, struct pfioc_ruleset *pr, void *warg)
2918 {
2919 if (pr->path[0]) {
2920 if (pr->path[0] != '_' || (opts & PF_OPT_VERBOSE))
2921 printf(" %s/%s\n", pr->path, pr->name);
2922 } else if (pr->name[0] != '_' || (opts & PF_OPT_VERBOSE))
2923 printf(" %s\n", pr->name);
2924
2925 return (0);
2926 }
2927
2928 int
pfctl_walk_get(int opts,struct pfioc_ruleset * pr,void * warg)2929 pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg)
2930 {
2931 struct pfr_anchoritem *pfra;
2932 struct pfr_anchors *anchors;
2933 int e;
2934
2935 anchors = (struct pfr_anchors *)warg;
2936
2937 pfra = malloc(sizeof(*pfra));
2938 if (pfra == NULL)
2939 err(1, "%s", __func__);
2940
2941 if (pr->path[0])
2942 e = asprintf(&pfra->pfra_anchorname, "%s/%s", pr->path,
2943 pr->name);
2944 else
2945 e = asprintf(&pfra->pfra_anchorname, "%s", pr->name);
2946
2947 if (e == -1)
2948 err(1, "%s", __func__);
2949
2950 SLIST_INSERT_HEAD(anchors, pfra, pfra_sle);
2951
2952 return (0);
2953 }
2954
2955 int
pfctl_walk_anchors(int dev,int opts,const char * anchor,int (walkf)(int,struct pfioc_ruleset *,void *),void * warg)2956 pfctl_walk_anchors(int dev, int opts, const char *anchor,
2957 int(walkf)(int, struct pfioc_ruleset *, void *), void *warg)
2958 {
2959 struct pfioc_ruleset pr;
2960 u_int32_t mnr, nr;
2961 int ret;
2962
2963 memset(&pr, 0, sizeof(pr));
2964 if ((ret = pfctl_get_rulesets(pfh, anchor, &mnr)) != 0)
2965 errx(1, "%s", pf_strerror(ret));
2966 for (nr = 0; nr < mnr; ++nr) {
2967 char sub[MAXPATHLEN];
2968
2969 if ((ret = pfctl_get_ruleset(pfh, anchor, nr, &pr)) != 0)
2970 errc(1, ret, "DIOCGETRULESET");
2971 if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
2972 continue;
2973 sub[0] = '\0';
2974 if (walkf(opts, &pr, warg))
2975 return (-1);
2976
2977 if (pr.path[0])
2978 snprintf(sub, sizeof(sub), "%s/%s", pr.path, pr.name);
2979 else
2980 snprintf(sub, sizeof(sub), "%s", pr.name);
2981 if (pfctl_walk_anchors(dev, opts, sub, walkf, warg))
2982 return (-1);
2983 }
2984 return (0);
2985 }
2986
2987 int
pfctl_show_anchors(int dev,int opts,char * anchor)2988 pfctl_show_anchors(int dev, int opts, char *anchor)
2989 {
2990 return (
2991 pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_show, NULL));
2992 }
2993
2994 struct pfr_anchors *
pfctl_get_anchors(int dev,const char * anchor,int opts)2995 pfctl_get_anchors(int dev, const char *anchor, int opts)
2996 {
2997 struct pfioc_ruleset pr;
2998 static struct pfr_anchors anchors;
2999 char anchorbuf[PATH_MAX];
3000 char *n;
3001
3002 SLIST_INIT(&anchors);
3003
3004 memset(&pr, 0, sizeof(pr));
3005 if (*anchor != '\0') {
3006 strlcpy(anchorbuf, anchor, sizeof(anchorbuf));
3007 n = dirname(anchorbuf);
3008 if (n[0] != '.' && n[1] != '\0')
3009 strlcpy(pr.path, n, sizeof(pr.path));
3010 strlcpy(anchorbuf, anchor, sizeof(anchorbuf));
3011 n = basename(anchorbuf);
3012 if (n != NULL)
3013 strlcpy(pr.name, n, sizeof(pr.name));
3014 }
3015
3016 /* insert a root anchor first. */
3017 pfctl_walk_get(opts, &pr, &anchors);
3018
3019 if (pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_get, &anchors))
3020 errx(1, "%s failed to retrieve list of anchors, can't continue",
3021 __func__);
3022
3023 return (&anchors);
3024 }
3025
3026 int
pfctl_call_cleartables(int dev,int opts,struct pfr_anchoritem * pfra)3027 pfctl_call_cleartables(int dev, int opts, struct pfr_anchoritem *pfra)
3028 {
3029 /*
3030 * PF_OPT_QUIET makes pfctl_clear_tables() to stop printing number of
3031 * tables cleared for given anchor.
3032 */
3033 opts |= PF_OPT_QUIET;
3034 return ((pfctl_do_clear_tables(pfra->pfra_anchorname, opts) == -1) ?
3035 1 : 0);
3036 }
3037
3038 int
pfctl_call_clearrules(int dev,int opts,struct pfr_anchoritem * pfra)3039 pfctl_call_clearrules(int dev, int opts, struct pfr_anchoritem *pfra)
3040 {
3041 /*
3042 * PF_OPT_QUIET makes pfctl_clear_rules() to stop printing a 'rules
3043 * cleared' message for every anchor it deletes.
3044 */
3045 opts |= PF_OPT_QUIET;
3046 return (pfctl_flush_rules(dev, opts, pfra->pfra_anchorname));
3047 }
3048
3049 int
pfctl_call_clearanchors(int dev,int opts,struct pfr_anchoritem * pfra)3050 pfctl_call_clearanchors(int dev, int opts, struct pfr_anchoritem *pfra)
3051 {
3052 int rv = 0;
3053
3054 rv |= pfctl_call_cleartables(dev, opts, pfra);
3055 rv |= pfctl_call_clearrules(dev, opts, pfra);
3056
3057 return (rv);
3058 }
3059
3060 int
pfctl_call_showtables(int dev,int opts,struct pfr_anchoritem * pfra)3061 pfctl_call_showtables(int dev, int opts, struct pfr_anchoritem *pfra)
3062 {
3063 pfctl_show_tables(pfra->pfra_anchorname, opts);
3064 return (0);
3065 }
3066
3067 int
pfctl_recurse(int dev,int opts,const char * anchorname,int (* walkf)(int,int,struct pfr_anchoritem *))3068 pfctl_recurse(int dev, int opts, const char *anchorname,
3069 int(*walkf)(int, int, struct pfr_anchoritem *))
3070 {
3071 int rv = 0;
3072 struct pfr_anchors *anchors;
3073 struct pfr_anchoritem *pfra, *pfra_save;
3074
3075 anchors = pfctl_get_anchors(dev, anchorname, opts);
3076 /*
3077 * While traversing the list, pfctl_clear_*() must always return
3078 * so that failures on one anchor do not prevent clearing others.
3079 */
3080 opts |= PF_OPT_IGNFAIL;
3081 if ((opts & PF_OPT_CALLSHOW) == 0)
3082 printf("Removing:\n");
3083 SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) {
3084 if ((opts & PF_OPT_CALLSHOW) == 0)
3085 printf(" %s\n",
3086 (*pfra->pfra_anchorname == '\0') ? "/" :
3087 pfra->pfra_anchorname);
3088 rv |= walkf(dev, opts, pfra);
3089 SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle);
3090 free(pfra->pfra_anchorname);
3091 free(pfra);
3092 }
3093
3094 return (rv);
3095 }
3096
3097 int
pfctl_show_eth_anchors(int dev,int opts,char * anchorname)3098 pfctl_show_eth_anchors(int dev, int opts, char *anchorname)
3099 {
3100 struct pfctl_eth_rulesets_info ri;
3101 struct pfctl_eth_ruleset_info rs;
3102 int ret;
3103
3104 if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, anchorname)) != 0) {
3105 if (ret == ENOENT)
3106 fprintf(stderr, "Anchor '%s' not found.\n",
3107 anchorname);
3108 else
3109 errc(1, ret, "DIOCGETETHRULESETS");
3110 return (-1);
3111 }
3112
3113 for (int nr = 0; nr < ri.nr; nr++) {
3114 char sub[MAXPATHLEN];
3115
3116 if ((ret = pfctl_get_eth_ruleset(dev, anchorname, nr, &rs)) != 0)
3117 errc(1, ret, "DIOCGETETHRULESET");
3118
3119 if (!strcmp(rs.name, PF_RESERVED_ANCHOR))
3120 continue;
3121 sub[0] = 0;
3122 if (rs.path[0]) {
3123 strlcat(sub, rs.path, sizeof(sub));
3124 strlcat(sub, "/", sizeof(sub));
3125 }
3126 strlcat(sub, rs.name, sizeof(sub));
3127 if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
3128 printf(" %s\n", sub);
3129 if ((opts & PF_OPT_VERBOSE) && pfctl_show_eth_anchors(dev, opts, sub))
3130 return (-1);
3131 }
3132 return (0);
3133 }
3134
3135 const char *
pfctl_lookup_option(char * cmd,const char * const * list)3136 pfctl_lookup_option(char *cmd, const char * const *list)
3137 {
3138 if (cmd != NULL && *cmd)
3139 for (; *list; list++)
3140 if (!strncmp(cmd, *list, strlen(cmd)))
3141 return (*list);
3142 return (NULL);
3143 }
3144
3145 void
pfctl_reset(int dev,int opts)3146 pfctl_reset(int dev, int opts)
3147 {
3148 struct pfctl pf;
3149 struct pfr_buffer t;
3150 int i;
3151
3152 memset(&pf, 0, sizeof(pf));
3153 pf.dev = dev;
3154 pf.h = pfh;
3155 pfctl_init_options(&pf);
3156
3157 /* Force reset upon pfctl_load_options() */
3158 pf.debug_set = 1;
3159 pf.reass_set = 1;
3160 pf.syncookieswat_set = 1;
3161 pf.ifname = strdup("none");
3162 if (pf.ifname == NULL)
3163 err(1, "%s: strdup", __func__);
3164 pf.ifname_set = 1;
3165
3166 memset(&t, 0, sizeof(t));
3167 t.pfrb_type = PFRB_TRANS;
3168 if (pfctl_trans(dev, &t, DIOCXBEGIN, 0))
3169 err(1, "%s: DIOCXBEGIN", __func__);
3170
3171 for (i = 0; pf_limits[i].name; i++)
3172 pf.limit_set[pf_limits[i].index] = 1;
3173
3174 for (i = 0; pf_timeouts[i].name; i++)
3175 pf.timeout_set[pf_timeouts[i].timeout] = 1;
3176
3177 pfctl_load_options(&pf);
3178
3179 if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
3180 err(1, "%s: DIOCXCOMMIT", __func__);
3181
3182 pfctl_clear_interface_flags(dev, opts);
3183 }
3184
3185 int
main(int argc,char * argv[])3186 main(int argc, char *argv[])
3187 {
3188 int ch;
3189 int mode = O_RDONLY;
3190 int opts = 0;
3191 int optimize = PF_OPTIMIZE_BASIC;
3192 char anchorname[MAXPATHLEN];
3193 char *path;
3194
3195 if (argc < 2)
3196 usage();
3197
3198 while ((ch = getopt(argc, argv,
3199 "a:AdD:eqf:F:ghi:k:K:mMnNOo:Pp:rRs:St:T:vx:z")) != -1) {
3200 switch (ch) {
3201 case 'a':
3202 anchoropt = optarg;
3203 break;
3204 case 'd':
3205 opts |= PF_OPT_DISABLE;
3206 mode = O_RDWR;
3207 break;
3208 case 'D':
3209 if (pfctl_cmdline_symset(optarg) < 0)
3210 warnx("could not parse macro definition %s",
3211 optarg);
3212 break;
3213 case 'e':
3214 opts |= PF_OPT_ENABLE;
3215 mode = O_RDWR;
3216 break;
3217 case 'q':
3218 opts |= PF_OPT_QUIET;
3219 break;
3220 case 'F':
3221 clearopt = pfctl_lookup_option(optarg, clearopt_list);
3222 if (clearopt == NULL) {
3223 warnx("Unknown flush modifier '%s'", optarg);
3224 usage();
3225 }
3226 mode = O_RDWR;
3227 break;
3228 case 'i':
3229 ifaceopt = optarg;
3230 break;
3231 case 'k':
3232 if (state_killers >= 2) {
3233 warnx("can only specify -k twice");
3234 usage();
3235 /* NOTREACHED */
3236 }
3237 state_kill[state_killers++] = optarg;
3238 mode = O_RDWR;
3239 break;
3240 case 'K':
3241 if (src_node_killers >= 2) {
3242 warnx("can only specify -K twice");
3243 usage();
3244 /* NOTREACHED */
3245 }
3246 src_node_kill[src_node_killers++] = optarg;
3247 mode = O_RDWR;
3248 break;
3249 case 'm':
3250 opts |= PF_OPT_MERGE;
3251 break;
3252 case 'M':
3253 opts |= PF_OPT_KILLMATCH;
3254 break;
3255 case 'n':
3256 opts |= PF_OPT_NOACTION;
3257 break;
3258 case 'N':
3259 loadopt |= PFCTL_FLAG_NAT;
3260 break;
3261 case 'r':
3262 opts |= PF_OPT_USEDNS;
3263 break;
3264 case 'f':
3265 rulesopt = optarg;
3266 mode = O_RDWR;
3267 break;
3268 case 'g':
3269 opts |= PF_OPT_DEBUG;
3270 break;
3271 case 'A':
3272 loadopt |= PFCTL_FLAG_ALTQ;
3273 break;
3274 case 'R':
3275 loadopt |= PFCTL_FLAG_FILTER;
3276 break;
3277 case 'o':
3278 optiopt = pfctl_lookup_option(optarg, optiopt_list);
3279 if (optiopt == NULL) {
3280 warnx("Unknown optimization '%s'", optarg);
3281 usage();
3282 }
3283 opts |= PF_OPT_OPTIMIZE;
3284 break;
3285 case 'O':
3286 loadopt |= PFCTL_FLAG_OPTION;
3287 break;
3288 case 'p':
3289 pf_device = optarg;
3290 break;
3291 case 'P':
3292 opts |= PF_OPT_NUMERIC;
3293 break;
3294 case 's':
3295 showopt = pfctl_lookup_option(optarg, showopt_list);
3296 if (showopt == NULL) {
3297 warnx("Unknown show modifier '%s'", optarg);
3298 usage();
3299 }
3300 break;
3301 case 'S':
3302 opts |= PF_OPT_NODNS;
3303 break;
3304 case 't':
3305 tableopt = optarg;
3306 break;
3307 case 'T':
3308 tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
3309 if (tblcmdopt == NULL) {
3310 warnx("Unknown table command '%s'", optarg);
3311 usage();
3312 }
3313 break;
3314 case 'v':
3315 if (opts & PF_OPT_VERBOSE)
3316 opts |= PF_OPT_VERBOSE2;
3317 opts |= PF_OPT_VERBOSE;
3318 break;
3319 case 'x':
3320 debugopt = pfctl_lookup_option(optarg, debugopt_list);
3321 if (debugopt == NULL) {
3322 warnx("Unknown debug level '%s'", optarg);
3323 usage();
3324 }
3325 mode = O_RDWR;
3326 break;
3327 case 'z':
3328 opts |= PF_OPT_CLRRULECTRS;
3329 mode = O_RDWR;
3330 break;
3331 case 'h':
3332 /* FALLTHROUGH */
3333 default:
3334 usage();
3335 /* NOTREACHED */
3336 }
3337 }
3338
3339 if ((opts & PF_OPT_NODNS) && (opts & PF_OPT_USEDNS))
3340 errx(1, "-N and -r are mutually exclusive");
3341
3342 if ((tblcmdopt == NULL) ^ (tableopt == NULL))
3343 usage();
3344
3345 if (tblcmdopt != NULL) {
3346 argc -= optind;
3347 argv += optind;
3348 ch = *tblcmdopt;
3349 if (ch == 'l') {
3350 loadopt |= PFCTL_FLAG_TABLE;
3351 tblcmdopt = NULL;
3352 } else
3353 mode = strchr("st", ch) ? O_RDONLY : O_RDWR;
3354 } else if (argc != optind) {
3355 warnx("unknown command line argument: %s ...", argv[optind]);
3356 usage();
3357 /* NOTREACHED */
3358 }
3359 if (loadopt == 0)
3360 loadopt = ~0;
3361
3362 memset(anchorname, 0, sizeof(anchorname));
3363 if (anchoropt != NULL) {
3364 int len = strlen(anchoropt);
3365
3366 if (anchoropt[0] == '\0')
3367 errx(1, "anchor name must not be empty");
3368 if (mode == O_RDONLY && showopt == NULL && tblcmdopt == NULL) {
3369 warnx("anchors apply to -f, -F, -s, and -T only");
3370 usage();
3371 }
3372 if (mode == O_RDWR && tblcmdopt == NULL &&
3373 (anchoropt[0] == '_' || strstr(anchoropt, "/_") != NULL))
3374 errx(1, "anchor names beginning with '_' cannot "
3375 "be modified from the command line");
3376
3377 if (len >= 1 && anchoropt[len - 1] == '*') {
3378 if (len >= 2 && anchoropt[len - 2] == '/')
3379 anchoropt[len - 2] = '\0';
3380 else
3381 anchoropt[len - 1] = '\0';
3382 opts |= PF_OPT_RECURSE;
3383 }
3384 if (strlcpy(anchorname, anchoropt,
3385 sizeof(anchorname)) >= sizeof(anchorname))
3386 errx(1, "anchor name '%s' too long",
3387 anchoropt);
3388 loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE|PFCTL_FLAG_ETH;
3389 }
3390
3391 if ((opts & PF_OPT_NOACTION) == 0) {
3392 dev = open(pf_device, mode);
3393 if (dev == -1)
3394 err(1, "%s", pf_device);
3395 altqsupport = pfctl_test_altqsupport(dev, opts);
3396 } else {
3397 dev = open(pf_device, O_RDONLY);
3398 if (dev >= 0)
3399 opts |= PF_OPT_DUMMYACTION;
3400 /* turn off options */
3401 opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
3402 clearopt = showopt = debugopt = NULL;
3403 #if !defined(ENABLE_ALTQ)
3404 altqsupport = 0;
3405 #else
3406 altqsupport = 1;
3407 #endif
3408 }
3409 pfh = pfctl_open(pf_device);
3410 if (pfh == NULL)
3411 err(1, "Failed to open netlink");
3412
3413 if (opts & PF_OPT_DISABLE)
3414 if (pfctl_disable(dev, opts))
3415 exit_val = 1;
3416
3417 if ((path = calloc(1, MAXPATHLEN)) == NULL)
3418 errx(1, "%s: calloc", __func__);
3419
3420 if (showopt != NULL) {
3421 switch (*showopt) {
3422 case 'A':
3423 pfctl_show_anchors(dev, opts, anchorname);
3424 if (opts & PF_OPT_VERBOSE2)
3425 printf("Ethernet:\n");
3426 pfctl_show_eth_anchors(dev, opts, anchorname);
3427 break;
3428 case 'r':
3429 pfctl_load_fingerprints(dev, opts);
3430 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
3431 anchorname, 0, 0);
3432 break;
3433 case 'l':
3434 pfctl_load_fingerprints(dev, opts);
3435 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
3436 anchorname, 0, 0);
3437 break;
3438 case 'n':
3439 pfctl_load_fingerprints(dev, opts);
3440 pfctl_show_nat(dev, path, opts, anchorname, 0, 0);
3441 break;
3442 case 'q':
3443 pfctl_show_altq(dev, ifaceopt, opts,
3444 opts & PF_OPT_VERBOSE2);
3445 break;
3446 case 's':
3447 pfctl_show_states(dev, ifaceopt, opts);
3448 break;
3449 case 'S':
3450 pfctl_show_src_nodes(dev, opts);
3451 break;
3452 case 'i':
3453 pfctl_show_status(dev, opts);
3454 break;
3455 case 'R':
3456 exit_val = pfctl_show_running(dev);
3457 break;
3458 case 't':
3459 pfctl_show_timeouts(dev, opts);
3460 break;
3461 case 'm':
3462 pfctl_show_limits(dev, opts);
3463 break;
3464 case 'e':
3465 pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0,
3466 0);
3467 break;
3468 case 'a':
3469 opts |= PF_OPT_SHOWALL;
3470 pfctl_load_fingerprints(dev, opts);
3471
3472 pfctl_show_eth_rules(dev, path, opts, 0, anchorname, 0,
3473 0);
3474
3475 pfctl_show_nat(dev, path, opts, anchorname, 0, 0);
3476 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
3477 anchorname, 0, 0);
3478 pfctl_show_altq(dev, ifaceopt, opts, 0);
3479 pfctl_show_states(dev, ifaceopt, opts);
3480 pfctl_show_src_nodes(dev, opts);
3481 pfctl_show_status(dev, opts);
3482 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
3483 anchorname, 0, 0);
3484 pfctl_show_timeouts(dev, opts);
3485 pfctl_show_limits(dev, opts);
3486 pfctl_show_tables(anchorname, opts);
3487 pfctl_show_fingerprints(opts);
3488 break;
3489 case 'T':
3490 if (opts & PF_OPT_RECURSE) {
3491 opts |= PF_OPT_CALLSHOW;
3492 pfctl_recurse(dev, opts, anchorname,
3493 pfctl_call_showtables);
3494 } else
3495 pfctl_show_tables(anchorname, opts);
3496 break;
3497 case 'o':
3498 pfctl_load_fingerprints(dev, opts);
3499 pfctl_show_fingerprints(opts);
3500 break;
3501 case 'I':
3502 pfctl_show_ifaces(ifaceopt, opts);
3503 break;
3504 case 'c':
3505 pfctl_show_creators(opts);
3506 break;
3507 }
3508 }
3509
3510 if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) {
3511 pfctl_show_eth_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
3512 anchorname, 0, 0);
3513 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
3514 anchorname, 0, 0);
3515 }
3516
3517 if (clearopt != NULL) {
3518 switch (*clearopt) {
3519 case 'e':
3520 pfctl_flush_eth_rules(dev, opts, anchorname);
3521 break;
3522 case 'r':
3523 if (opts & PF_OPT_RECURSE)
3524 pfctl_recurse(dev, opts, anchorname,
3525 pfctl_call_clearrules);
3526 else
3527 pfctl_flush_rules(dev, opts, anchorname);
3528 break;
3529 case 'n':
3530 pfctl_flush_nat(dev, opts, anchorname);
3531 break;
3532 case 'q':
3533 pfctl_clear_altq(dev, opts);
3534 break;
3535 case 's':
3536 pfctl_clear_iface_states(dev, ifaceopt, opts);
3537 break;
3538 case 'S':
3539 pfctl_clear_src_nodes(dev, opts);
3540 break;
3541 case 'i':
3542 pfctl_clear_stats(pfh, opts);
3543 break;
3544 case 'a':
3545 if (ifaceopt) {
3546 warnx("don't specify an interface with -Fall");
3547 usage();
3548 /* NOTREACHED */
3549 }
3550 pfctl_flush_eth_rules(dev, opts, anchorname);
3551 pfctl_flush_rules(dev, opts, anchorname);
3552 pfctl_flush_nat(dev, opts, anchorname);
3553 if (opts & PF_OPT_RECURSE)
3554 pfctl_recurse(dev, opts, anchorname,
3555 pfctl_call_clearanchors);
3556 else {
3557 pfctl_do_clear_tables(anchorname, opts);
3558 pfctl_flush_rules(dev, opts, anchorname);
3559 }
3560 if (!*anchorname) {
3561 pfctl_clear_altq(dev, opts);
3562 pfctl_clear_iface_states(dev, ifaceopt, opts);
3563 pfctl_clear_src_nodes(dev, opts);
3564 pfctl_clear_stats(pfh, opts);
3565 pfctl_clear_fingerprints(dev, opts);
3566 pfctl_reset(dev, opts);
3567 }
3568 break;
3569 case 'o':
3570 pfctl_clear_fingerprints(dev, opts);
3571 break;
3572 case 'T':
3573 if ((opts & PF_OPT_RECURSE) == 0)
3574 pfctl_do_clear_tables(anchorname, opts);
3575 else
3576 pfctl_recurse(dev, opts, anchorname,
3577 pfctl_call_cleartables);
3578 break;
3579 case 'R':
3580 pfctl_reset(dev, opts);
3581 break;
3582 }
3583 }
3584 if (state_killers) {
3585 if (!strcmp(state_kill[0], "label"))
3586 pfctl_label_kill_states(dev, ifaceopt, opts);
3587 else if (!strcmp(state_kill[0], "id"))
3588 pfctl_id_kill_states(dev, ifaceopt, opts);
3589 else if (!strcmp(state_kill[0], "gateway"))
3590 pfctl_gateway_kill_states(dev, ifaceopt, opts);
3591 else if (!strcmp(state_kill[0], "key"))
3592 pfctl_key_kill_states(dev, ifaceopt, opts);
3593 else
3594 pfctl_net_kill_states(dev, ifaceopt, opts);
3595 }
3596
3597 if (src_node_killers)
3598 pfctl_kill_src_nodes(dev, opts);
3599
3600 if (tblcmdopt != NULL) {
3601 exit_val = pfctl_table(argc, argv, tableopt,
3602 tblcmdopt, rulesopt, anchorname, opts);
3603 rulesopt = NULL;
3604 }
3605 if (optiopt != NULL) {
3606 switch (*optiopt) {
3607 case 'n':
3608 optimize = 0;
3609 break;
3610 case 'b':
3611 optimize |= PF_OPTIMIZE_BASIC;
3612 break;
3613 case 'o':
3614 case 'p':
3615 optimize |= PF_OPTIMIZE_PROFILE;
3616 break;
3617 }
3618 }
3619
3620 if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
3621 !anchorname[0] && !(opts & PF_OPT_NOACTION))
3622 pfctl_get_skip_ifaces();
3623
3624 if (rulesopt != NULL && !(opts & PF_OPT_MERGE) &&
3625 !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
3626 if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
3627 exit_val = 1;
3628
3629 if (rulesopt != NULL) {
3630 if (pfctl_rules(dev, rulesopt, opts, optimize,
3631 anchorname, NULL))
3632 exit_val = 1;
3633 }
3634
3635 if (opts & PF_OPT_ENABLE)
3636 if (pfctl_enable(dev, opts))
3637 exit_val = 1;
3638
3639 if (debugopt != NULL) {
3640 switch (*debugopt) {
3641 case 'n':
3642 pfctl_debug(dev, PF_DEBUG_NONE, opts);
3643 break;
3644 case 'u':
3645 pfctl_debug(dev, PF_DEBUG_URGENT, opts);
3646 break;
3647 case 'm':
3648 pfctl_debug(dev, PF_DEBUG_MISC, opts);
3649 break;
3650 case 'l':
3651 pfctl_debug(dev, PF_DEBUG_NOISY, opts);
3652 break;
3653 }
3654 }
3655
3656 exit(exit_val);
3657 }
3658
3659 char *
pf_strerror(int errnum)3660 pf_strerror(int errnum)
3661 {
3662 switch (errnum) {
3663 case ESRCH:
3664 return "Table does not exist.";
3665 case EINVAL:
3666 case ENOENT:
3667 return "Anchor does not exist.";
3668 default:
3669 return strerror(errnum);
3670 }
3671 }
3672