xref: /freebsd-11-stable/sbin/pfctl/pfctl.c (revision 46657c3818f196ffc32a9a1148d7bd0302c144ea)
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 __FBSDID("$FreeBSD$");
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 #include <sys/sysctl.h>
51 
52 #include <err.h>
53 #include <errno.h>
54 #include <fcntl.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 
63 #include "pfctl_parser.h"
64 #include "pfctl.h"
65 
66 void	 usage(void);
67 int	 pfctl_enable(int, int);
68 int	 pfctl_disable(int, int);
69 int	 pfctl_clear_stats(int, int);
70 int	 pfctl_get_skip_ifaces(void);
71 int	 pfctl_check_skip_ifaces(char *);
72 int	 pfctl_adjust_skip_ifaces(struct pfctl *);
73 int	 pfctl_clear_interface_flags(int, int);
74 int	 pfctl_clear_rules(int, int, char *);
75 int	 pfctl_clear_nat(int, int, char *);
76 int	 pfctl_clear_altq(int, int);
77 int	 pfctl_clear_src_nodes(int, int);
78 int	 pfctl_clear_states(int, const char *, int);
79 void	 pfctl_addrprefix(char *, struct pf_addr *);
80 int	 pfctl_kill_src_nodes(int, const char *, int);
81 int	 pfctl_net_kill_states(int, const char *, int);
82 int	 pfctl_label_kill_states(int, const char *, int);
83 int	 pfctl_id_kill_states(int, const char *, int);
84 void	 pfctl_init_options(struct pfctl *);
85 int	 pfctl_load_options(struct pfctl *);
86 int	 pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
87 int	 pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
88 int	 pfctl_load_debug(struct pfctl *, unsigned int);
89 int	 pfctl_load_logif(struct pfctl *, char *);
90 int	 pfctl_load_hostid(struct pfctl *, unsigned int);
91 int	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
92 	    char *);
93 void	 pfctl_print_rule_counters(struct pf_rule *, int);
94 int	 pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
95 int	 pfctl_show_nat(int, int, char *);
96 int	 pfctl_show_src_nodes(int, int);
97 int	 pfctl_show_states(int, const char *, int);
98 int	 pfctl_show_status(int, int);
99 int	 pfctl_show_running(int);
100 int	 pfctl_show_timeouts(int, int);
101 int	 pfctl_show_limits(int, int);
102 void	 pfctl_debug(int, u_int32_t, int);
103 int	 pfctl_test_altqsupport(int, int);
104 int	 pfctl_show_anchors(int, int, char *);
105 int	 pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
106 int	 pfctl_load_ruleset(struct pfctl *, char *,
107 		struct pf_ruleset *, int, int);
108 int	 pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
109 const char	*pfctl_lookup_option(char *, const char **);
110 
111 struct pf_anchor_global	 pf_anchors;
112 struct pf_anchor	 pf_main_anchor;
113 static struct pfr_buffer skip_b;
114 
115 const char	*clearopt;
116 char		*rulesopt;
117 const char	*showopt;
118 const char	*debugopt;
119 char		*anchoropt;
120 const char	*optiopt = NULL;
121 char		*pf_device = "/dev/pf";
122 char		*ifaceopt;
123 char		*tableopt;
124 const char	*tblcmdopt;
125 int		 src_node_killers;
126 char		*src_node_kill[2];
127 int		 state_killers;
128 char		*state_kill[2];
129 int		 loadopt;
130 int		 altqsupport;
131 
132 int		 dev = -1;
133 int		 first_title = 1;
134 int		 labels = 0;
135 
136 #define INDENT(d, o)	do {						\
137 				if (o) {				\
138 					int i;				\
139 					for (i=0; i < d; i++)		\
140 						printf("  ");		\
141 				}					\
142 			} while (0);					\
143 
144 
145 static const struct {
146 	const char	*name;
147 	int		index;
148 } pf_limits[] = {
149 	{ "states",		PF_LIMIT_STATES },
150 	{ "src-nodes",		PF_LIMIT_SRC_NODES },
151 	{ "frags",		PF_LIMIT_FRAGS },
152 	{ "table-entries",	PF_LIMIT_TABLE_ENTRIES },
153 	{ NULL,			0 }
154 };
155 
156 struct pf_hint {
157 	const char	*name;
158 	int		timeout;
159 };
160 static const struct pf_hint pf_hint_normal[] = {
161 	{ "tcp.first",		2 * 60 },
162 	{ "tcp.opening",	30 },
163 	{ "tcp.established",	24 * 60 * 60 },
164 	{ "tcp.closing",	15 * 60 },
165 	{ "tcp.finwait",	45 },
166 	{ "tcp.closed",		90 },
167 	{ "tcp.tsdiff",		30 },
168 	{ NULL,			0 }
169 };
170 static const struct pf_hint pf_hint_satellite[] = {
171 	{ "tcp.first",		3 * 60 },
172 	{ "tcp.opening",	30 + 5 },
173 	{ "tcp.established",	24 * 60 * 60 },
174 	{ "tcp.closing",	15 * 60 + 5 },
175 	{ "tcp.finwait",	45 + 5 },
176 	{ "tcp.closed",		90 + 5 },
177 	{ "tcp.tsdiff",		60 },
178 	{ NULL,			0 }
179 };
180 static const struct pf_hint pf_hint_conservative[] = {
181 	{ "tcp.first",		60 * 60 },
182 	{ "tcp.opening",	15 * 60 },
183 	{ "tcp.established",	5 * 24 * 60 * 60 },
184 	{ "tcp.closing",	60 * 60 },
185 	{ "tcp.finwait",	10 * 60 },
186 	{ "tcp.closed",		3 * 60 },
187 	{ "tcp.tsdiff",		60 },
188 	{ NULL,			0 }
189 };
190 static const struct pf_hint pf_hint_aggressive[] = {
191 	{ "tcp.first",		30 },
192 	{ "tcp.opening",	5 },
193 	{ "tcp.established",	5 * 60 * 60 },
194 	{ "tcp.closing",	60 },
195 	{ "tcp.finwait",	30 },
196 	{ "tcp.closed",		30 },
197 	{ "tcp.tsdiff",		10 },
198 	{ NULL,			0 }
199 };
200 
201 static const struct {
202 	const char *name;
203 	const struct pf_hint *hint;
204 } pf_hints[] = {
205 	{ "normal",		pf_hint_normal },
206 	{ "satellite",		pf_hint_satellite },
207 	{ "high-latency",	pf_hint_satellite },
208 	{ "conservative",	pf_hint_conservative },
209 	{ "aggressive",		pf_hint_aggressive },
210 	{ NULL,			NULL }
211 };
212 
213 static const char *clearopt_list[] = {
214 	"nat", "queue", "rules", "Sources",
215 	"states", "info", "Tables", "osfp", "all", NULL
216 };
217 
218 static const char *showopt_list[] = {
219 	"nat", "queue", "rules", "Anchors", "Sources", "states", "info",
220 	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
221 	"Running", "all", NULL
222 };
223 
224 static const char *tblcmdopt_list[] = {
225 	"kill", "flush", "add", "delete", "load", "replace", "show",
226 	"test", "zero", "expire", NULL
227 };
228 
229 static const char *debugopt_list[] = {
230 	"none", "urgent", "misc", "loud", NULL
231 };
232 
233 static const char *optiopt_list[] = {
234 	"none", "basic", "profile", NULL
235 };
236 
237 void
usage(void)238 usage(void)
239 {
240 	extern char *__progname;
241 
242 	fprintf(stderr,
243 "usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
244 	"\t[-f file] [-i interface] [-K host | network]\n"
245 	"\t[-k host | network | label | id] [-o level] [-p device]\n"
246 	"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
247 	    __progname);
248 
249 	exit(1);
250 }
251 
252 int
pfctl_enable(int dev,int opts)253 pfctl_enable(int dev, int opts)
254 {
255 	if (ioctl(dev, DIOCSTART)) {
256 		if (errno == EEXIST)
257 			errx(1, "pf already enabled");
258 		else if (errno == ESRCH)
259 			errx(1, "pfil registeration failed");
260 		else
261 			err(1, "DIOCSTART");
262 	}
263 	if ((opts & PF_OPT_QUIET) == 0)
264 		fprintf(stderr, "pf enabled\n");
265 
266 	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
267 		if (errno != EEXIST)
268 			err(1, "DIOCSTARTALTQ");
269 
270 	return (0);
271 }
272 
273 int
pfctl_disable(int dev,int opts)274 pfctl_disable(int dev, int opts)
275 {
276 	if (ioctl(dev, DIOCSTOP)) {
277 		if (errno == ENOENT)
278 			errx(1, "pf not enabled");
279 		else
280 			err(1, "DIOCSTOP");
281 	}
282 	if ((opts & PF_OPT_QUIET) == 0)
283 		fprintf(stderr, "pf disabled\n");
284 
285 	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
286 			if (errno != ENOENT)
287 				err(1, "DIOCSTOPALTQ");
288 
289 	return (0);
290 }
291 
292 int
pfctl_clear_stats(int dev,int opts)293 pfctl_clear_stats(int dev, int opts)
294 {
295 	if (ioctl(dev, DIOCCLRSTATUS))
296 		err(1, "DIOCCLRSTATUS");
297 	if ((opts & PF_OPT_QUIET) == 0)
298 		fprintf(stderr, "pf: statistics cleared\n");
299 	return (0);
300 }
301 
302 int
pfctl_get_skip_ifaces(void)303 pfctl_get_skip_ifaces(void)
304 {
305 	bzero(&skip_b, sizeof(skip_b));
306 	skip_b.pfrb_type = PFRB_IFACES;
307 	for (;;) {
308 		pfr_buf_grow(&skip_b, skip_b.pfrb_size);
309 		skip_b.pfrb_size = skip_b.pfrb_msize;
310 		if (pfi_get_ifaces(NULL, skip_b.pfrb_caddr, &skip_b.pfrb_size))
311 			err(1, "pfi_get_ifaces");
312 		if (skip_b.pfrb_size <= skip_b.pfrb_msize)
313 			break;
314 	}
315 	return (0);
316 }
317 
318 int
pfctl_check_skip_ifaces(char * ifname)319 pfctl_check_skip_ifaces(char *ifname)
320 {
321 	struct pfi_kif		*p;
322 	struct node_host	*h = NULL, *n = NULL;
323 
324 	PFRB_FOREACH(p, &skip_b) {
325 		if (!strcmp(ifname, p->pfik_name) &&
326 		    (p->pfik_flags & PFI_IFLAG_SKIP))
327 			p->pfik_flags &= ~PFI_IFLAG_SKIP;
328 		if (!strcmp(ifname, p->pfik_name) && p->pfik_group != NULL) {
329 			if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL)
330 				continue;
331 
332 			for (n = h; n != NULL; n = n->next) {
333 				if (p->pfik_ifp == NULL)
334 					continue;
335 				if (strncmp(p->pfik_name, ifname, IFNAMSIZ))
336 					continue;
337 
338 				p->pfik_flags &= ~PFI_IFLAG_SKIP;
339 			}
340 		}
341 	}
342 	return (0);
343 }
344 
345 int
pfctl_adjust_skip_ifaces(struct pfctl * pf)346 pfctl_adjust_skip_ifaces(struct pfctl *pf)
347 {
348 	struct pfi_kif		*p, *pp;
349 	struct node_host	*h = NULL, *n = NULL;
350 
351 	PFRB_FOREACH(p, &skip_b) {
352 		if (p->pfik_group == NULL || !(p->pfik_flags & PFI_IFLAG_SKIP))
353 			continue;
354 
355 		pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0);
356 		if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL)
357 			continue;
358 
359 		for (n = h; n != NULL; n = n->next)
360 			PFRB_FOREACH(pp, &skip_b) {
361 				if (pp->pfik_ifp == NULL)
362 					continue;
363 
364 				if (strncmp(pp->pfik_name, n->ifname, IFNAMSIZ))
365 					continue;
366 
367 				if (!(pp->pfik_flags & PFI_IFLAG_SKIP))
368 					pfctl_set_interface_flags(pf,
369 					    pp->pfik_name, PFI_IFLAG_SKIP, 1);
370 				if (pp->pfik_flags & PFI_IFLAG_SKIP)
371 					pp->pfik_flags &= ~PFI_IFLAG_SKIP;
372 			}
373 	}
374 
375 	PFRB_FOREACH(p, &skip_b) {
376 		if (p->pfik_ifp == NULL || ! (p->pfik_flags & PFI_IFLAG_SKIP))
377 			continue;
378 
379 		pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0);
380 	}
381 
382 	return (0);
383 }
384 
385 int
pfctl_clear_interface_flags(int dev,int opts)386 pfctl_clear_interface_flags(int dev, int opts)
387 {
388 	struct pfioc_iface	pi;
389 
390 	if ((opts & PF_OPT_NOACTION) == 0) {
391 		bzero(&pi, sizeof(pi));
392 		pi.pfiio_flags = PFI_IFLAG_SKIP;
393 
394 		if (ioctl(dev, DIOCCLRIFFLAG, &pi))
395 			err(1, "DIOCCLRIFFLAG");
396 		if ((opts & PF_OPT_QUIET) == 0)
397 			fprintf(stderr, "pf: interface flags reset\n");
398 	}
399 	return (0);
400 }
401 
402 int
pfctl_clear_rules(int dev,int opts,char * anchorname)403 pfctl_clear_rules(int dev, int opts, char *anchorname)
404 {
405 	struct pfr_buffer t;
406 
407 	memset(&t, 0, sizeof(t));
408 	t.pfrb_type = PFRB_TRANS;
409 	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
410 	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
411 	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
412 	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
413 		err(1, "pfctl_clear_rules");
414 	if ((opts & PF_OPT_QUIET) == 0)
415 		fprintf(stderr, "rules cleared\n");
416 	return (0);
417 }
418 
419 int
pfctl_clear_nat(int dev,int opts,char * anchorname)420 pfctl_clear_nat(int dev, int opts, char *anchorname)
421 {
422 	struct pfr_buffer t;
423 
424 	memset(&t, 0, sizeof(t));
425 	t.pfrb_type = PFRB_TRANS;
426 	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
427 	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
428 	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
429 	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
430 	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
431 		err(1, "pfctl_clear_nat");
432 	if ((opts & PF_OPT_QUIET) == 0)
433 		fprintf(stderr, "nat cleared\n");
434 	return (0);
435 }
436 
437 int
pfctl_clear_altq(int dev,int opts)438 pfctl_clear_altq(int dev, int opts)
439 {
440 	struct pfr_buffer t;
441 
442 	if (!altqsupport)
443 		return (-1);
444 	memset(&t, 0, sizeof(t));
445 	t.pfrb_type = PFRB_TRANS;
446 	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
447 	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
448 	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
449 		err(1, "pfctl_clear_altq");
450 	if ((opts & PF_OPT_QUIET) == 0)
451 		fprintf(stderr, "altq cleared\n");
452 	return (0);
453 }
454 
455 int
pfctl_clear_src_nodes(int dev,int opts)456 pfctl_clear_src_nodes(int dev, int opts)
457 {
458 	if (ioctl(dev, DIOCCLRSRCNODES))
459 		err(1, "DIOCCLRSRCNODES");
460 	if ((opts & PF_OPT_QUIET) == 0)
461 		fprintf(stderr, "source tracking entries cleared\n");
462 	return (0);
463 }
464 
465 int
pfctl_clear_states(int dev,const char * iface,int opts)466 pfctl_clear_states(int dev, const char *iface, int opts)
467 {
468 	struct pfioc_state_kill psk;
469 
470 	memset(&psk, 0, sizeof(psk));
471 	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
472 	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
473 		errx(1, "invalid interface: %s", iface);
474 
475 	if (ioctl(dev, DIOCCLRSTATES, &psk))
476 		err(1, "DIOCCLRSTATES");
477 	if ((opts & PF_OPT_QUIET) == 0)
478 		fprintf(stderr, "%d states cleared\n", psk.psk_killed);
479 	return (0);
480 }
481 
482 void
pfctl_addrprefix(char * addr,struct pf_addr * mask)483 pfctl_addrprefix(char *addr, struct pf_addr *mask)
484 {
485 	char *p;
486 	const char *errstr;
487 	int prefix, ret_ga, q, r;
488 	struct addrinfo hints, *res;
489 
490 	if ((p = strchr(addr, '/')) == NULL)
491 		return;
492 
493 	*p++ = '\0';
494 	prefix = strtonum(p, 0, 128, &errstr);
495 	if (errstr)
496 		errx(1, "prefix is %s: %s", errstr, p);
497 
498 	bzero(&hints, sizeof(hints));
499 	/* prefix only with numeric addresses */
500 	hints.ai_flags |= AI_NUMERICHOST;
501 
502 	if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
503 		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
504 		/* NOTREACHED */
505 	}
506 
507 	if (res->ai_family == AF_INET && prefix > 32)
508 		errx(1, "prefix too long for AF_INET");
509 	else if (res->ai_family == AF_INET6 && prefix > 128)
510 		errx(1, "prefix too long for AF_INET6");
511 
512 	q = prefix >> 3;
513 	r = prefix & 7;
514 	switch (res->ai_family) {
515 	case AF_INET:
516 		bzero(&mask->v4, sizeof(mask->v4));
517 		mask->v4.s_addr = htonl((u_int32_t)
518 		    (0xffffffffffULL << (32 - prefix)));
519 		break;
520 	case AF_INET6:
521 		bzero(&mask->v6, sizeof(mask->v6));
522 		if (q > 0)
523 			memset((void *)&mask->v6, 0xff, q);
524 		if (r > 0)
525 			*((u_char *)&mask->v6 + q) =
526 			    (0xff00 >> r) & 0xff;
527 		break;
528 	}
529 	freeaddrinfo(res);
530 }
531 
532 int
pfctl_kill_src_nodes(int dev,const char * iface,int opts)533 pfctl_kill_src_nodes(int dev, const char *iface, int opts)
534 {
535 	struct pfioc_src_node_kill psnk;
536 	struct addrinfo *res[2], *resp[2];
537 	struct sockaddr last_src, last_dst;
538 	int killed, sources, dests;
539 	int ret_ga;
540 
541 	killed = sources = dests = 0;
542 
543 	memset(&psnk, 0, sizeof(psnk));
544 	memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
545 	    sizeof(psnk.psnk_src.addr.v.a.mask));
546 	memset(&last_src, 0xff, sizeof(last_src));
547 	memset(&last_dst, 0xff, sizeof(last_dst));
548 
549 	pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
550 
551 	if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
552 		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
553 		/* NOTREACHED */
554 	}
555 	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
556 		if (resp[0]->ai_addr == NULL)
557 			continue;
558 		/* We get lots of duplicates.  Catch the easy ones */
559 		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
560 			continue;
561 		last_src = *(struct sockaddr *)resp[0]->ai_addr;
562 
563 		psnk.psnk_af = resp[0]->ai_family;
564 		sources++;
565 
566 		if (psnk.psnk_af == AF_INET)
567 			psnk.psnk_src.addr.v.a.addr.v4 =
568 			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
569 		else if (psnk.psnk_af == AF_INET6)
570 			psnk.psnk_src.addr.v.a.addr.v6 =
571 			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
572 			    sin6_addr;
573 		else
574 			errx(1, "Unknown address family %d", psnk.psnk_af);
575 
576 		if (src_node_killers > 1) {
577 			dests = 0;
578 			memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
579 			    sizeof(psnk.psnk_dst.addr.v.a.mask));
580 			memset(&last_dst, 0xff, sizeof(last_dst));
581 			pfctl_addrprefix(src_node_kill[1],
582 			    &psnk.psnk_dst.addr.v.a.mask);
583 			if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
584 			    &res[1]))) {
585 				errx(1, "getaddrinfo: %s",
586 				    gai_strerror(ret_ga));
587 				/* NOTREACHED */
588 			}
589 			for (resp[1] = res[1]; resp[1];
590 			    resp[1] = resp[1]->ai_next) {
591 				if (resp[1]->ai_addr == NULL)
592 					continue;
593 				if (psnk.psnk_af != resp[1]->ai_family)
594 					continue;
595 
596 				if (memcmp(&last_dst, resp[1]->ai_addr,
597 				    sizeof(last_dst)) == 0)
598 					continue;
599 				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
600 
601 				dests++;
602 
603 				if (psnk.psnk_af == AF_INET)
604 					psnk.psnk_dst.addr.v.a.addr.v4 =
605 					    ((struct sockaddr_in *)resp[1]->
606 					    ai_addr)->sin_addr;
607 				else if (psnk.psnk_af == AF_INET6)
608 					psnk.psnk_dst.addr.v.a.addr.v6 =
609 					    ((struct sockaddr_in6 *)resp[1]->
610 					    ai_addr)->sin6_addr;
611 				else
612 					errx(1, "Unknown address family %d",
613 					    psnk.psnk_af);
614 
615 				if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
616 					err(1, "DIOCKILLSRCNODES");
617 				killed += psnk.psnk_killed;
618 			}
619 			freeaddrinfo(res[1]);
620 		} else {
621 			if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
622 				err(1, "DIOCKILLSRCNODES");
623 			killed += psnk.psnk_killed;
624 		}
625 	}
626 
627 	freeaddrinfo(res[0]);
628 
629 	if ((opts & PF_OPT_QUIET) == 0)
630 		fprintf(stderr, "killed %d src nodes from %d sources and %d "
631 		    "destinations\n", killed, sources, dests);
632 	return (0);
633 }
634 
635 int
pfctl_net_kill_states(int dev,const char * iface,int opts)636 pfctl_net_kill_states(int dev, const char *iface, int opts)
637 {
638 	struct pfioc_state_kill psk;
639 	struct addrinfo *res[2], *resp[2];
640 	struct sockaddr last_src, last_dst;
641 	int killed, sources, dests;
642 	int ret_ga;
643 
644 	killed = sources = dests = 0;
645 
646 	memset(&psk, 0, sizeof(psk));
647 	memset(&psk.psk_src.addr.v.a.mask, 0xff,
648 	    sizeof(psk.psk_src.addr.v.a.mask));
649 	memset(&last_src, 0xff, sizeof(last_src));
650 	memset(&last_dst, 0xff, sizeof(last_dst));
651 	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
652 	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
653 		errx(1, "invalid interface: %s", iface);
654 
655 	pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
656 
657 	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
658 		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
659 		/* NOTREACHED */
660 	}
661 	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
662 		if (resp[0]->ai_addr == NULL)
663 			continue;
664 		/* We get lots of duplicates.  Catch the easy ones */
665 		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
666 			continue;
667 		last_src = *(struct sockaddr *)resp[0]->ai_addr;
668 
669 		psk.psk_af = resp[0]->ai_family;
670 		sources++;
671 
672 		if (psk.psk_af == AF_INET)
673 			psk.psk_src.addr.v.a.addr.v4 =
674 			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
675 		else if (psk.psk_af == AF_INET6)
676 			psk.psk_src.addr.v.a.addr.v6 =
677 			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
678 			    sin6_addr;
679 		else
680 			errx(1, "Unknown address family %d", psk.psk_af);
681 
682 		if (state_killers > 1) {
683 			dests = 0;
684 			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
685 			    sizeof(psk.psk_dst.addr.v.a.mask));
686 			memset(&last_dst, 0xff, sizeof(last_dst));
687 			pfctl_addrprefix(state_kill[1],
688 			    &psk.psk_dst.addr.v.a.mask);
689 			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
690 			    &res[1]))) {
691 				errx(1, "getaddrinfo: %s",
692 				    gai_strerror(ret_ga));
693 				/* NOTREACHED */
694 			}
695 			for (resp[1] = res[1]; resp[1];
696 			    resp[1] = resp[1]->ai_next) {
697 				if (resp[1]->ai_addr == NULL)
698 					continue;
699 				if (psk.psk_af != resp[1]->ai_family)
700 					continue;
701 
702 				if (memcmp(&last_dst, resp[1]->ai_addr,
703 				    sizeof(last_dst)) == 0)
704 					continue;
705 				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
706 
707 				dests++;
708 
709 				if (psk.psk_af == AF_INET)
710 					psk.psk_dst.addr.v.a.addr.v4 =
711 					    ((struct sockaddr_in *)resp[1]->
712 					    ai_addr)->sin_addr;
713 				else if (psk.psk_af == AF_INET6)
714 					psk.psk_dst.addr.v.a.addr.v6 =
715 					    ((struct sockaddr_in6 *)resp[1]->
716 					    ai_addr)->sin6_addr;
717 				else
718 					errx(1, "Unknown address family %d",
719 					    psk.psk_af);
720 
721 				if (ioctl(dev, DIOCKILLSTATES, &psk))
722 					err(1, "DIOCKILLSTATES");
723 				killed += psk.psk_killed;
724 			}
725 			freeaddrinfo(res[1]);
726 		} else {
727 			if (ioctl(dev, DIOCKILLSTATES, &psk))
728 				err(1, "DIOCKILLSTATES");
729 			killed += psk.psk_killed;
730 		}
731 	}
732 
733 	freeaddrinfo(res[0]);
734 
735 	if ((opts & PF_OPT_QUIET) == 0)
736 		fprintf(stderr, "killed %d states from %d sources and %d "
737 		    "destinations\n", killed, sources, dests);
738 	return (0);
739 }
740 
741 int
pfctl_label_kill_states(int dev,const char * iface,int opts)742 pfctl_label_kill_states(int dev, const char *iface, int opts)
743 {
744 	struct pfioc_state_kill psk;
745 
746 	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
747 		warnx("no label specified");
748 		usage();
749 	}
750 	memset(&psk, 0, sizeof(psk));
751 	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
752 	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
753 		errx(1, "invalid interface: %s", iface);
754 
755 	if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
756 	    sizeof(psk.psk_label))
757 		errx(1, "label too long: %s", state_kill[1]);
758 
759 	if (ioctl(dev, DIOCKILLSTATES, &psk))
760 		err(1, "DIOCKILLSTATES");
761 
762 	if ((opts & PF_OPT_QUIET) == 0)
763 		fprintf(stderr, "killed %d states\n", psk.psk_killed);
764 
765 	return (0);
766 }
767 
768 int
pfctl_id_kill_states(int dev,const char * iface,int opts)769 pfctl_id_kill_states(int dev, const char *iface, int opts)
770 {
771 	struct pfioc_state_kill psk;
772 
773 	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
774 		warnx("no id specified");
775 		usage();
776 	}
777 
778 	memset(&psk, 0, sizeof(psk));
779 	if ((sscanf(state_kill[1], "%jx/%x",
780 	    &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
781 		HTONL(psk.psk_pfcmp.creatorid);
782 	else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
783 		psk.psk_pfcmp.creatorid = 0;
784 	} else {
785 		warnx("wrong id format specified");
786 		usage();
787 	}
788 	if (psk.psk_pfcmp.id == 0) {
789 		warnx("cannot kill id 0");
790 		usage();
791 	}
792 
793 	psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
794 	if (ioctl(dev, DIOCKILLSTATES, &psk))
795 		err(1, "DIOCKILLSTATES");
796 
797 	if ((opts & PF_OPT_QUIET) == 0)
798 		fprintf(stderr, "killed %d states\n", psk.psk_killed);
799 
800 	return (0);
801 }
802 
803 int
pfctl_get_pool(int dev,struct pf_pool * pool,u_int32_t nr,u_int32_t ticket,int r_action,char * anchorname)804 pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
805     u_int32_t ticket, int r_action, char *anchorname)
806 {
807 	struct pfioc_pooladdr pp;
808 	struct pf_pooladdr *pa;
809 	u_int32_t pnr, mpnr;
810 
811 	memset(&pp, 0, sizeof(pp));
812 	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
813 	pp.r_action = r_action;
814 	pp.r_num = nr;
815 	pp.ticket = ticket;
816 	if (ioctl(dev, DIOCGETADDRS, &pp)) {
817 		warn("DIOCGETADDRS");
818 		return (-1);
819 	}
820 	mpnr = pp.nr;
821 	TAILQ_INIT(&pool->list);
822 	for (pnr = 0; pnr < mpnr; ++pnr) {
823 		pp.nr = pnr;
824 		if (ioctl(dev, DIOCGETADDR, &pp)) {
825 			warn("DIOCGETADDR");
826 			return (-1);
827 		}
828 		pa = calloc(1, sizeof(struct pf_pooladdr));
829 		if (pa == NULL)
830 			err(1, "calloc");
831 		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
832 		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
833 	}
834 
835 	return (0);
836 }
837 
838 void
pfctl_move_pool(struct pf_pool * src,struct pf_pool * dst)839 pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
840 {
841 	struct pf_pooladdr *pa;
842 
843 	while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
844 		TAILQ_REMOVE(&src->list, pa, entries);
845 		TAILQ_INSERT_TAIL(&dst->list, pa, entries);
846 	}
847 }
848 
849 void
pfctl_clear_pool(struct pf_pool * pool)850 pfctl_clear_pool(struct pf_pool *pool)
851 {
852 	struct pf_pooladdr *pa;
853 
854 	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
855 		TAILQ_REMOVE(&pool->list, pa, entries);
856 		free(pa);
857 	}
858 }
859 
860 void
pfctl_print_rule_counters(struct pf_rule * rule,int opts)861 pfctl_print_rule_counters(struct pf_rule *rule, int opts)
862 {
863 	if (opts & PF_OPT_DEBUG) {
864 		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
865 		    "p", "sa", "sp", "da", "dp" };
866 		int i;
867 
868 		printf("  [ Skip steps: ");
869 		for (i = 0; i < PF_SKIP_COUNT; ++i) {
870 			if (rule->skip[i].nr == rule->nr + 1)
871 				continue;
872 			printf("%s=", t[i]);
873 			if (rule->skip[i].nr == -1)
874 				printf("end ");
875 			else
876 				printf("%u ", rule->skip[i].nr);
877 		}
878 		printf("]\n");
879 
880 		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
881 		    rule->qname, rule->qid, rule->pqname, rule->pqid);
882 	}
883 	if (opts & PF_OPT_VERBOSE) {
884 		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
885 			    "Bytes: %-10llu  States: %-6ju]\n",
886 			    (unsigned long long)rule->evaluations,
887 			    (unsigned long long)(rule->packets[0] +
888 			    rule->packets[1]),
889 			    (unsigned long long)(rule->bytes[0] +
890 			    rule->bytes[1]), (uintmax_t)rule->u_states_cur);
891 		if (!(opts & PF_OPT_DEBUG))
892 			printf("  [ Inserted: uid %u pid %u "
893 			    "State Creations: %-6ju]\n",
894 			    (unsigned)rule->cuid, (unsigned)rule->cpid,
895 			    (uintmax_t)rule->u_states_tot);
896 	}
897 }
898 
899 void
pfctl_print_title(char * title)900 pfctl_print_title(char *title)
901 {
902 	if (!first_title)
903 		printf("\n");
904 	first_title = 0;
905 	printf("%s\n", title);
906 }
907 
908 int
pfctl_show_rules(int dev,char * path,int opts,enum pfctl_show format,char * anchorname,int depth)909 pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
910     char *anchorname, int depth)
911 {
912 	struct pfioc_rule pr;
913 	u_int32_t nr, mnr, header = 0;
914 	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
915 	int numeric = opts & PF_OPT_NUMERIC;
916 	int len = strlen(path);
917 	int brace;
918 	char *p;
919 
920 	if (path[0])
921 		snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
922 	else
923 		snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
924 
925 	memset(&pr, 0, sizeof(pr));
926 	memcpy(pr.anchor, path, sizeof(pr.anchor));
927 	if (opts & PF_OPT_SHOWALL) {
928 		pr.rule.action = PF_PASS;
929 		if (ioctl(dev, DIOCGETRULES, &pr)) {
930 			warn("DIOCGETRULES");
931 			goto error;
932 		}
933 		header++;
934 	}
935 	pr.rule.action = PF_SCRUB;
936 	if (ioctl(dev, DIOCGETRULES, &pr)) {
937 		warn("DIOCGETRULES");
938 		goto error;
939 	}
940 	if (opts & PF_OPT_SHOWALL) {
941 		if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
942 			pfctl_print_title("FILTER RULES:");
943 		else if (format == PFCTL_SHOW_LABELS && labels)
944 			pfctl_print_title("LABEL COUNTERS:");
945 	}
946 	mnr = pr.nr;
947 	if (opts & PF_OPT_CLRRULECTRS)
948 		pr.action = PF_GET_CLR_CNTR;
949 
950 	for (nr = 0; nr < mnr; ++nr) {
951 		pr.nr = nr;
952 		if (ioctl(dev, DIOCGETRULE, &pr)) {
953 			warn("DIOCGETRULE");
954 			goto error;
955 		}
956 
957 		if (pfctl_get_pool(dev, &pr.rule.rpool,
958 		    nr, pr.ticket, PF_SCRUB, path) != 0)
959 			goto error;
960 
961 		switch (format) {
962 		case PFCTL_SHOW_LABELS:
963 			break;
964 		case PFCTL_SHOW_RULES:
965 			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
966 				labels = 1;
967 			print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
968 			printf("\n");
969 			pfctl_print_rule_counters(&pr.rule, opts);
970 			break;
971 		case PFCTL_SHOW_NOTHING:
972 			break;
973 		}
974 		pfctl_clear_pool(&pr.rule.rpool);
975 	}
976 	pr.rule.action = PF_PASS;
977 	if (ioctl(dev, DIOCGETRULES, &pr)) {
978 		warn("DIOCGETRULES");
979 		goto error;
980 	}
981 	mnr = pr.nr;
982 	for (nr = 0; nr < mnr; ++nr) {
983 		pr.nr = nr;
984 		if (ioctl(dev, DIOCGETRULE, &pr)) {
985 			warn("DIOCGETRULE");
986 			goto error;
987 		}
988 
989 		if (pfctl_get_pool(dev, &pr.rule.rpool,
990 		    nr, pr.ticket, PF_PASS, path) != 0)
991 			goto error;
992 
993 		switch (format) {
994 		case PFCTL_SHOW_LABELS:
995 			if (pr.rule.label[0]) {
996 				printf("%s %llu %llu %llu %llu"
997 				    " %llu %llu %llu %ju\n",
998 				    pr.rule.label,
999 				    (unsigned long long)pr.rule.evaluations,
1000 				    (unsigned long long)(pr.rule.packets[0] +
1001 				    pr.rule.packets[1]),
1002 				    (unsigned long long)(pr.rule.bytes[0] +
1003 				    pr.rule.bytes[1]),
1004 				    (unsigned long long)pr.rule.packets[0],
1005 				    (unsigned long long)pr.rule.bytes[0],
1006 				    (unsigned long long)pr.rule.packets[1],
1007 				    (unsigned long long)pr.rule.bytes[1],
1008 				    (uintmax_t)pr.rule.u_states_tot);
1009 			}
1010 			break;
1011 		case PFCTL_SHOW_RULES:
1012 			brace = 0;
1013 			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
1014 				labels = 1;
1015 			INDENT(depth, !(opts & PF_OPT_VERBOSE));
1016 			if (pr.anchor_call[0] &&
1017 			   ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
1018 			   ((void *)p == (void *)pr.anchor_call ||
1019 			   *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
1020 				brace++;
1021 				if ((p = strrchr(pr.anchor_call, '/')) !=
1022 				    NULL)
1023 					p++;
1024 				else
1025 					p = &pr.anchor_call[0];
1026 			} else
1027 				p = &pr.anchor_call[0];
1028 
1029 			print_rule(&pr.rule, p, rule_numbers, numeric);
1030 			if (brace)
1031 				printf(" {\n");
1032 			else
1033 				printf("\n");
1034 			pfctl_print_rule_counters(&pr.rule, opts);
1035 			if (brace) {
1036 				pfctl_show_rules(dev, path, opts, format,
1037 				    p, depth + 1);
1038 				INDENT(depth, !(opts & PF_OPT_VERBOSE));
1039 				printf("}\n");
1040 			}
1041 			break;
1042 		case PFCTL_SHOW_NOTHING:
1043 			break;
1044 		}
1045 		pfctl_clear_pool(&pr.rule.rpool);
1046 	}
1047 	path[len] = '\0';
1048 	return (0);
1049 
1050  error:
1051 	path[len] = '\0';
1052 	return (-1);
1053 }
1054 
1055 int
pfctl_show_nat(int dev,int opts,char * anchorname)1056 pfctl_show_nat(int dev, int opts, char *anchorname)
1057 {
1058 	struct pfioc_rule pr;
1059 	u_int32_t mnr, nr;
1060 	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
1061 	int i, dotitle = opts & PF_OPT_SHOWALL;
1062 
1063 	memset(&pr, 0, sizeof(pr));
1064 	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
1065 	for (i = 0; i < 3; i++) {
1066 		pr.rule.action = nattype[i];
1067 		if (ioctl(dev, DIOCGETRULES, &pr)) {
1068 			warn("DIOCGETRULES");
1069 			return (-1);
1070 		}
1071 		mnr = pr.nr;
1072 		for (nr = 0; nr < mnr; ++nr) {
1073 			pr.nr = nr;
1074 			if (ioctl(dev, DIOCGETRULE, &pr)) {
1075 				warn("DIOCGETRULE");
1076 				return (-1);
1077 			}
1078 			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
1079 			    pr.ticket, nattype[i], anchorname) != 0)
1080 				return (-1);
1081 			if (dotitle) {
1082 				pfctl_print_title("TRANSLATION RULES:");
1083 				dotitle = 0;
1084 			}
1085 			print_rule(&pr.rule, pr.anchor_call,
1086 			    opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
1087 			printf("\n");
1088 			pfctl_print_rule_counters(&pr.rule, opts);
1089 			pfctl_clear_pool(&pr.rule.rpool);
1090 		}
1091 	}
1092 	return (0);
1093 }
1094 
1095 int
pfctl_show_src_nodes(int dev,int opts)1096 pfctl_show_src_nodes(int dev, int opts)
1097 {
1098 	struct pfioc_src_nodes psn;
1099 	struct pf_src_node *p;
1100 	char *inbuf = NULL, *newinbuf = NULL;
1101 	unsigned int len = 0;
1102 	int i;
1103 
1104 	memset(&psn, 0, sizeof(psn));
1105 	for (;;) {
1106 		psn.psn_len = len;
1107 		if (len) {
1108 			newinbuf = realloc(inbuf, len);
1109 			if (newinbuf == NULL)
1110 				err(1, "realloc");
1111 			psn.psn_buf = inbuf = newinbuf;
1112 		}
1113 		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
1114 			warn("DIOCGETSRCNODES");
1115 			free(inbuf);
1116 			return (-1);
1117 		}
1118 		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
1119 			break;
1120 		if (len == 0 && psn.psn_len == 0)
1121 			goto done;
1122 		if (len == 0 && psn.psn_len != 0)
1123 			len = psn.psn_len;
1124 		if (psn.psn_len == 0)
1125 			goto done;	/* no src_nodes */
1126 		len *= 2;
1127 	}
1128 	p = psn.psn_src_nodes;
1129 	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
1130 		pfctl_print_title("SOURCE TRACKING NODES:");
1131 	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
1132 		print_src_node(p, opts);
1133 		p++;
1134 	}
1135 done:
1136 	free(inbuf);
1137 	return (0);
1138 }
1139 
1140 int
pfctl_show_states(int dev,const char * iface,int opts)1141 pfctl_show_states(int dev, const char *iface, int opts)
1142 {
1143 	struct pfioc_states ps;
1144 	struct pfsync_state *p;
1145 	char *inbuf = NULL, *newinbuf = NULL;
1146 	unsigned int len = 0;
1147 	int i, dotitle = (opts & PF_OPT_SHOWALL);
1148 
1149 	memset(&ps, 0, sizeof(ps));
1150 	for (;;) {
1151 		ps.ps_len = len;
1152 		if (len) {
1153 			newinbuf = realloc(inbuf, len);
1154 			if (newinbuf == NULL)
1155 				err(1, "realloc");
1156 			ps.ps_buf = inbuf = newinbuf;
1157 		}
1158 		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
1159 			warn("DIOCGETSTATES");
1160 			free(inbuf);
1161 			return (-1);
1162 		}
1163 		if (ps.ps_len + sizeof(struct pfioc_states) < len)
1164 			break;
1165 		if (len == 0 && ps.ps_len == 0)
1166 			goto done;
1167 		if (len == 0 && ps.ps_len != 0)
1168 			len = ps.ps_len;
1169 		if (ps.ps_len == 0)
1170 			goto done;	/* no states */
1171 		len *= 2;
1172 	}
1173 	p = ps.ps_states;
1174 	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
1175 		if (iface != NULL && strcmp(p->ifname, iface))
1176 			continue;
1177 		if (dotitle) {
1178 			pfctl_print_title("STATES:");
1179 			dotitle = 0;
1180 		}
1181 		print_state(p, opts);
1182 	}
1183 done:
1184 	free(inbuf);
1185 	return (0);
1186 }
1187 
1188 int
pfctl_show_status(int dev,int opts)1189 pfctl_show_status(int dev, int opts)
1190 {
1191 	struct pf_status status;
1192 
1193 	if (ioctl(dev, DIOCGETSTATUS, &status)) {
1194 		warn("DIOCGETSTATUS");
1195 		return (-1);
1196 	}
1197 	if (opts & PF_OPT_SHOWALL)
1198 		pfctl_print_title("INFO:");
1199 	print_status(&status, opts);
1200 	return (0);
1201 }
1202 
1203 int
pfctl_show_running(int dev)1204 pfctl_show_running(int dev)
1205 {
1206 	struct pf_status status;
1207 
1208 	if (ioctl(dev, DIOCGETSTATUS, &status)) {
1209 		warn("DIOCGETSTATUS");
1210 		return (-1);
1211 	}
1212 
1213 	print_running(&status);
1214 	return (!status.running);
1215 }
1216 
1217 int
pfctl_show_timeouts(int dev,int opts)1218 pfctl_show_timeouts(int dev, int opts)
1219 {
1220 	struct pfioc_tm pt;
1221 	int i;
1222 
1223 	if (opts & PF_OPT_SHOWALL)
1224 		pfctl_print_title("TIMEOUTS:");
1225 	memset(&pt, 0, sizeof(pt));
1226 	for (i = 0; pf_timeouts[i].name; i++) {
1227 		pt.timeout = pf_timeouts[i].timeout;
1228 		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
1229 			err(1, "DIOCGETTIMEOUT");
1230 		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
1231 		if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1232 		    pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1233 			printf(" states");
1234 		else
1235 			printf("s");
1236 		printf("\n");
1237 	}
1238 	return (0);
1239 
1240 }
1241 
1242 int
pfctl_show_limits(int dev,int opts)1243 pfctl_show_limits(int dev, int opts)
1244 {
1245 	struct pfioc_limit pl;
1246 	int i;
1247 
1248 	if (opts & PF_OPT_SHOWALL)
1249 		pfctl_print_title("LIMITS:");
1250 	memset(&pl, 0, sizeof(pl));
1251 	for (i = 0; pf_limits[i].name; i++) {
1252 		pl.index = pf_limits[i].index;
1253 		if (ioctl(dev, DIOCGETLIMIT, &pl))
1254 			err(1, "DIOCGETLIMIT");
1255 		printf("%-13s ", pf_limits[i].name);
1256 		if (pl.limit == UINT_MAX)
1257 			printf("unlimited\n");
1258 		else
1259 			printf("hard limit %8u\n", pl.limit);
1260 	}
1261 	return (0);
1262 }
1263 
1264 /* callbacks for rule/nat/rdr/addr */
1265 int
pfctl_add_pool(struct pfctl * pf,struct pf_pool * p,sa_family_t af)1266 pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
1267 {
1268 	struct pf_pooladdr *pa;
1269 
1270 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1271 		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
1272 			err(1, "DIOCBEGINADDRS");
1273 	}
1274 
1275 	pf->paddr.af = af;
1276 	TAILQ_FOREACH(pa, &p->list, entries) {
1277 		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
1278 		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1279 			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
1280 				err(1, "DIOCADDADDR");
1281 		}
1282 	}
1283 	return (0);
1284 }
1285 
1286 int
pfctl_add_rule(struct pfctl * pf,struct pf_rule * r,const char * anchor_call)1287 pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
1288 {
1289 	u_int8_t		rs_num;
1290 	struct pf_rule		*rule;
1291 	struct pf_ruleset	*rs;
1292 	char 			*p;
1293 
1294 	rs_num = pf_get_ruleset_number(r->action);
1295 	if (rs_num == PF_RULESET_MAX)
1296 		errx(1, "Invalid rule type %d", r->action);
1297 
1298 	rs = &pf->anchor->ruleset;
1299 
1300 	if (anchor_call[0] && r->anchor == NULL) {
1301 		/*
1302 		 * Don't make non-brace anchors part of the main anchor pool.
1303 		 */
1304 		if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1305 			err(1, "pfctl_add_rule: calloc");
1306 
1307 		pf_init_ruleset(&r->anchor->ruleset);
1308 		r->anchor->ruleset.anchor = r->anchor;
1309 		if (strlcpy(r->anchor->path, anchor_call,
1310 		    sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1311 			errx(1, "pfctl_add_rule: strlcpy");
1312 		if ((p = strrchr(anchor_call, '/')) != NULL) {
1313 			if (!strlen(p))
1314 				err(1, "pfctl_add_rule: bad anchor name %s",
1315 				    anchor_call);
1316 		} else
1317 			p = (char *)anchor_call;
1318 		if (strlcpy(r->anchor->name, p,
1319 		    sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1320 			errx(1, "pfctl_add_rule: strlcpy");
1321 	}
1322 
1323 	if ((rule = calloc(1, sizeof(*rule))) == NULL)
1324 		err(1, "calloc");
1325 	bcopy(r, rule, sizeof(*rule));
1326 	TAILQ_INIT(&rule->rpool.list);
1327 	pfctl_move_pool(&r->rpool, &rule->rpool);
1328 
1329 	TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1330 	return (0);
1331 }
1332 
1333 int
pfctl_ruleset_trans(struct pfctl * pf,char * path,struct pf_anchor * a)1334 pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
1335 {
1336 	int osize = pf->trans->pfrb_size;
1337 
1338 	if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1339 		if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1340 		    pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1341 		    pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1342 			return (1);
1343 	}
1344 	if (a == pf->astack[0] && ((altqsupport &&
1345 	    (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1346 		if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1347 			return (2);
1348 	}
1349 	if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1350 		if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1351 		    pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1352 			return (3);
1353 	}
1354 	if (pf->loadopt & PFCTL_FLAG_TABLE)
1355 		if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1356 			return (4);
1357 	if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1358 		return (5);
1359 
1360 	return (0);
1361 }
1362 
1363 int
pfctl_load_ruleset(struct pfctl * pf,char * path,struct pf_ruleset * rs,int rs_num,int depth)1364 pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
1365     int rs_num, int depth)
1366 {
1367 	struct pf_rule *r;
1368 	int		error, len = strlen(path);
1369 	int		brace = 0;
1370 
1371 	pf->anchor = rs->anchor;
1372 
1373 	if (path[0])
1374 		snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
1375 	else
1376 		snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
1377 
1378 	if (depth) {
1379 		if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
1380 			brace++;
1381 			if (pf->opts & PF_OPT_VERBOSE)
1382 				printf(" {\n");
1383 			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1384 			    (error = pfctl_ruleset_trans(pf,
1385 			    path, rs->anchor))) {
1386 				printf("pfctl_load_rulesets: "
1387 				    "pfctl_ruleset_trans %d\n", error);
1388 				goto error;
1389 			}
1390 		} else if (pf->opts & PF_OPT_VERBOSE)
1391 			printf("\n");
1392 
1393 	}
1394 
1395 	if (pf->optimize && rs_num == PF_RULESET_FILTER)
1396 		pfctl_optimize_ruleset(pf, rs);
1397 
1398 	while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
1399 		TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
1400 		if ((error = pfctl_load_rule(pf, path, r, depth)))
1401 			goto error;
1402 		if (r->anchor) {
1403 			if ((error = pfctl_load_ruleset(pf, path,
1404 			    &r->anchor->ruleset, rs_num, depth + 1)))
1405 				goto error;
1406 		} else if (pf->opts & PF_OPT_VERBOSE)
1407 			printf("\n");
1408 		free(r);
1409 	}
1410 	if (brace && pf->opts & PF_OPT_VERBOSE) {
1411 		INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
1412 		printf("}\n");
1413 	}
1414 	path[len] = '\0';
1415 	return (0);
1416 
1417  error:
1418 	path[len] = '\0';
1419 	return (error);
1420 
1421 }
1422 
1423 int
pfctl_load_rule(struct pfctl * pf,char * path,struct pf_rule * r,int depth)1424 pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
1425 {
1426 	u_int8_t		rs_num = pf_get_ruleset_number(r->action);
1427 	char			*name;
1428 	struct pfioc_rule	pr;
1429 	int			len = strlen(path);
1430 
1431 	bzero(&pr, sizeof(pr));
1432 	/* set up anchor before adding to path for anchor_call */
1433 	if ((pf->opts & PF_OPT_NOACTION) == 0)
1434 		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
1435 	if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
1436 		errx(1, "pfctl_load_rule: strlcpy");
1437 
1438 	if (r->anchor) {
1439 		if (r->anchor->match) {
1440 			if (path[0])
1441 				snprintf(&path[len], MAXPATHLEN - len,
1442 				    "/%s", r->anchor->name);
1443 			else
1444 				snprintf(&path[len], MAXPATHLEN - len,
1445 				    "%s", r->anchor->name);
1446 			name = path;
1447 		} else
1448 			name = r->anchor->path;
1449 	} else
1450 		name = "";
1451 
1452 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1453 		if (pfctl_add_pool(pf, &r->rpool, r->af))
1454 			return (1);
1455 		pr.pool_ticket = pf->paddr.ticket;
1456 		memcpy(&pr.rule, r, sizeof(pr.rule));
1457 		if (r->anchor && strlcpy(pr.anchor_call, name,
1458 		    sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
1459 			errx(1, "pfctl_load_rule: strlcpy");
1460 		if (ioctl(pf->dev, DIOCADDRULE, &pr))
1461 			err(1, "DIOCADDRULE");
1462 	}
1463 
1464 	if (pf->opts & PF_OPT_VERBOSE) {
1465 		INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
1466 		print_rule(r, r->anchor ? r->anchor->name : "",
1467 		    pf->opts & PF_OPT_VERBOSE2,
1468 		    pf->opts & PF_OPT_NUMERIC);
1469 	}
1470 	path[len] = '\0';
1471 	pfctl_clear_pool(&r->rpool);
1472 	return (0);
1473 }
1474 
1475 int
pfctl_add_altq(struct pfctl * pf,struct pf_altq * a)1476 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1477 {
1478 	if (altqsupport &&
1479 	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1480 		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1481 		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1482 			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1483 				if (errno == ENXIO)
1484 					errx(1, "qtype not configured");
1485 				else if (errno == ENODEV)
1486 					errx(1, "%s: driver does not support "
1487 					    "altq", a->ifname);
1488 				else
1489 					err(1, "DIOCADDALTQ");
1490 			}
1491 		}
1492 		pfaltq_store(&pf->paltq->altq);
1493 	}
1494 	return (0);
1495 }
1496 
1497 int
pfctl_rules(int dev,char * filename,int opts,int optimize,char * anchorname,struct pfr_buffer * trans)1498 pfctl_rules(int dev, char *filename, int opts, int optimize,
1499     char *anchorname, struct pfr_buffer *trans)
1500 {
1501 #define ERR(x) do { warn(x); goto _error; } while(0)
1502 #define ERRX(x) do { warnx(x); goto _error; } while(0)
1503 
1504 	struct pfr_buffer	*t, buf;
1505 	struct pfioc_altq	 pa;
1506 	struct pfctl		 pf;
1507 	struct pf_ruleset	*rs;
1508 	struct pfr_table	 trs;
1509 	char			*path;
1510 	int			 osize;
1511 
1512 	RB_INIT(&pf_anchors);
1513 	memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
1514 	pf_init_ruleset(&pf_main_anchor.ruleset);
1515 	pf_main_anchor.ruleset.anchor = &pf_main_anchor;
1516 	if (trans == NULL) {
1517 		bzero(&buf, sizeof(buf));
1518 		buf.pfrb_type = PFRB_TRANS;
1519 		t = &buf;
1520 		osize = 0;
1521 	} else {
1522 		t = trans;
1523 		osize = t->pfrb_size;
1524 	}
1525 
1526 	memset(&pa, 0, sizeof(pa));
1527 	memset(&pf, 0, sizeof(pf));
1528 	memset(&trs, 0, sizeof(trs));
1529 	if ((path = calloc(1, MAXPATHLEN)) == NULL)
1530 		ERRX("pfctl_rules: calloc");
1531 	if (strlcpy(trs.pfrt_anchor, anchorname,
1532 	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1533 		ERRX("pfctl_rules: strlcpy");
1534 	pf.dev = dev;
1535 	pf.opts = opts;
1536 	pf.optimize = optimize;
1537 	pf.loadopt = loadopt;
1538 
1539 	/* non-brace anchor, create without resolving the path */
1540 	if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
1541 		ERRX("pfctl_rules: calloc");
1542 	rs = &pf.anchor->ruleset;
1543 	pf_init_ruleset(rs);
1544 	rs->anchor = pf.anchor;
1545 	if (strlcpy(pf.anchor->path, anchorname,
1546 	    sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
1547 		errx(1, "pfctl_add_rule: strlcpy");
1548 	if (strlcpy(pf.anchor->name, anchorname,
1549 	    sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
1550 		errx(1, "pfctl_add_rule: strlcpy");
1551 
1552 
1553 	pf.astack[0] = pf.anchor;
1554 	pf.asd = 0;
1555 	if (anchorname[0])
1556 		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1557 	pf.paltq = &pa;
1558 	pf.trans = t;
1559 	pfctl_init_options(&pf);
1560 
1561 	if ((opts & PF_OPT_NOACTION) == 0) {
1562 		/*
1563 		 * XXX For the time being we need to open transactions for
1564 		 * the main ruleset before parsing, because tables are still
1565 		 * loaded at parse time.
1566 		 */
1567 		if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
1568 			ERRX("pfctl_rules");
1569 		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1570 			pa.ticket =
1571 			    pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
1572 		if (pf.loadopt & PFCTL_FLAG_TABLE)
1573 			pf.astack[0]->ruleset.tticket =
1574 			    pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
1575 	}
1576 
1577 	if (parse_config(filename, &pf) < 0) {
1578 		if ((opts & PF_OPT_NOACTION) == 0)
1579 			ERRX("Syntax error in config file: "
1580 			    "pf rules not loaded");
1581 		else
1582 			goto _error;
1583 	}
1584 	if (loadopt & PFCTL_FLAG_OPTION)
1585 		pfctl_adjust_skip_ifaces(&pf);
1586 
1587 	if ((pf.loadopt & PFCTL_FLAG_FILTER &&
1588 	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
1589 	    (pf.loadopt & PFCTL_FLAG_NAT &&
1590 	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
1591 	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
1592 	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
1593 	    (pf.loadopt & PFCTL_FLAG_FILTER &&
1594 	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
1595 		if ((opts & PF_OPT_NOACTION) == 0)
1596 			ERRX("Unable to load rules into kernel");
1597 		else
1598 			goto _error;
1599 	}
1600 
1601 	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1602 		if (check_commit_altq(dev, opts) != 0)
1603 			ERRX("errors in altq config");
1604 
1605 	/* process "load anchor" directives */
1606 	if (!anchorname[0])
1607 		if (pfctl_load_anchors(dev, &pf, t) == -1)
1608 			ERRX("load anchors");
1609 
1610 	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1611 		if (!anchorname[0])
1612 			if (pfctl_load_options(&pf))
1613 				goto _error;
1614 		if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
1615 			ERR("DIOCXCOMMIT");
1616 	}
1617 	return (0);
1618 
1619 _error:
1620 	if (trans == NULL) {	/* main ruleset */
1621 		if ((opts & PF_OPT_NOACTION) == 0)
1622 			if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
1623 				err(1, "DIOCXROLLBACK");
1624 		exit(1);
1625 	} else {		/* sub ruleset */
1626 		return (-1);
1627 	}
1628 
1629 #undef ERR
1630 #undef ERRX
1631 }
1632 
1633 FILE *
pfctl_fopen(const char * name,const char * mode)1634 pfctl_fopen(const char *name, const char *mode)
1635 {
1636 	struct stat	 st;
1637 	FILE		*fp;
1638 
1639 	fp = fopen(name, mode);
1640 	if (fp == NULL)
1641 		return (NULL);
1642 	if (fstat(fileno(fp), &st)) {
1643 		fclose(fp);
1644 		return (NULL);
1645 	}
1646 	if (S_ISDIR(st.st_mode)) {
1647 		fclose(fp);
1648 		errno = EISDIR;
1649 		return (NULL);
1650 	}
1651 	return (fp);
1652 }
1653 
1654 void
pfctl_init_options(struct pfctl * pf)1655 pfctl_init_options(struct pfctl *pf)
1656 {
1657 
1658 	pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1659 	pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1660 	pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1661 	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1662 	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1663 	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1664 	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1665 	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1666 	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1667 	pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1668 	pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1669 	pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1670 	pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1671 	pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1672 	pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1673 	pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1674 	pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1675 	pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1676 	pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
1677 	pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
1678 
1679 	pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
1680 	pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
1681 	pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
1682 	pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
1683 
1684 	pf->debug = PF_DEBUG_URGENT;
1685 }
1686 
1687 int
pfctl_load_options(struct pfctl * pf)1688 pfctl_load_options(struct pfctl *pf)
1689 {
1690 	int i, error = 0;
1691 
1692 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1693 		return (0);
1694 
1695 	/* load limits */
1696 	for (i = 0; i < PF_LIMIT_MAX; i++) {
1697 		if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1698 			continue;
1699 		if (pfctl_load_limit(pf, i, pf->limit[i]))
1700 			error = 1;
1701 	}
1702 
1703 	/*
1704 	 * If we've set the limit, but haven't explicitly set adaptive
1705 	 * timeouts, do it now with a start of 60% and end of 120%.
1706 	 */
1707 	if (pf->limit_set[PF_LIMIT_STATES] &&
1708 	    !pf->timeout_set[PFTM_ADAPTIVE_START] &&
1709 	    !pf->timeout_set[PFTM_ADAPTIVE_END]) {
1710 		pf->timeout[PFTM_ADAPTIVE_START] =
1711 			(pf->limit[PF_LIMIT_STATES] / 10) * 6;
1712 		pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
1713 		pf->timeout[PFTM_ADAPTIVE_END] =
1714 			(pf->limit[PF_LIMIT_STATES] / 10) * 12;
1715 		pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
1716 	}
1717 
1718 	/* load timeouts */
1719 	for (i = 0; i < PFTM_MAX; i++) {
1720 		if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1721 			continue;
1722 		if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1723 			error = 1;
1724 	}
1725 
1726 	/* load debug */
1727 	if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1728 		if (pfctl_load_debug(pf, pf->debug))
1729 			error = 1;
1730 
1731 	/* load logif */
1732 	if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1733 		if (pfctl_load_logif(pf, pf->ifname))
1734 			error = 1;
1735 
1736 	/* load hostid */
1737 	if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1738 		if (pfctl_load_hostid(pf, pf->hostid))
1739 			error = 1;
1740 
1741 	return (error);
1742 }
1743 
1744 int
pfctl_set_limit(struct pfctl * pf,const char * opt,unsigned int limit)1745 pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1746 {
1747 	int i;
1748 
1749 
1750 	for (i = 0; pf_limits[i].name; i++) {
1751 		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1752 			pf->limit[pf_limits[i].index] = limit;
1753 			pf->limit_set[pf_limits[i].index] = 1;
1754 			break;
1755 		}
1756 	}
1757 	if (pf_limits[i].name == NULL) {
1758 		warnx("Bad pool name.");
1759 		return (1);
1760 	}
1761 
1762 	if (pf->opts & PF_OPT_VERBOSE)
1763 		printf("set limit %s %d\n", opt, limit);
1764 
1765 	return (0);
1766 }
1767 
1768 int
pfctl_load_limit(struct pfctl * pf,unsigned int index,unsigned int limit)1769 pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1770 {
1771 	struct pfioc_limit pl;
1772 
1773 	memset(&pl, 0, sizeof(pl));
1774 	pl.index = index;
1775 	pl.limit = limit;
1776 	if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1777 		if (errno == EBUSY)
1778 			warnx("Current pool size exceeds requested hard limit");
1779 		else
1780 			warnx("DIOCSETLIMIT");
1781 		return (1);
1782 	}
1783 	return (0);
1784 }
1785 
1786 int
pfctl_set_timeout(struct pfctl * pf,const char * opt,int seconds,int quiet)1787 pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1788 {
1789 	int i;
1790 
1791 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1792 		return (0);
1793 
1794 	for (i = 0; pf_timeouts[i].name; i++) {
1795 		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1796 			pf->timeout[pf_timeouts[i].timeout] = seconds;
1797 			pf->timeout_set[pf_timeouts[i].timeout] = 1;
1798 			break;
1799 		}
1800 	}
1801 
1802 	if (pf_timeouts[i].name == NULL) {
1803 		warnx("Bad timeout name.");
1804 		return (1);
1805 	}
1806 
1807 
1808 	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1809 		printf("set timeout %s %d\n", opt, seconds);
1810 
1811 	return (0);
1812 }
1813 
1814 int
pfctl_load_timeout(struct pfctl * pf,unsigned int timeout,unsigned int seconds)1815 pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1816 {
1817 	struct pfioc_tm pt;
1818 
1819 	memset(&pt, 0, sizeof(pt));
1820 	pt.timeout = timeout;
1821 	pt.seconds = seconds;
1822 	if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1823 		warnx("DIOCSETTIMEOUT");
1824 		return (1);
1825 	}
1826 	return (0);
1827 }
1828 
1829 int
pfctl_set_optimization(struct pfctl * pf,const char * opt)1830 pfctl_set_optimization(struct pfctl *pf, const char *opt)
1831 {
1832 	const struct pf_hint *hint;
1833 	int i, r;
1834 
1835 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1836 		return (0);
1837 
1838 	for (i = 0; pf_hints[i].name; i++)
1839 		if (strcasecmp(opt, pf_hints[i].name) == 0)
1840 			break;
1841 
1842 	hint = pf_hints[i].hint;
1843 	if (hint == NULL) {
1844 		warnx("invalid state timeouts optimization");
1845 		return (1);
1846 	}
1847 
1848 	for (i = 0; hint[i].name; i++)
1849 		if ((r = pfctl_set_timeout(pf, hint[i].name,
1850 		    hint[i].timeout, 1)))
1851 			return (r);
1852 
1853 	if (pf->opts & PF_OPT_VERBOSE)
1854 		printf("set optimization %s\n", opt);
1855 
1856 	return (0);
1857 }
1858 
1859 int
pfctl_set_logif(struct pfctl * pf,char * ifname)1860 pfctl_set_logif(struct pfctl *pf, char *ifname)
1861 {
1862 
1863 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1864 		return (0);
1865 
1866 	if (!strcmp(ifname, "none")) {
1867 		free(pf->ifname);
1868 		pf->ifname = NULL;
1869 	} else {
1870 		pf->ifname = strdup(ifname);
1871 		if (!pf->ifname)
1872 			errx(1, "pfctl_set_logif: strdup");
1873 	}
1874 	pf->ifname_set = 1;
1875 
1876 	if (pf->opts & PF_OPT_VERBOSE)
1877 		printf("set loginterface %s\n", ifname);
1878 
1879 	return (0);
1880 }
1881 
1882 int
pfctl_load_logif(struct pfctl * pf,char * ifname)1883 pfctl_load_logif(struct pfctl *pf, char *ifname)
1884 {
1885 	struct pfioc_if pi;
1886 
1887 	memset(&pi, 0, sizeof(pi));
1888 	if (ifname && strlcpy(pi.ifname, ifname,
1889 	    sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1890 		warnx("pfctl_load_logif: strlcpy");
1891 		return (1);
1892 	}
1893 	if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1894 		warnx("DIOCSETSTATUSIF");
1895 		return (1);
1896 	}
1897 	return (0);
1898 }
1899 
1900 int
pfctl_set_hostid(struct pfctl * pf,u_int32_t hostid)1901 pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1902 {
1903 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1904 		return (0);
1905 
1906 	HTONL(hostid);
1907 
1908 	pf->hostid = hostid;
1909 	pf->hostid_set = 1;
1910 
1911 	if (pf->opts & PF_OPT_VERBOSE)
1912 		printf("set hostid 0x%08x\n", ntohl(hostid));
1913 
1914 	return (0);
1915 }
1916 
1917 int
pfctl_load_hostid(struct pfctl * pf,u_int32_t hostid)1918 pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1919 {
1920 	if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1921 		warnx("DIOCSETHOSTID");
1922 		return (1);
1923 	}
1924 	return (0);
1925 }
1926 
1927 int
pfctl_set_debug(struct pfctl * pf,char * d)1928 pfctl_set_debug(struct pfctl *pf, char *d)
1929 {
1930 	u_int32_t	level;
1931 
1932 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1933 		return (0);
1934 
1935 	if (!strcmp(d, "none"))
1936 		pf->debug = PF_DEBUG_NONE;
1937 	else if (!strcmp(d, "urgent"))
1938 		pf->debug = PF_DEBUG_URGENT;
1939 	else if (!strcmp(d, "misc"))
1940 		pf->debug = PF_DEBUG_MISC;
1941 	else if (!strcmp(d, "loud"))
1942 		pf->debug = PF_DEBUG_NOISY;
1943 	else {
1944 		warnx("unknown debug level \"%s\"", d);
1945 		return (-1);
1946 	}
1947 
1948 	pf->debug_set = 1;
1949 	level = pf->debug;
1950 
1951 	if ((pf->opts & PF_OPT_NOACTION) == 0)
1952 		if (ioctl(dev, DIOCSETDEBUG, &level))
1953 			err(1, "DIOCSETDEBUG");
1954 
1955 	if (pf->opts & PF_OPT_VERBOSE)
1956 		printf("set debug %s\n", d);
1957 
1958 	return (0);
1959 }
1960 
1961 int
pfctl_load_debug(struct pfctl * pf,unsigned int level)1962 pfctl_load_debug(struct pfctl *pf, unsigned int level)
1963 {
1964 	if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1965 		warnx("DIOCSETDEBUG");
1966 		return (1);
1967 	}
1968 	return (0);
1969 }
1970 
1971 int
pfctl_set_interface_flags(struct pfctl * pf,char * ifname,int flags,int how)1972 pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1973 {
1974 	struct pfioc_iface	pi;
1975 	struct node_host	*h = NULL, *n = NULL;
1976 
1977 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1978 		return (0);
1979 
1980 	bzero(&pi, sizeof(pi));
1981 
1982 	pi.pfiio_flags = flags;
1983 
1984 	/* Make sure our cache matches the kernel. If we set or clear the flag
1985 	 * for a group this applies to all members. */
1986 	h = ifa_grouplookup(ifname, 0);
1987 	for (n = h; n != NULL; n = n->next)
1988 		pfctl_set_interface_flags(pf, n->ifname, flags, how);
1989 
1990 	if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
1991 	    sizeof(pi.pfiio_name))
1992 		errx(1, "pfctl_set_interface_flags: strlcpy");
1993 
1994 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1995 		if (how == 0) {
1996 			if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
1997 				err(1, "DIOCCLRIFFLAG");
1998 		} else {
1999 			if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
2000 				err(1, "DIOCSETIFFLAG");
2001 			pfctl_check_skip_ifaces(ifname);
2002 		}
2003 	}
2004 	return (0);
2005 }
2006 
2007 void
pfctl_debug(int dev,u_int32_t level,int opts)2008 pfctl_debug(int dev, u_int32_t level, int opts)
2009 {
2010 	if (ioctl(dev, DIOCSETDEBUG, &level))
2011 		err(1, "DIOCSETDEBUG");
2012 	if ((opts & PF_OPT_QUIET) == 0) {
2013 		fprintf(stderr, "debug level set to '");
2014 		switch (level) {
2015 		case PF_DEBUG_NONE:
2016 			fprintf(stderr, "none");
2017 			break;
2018 		case PF_DEBUG_URGENT:
2019 			fprintf(stderr, "urgent");
2020 			break;
2021 		case PF_DEBUG_MISC:
2022 			fprintf(stderr, "misc");
2023 			break;
2024 		case PF_DEBUG_NOISY:
2025 			fprintf(stderr, "loud");
2026 			break;
2027 		default:
2028 			fprintf(stderr, "<invalid>");
2029 			break;
2030 		}
2031 		fprintf(stderr, "'\n");
2032 	}
2033 }
2034 
2035 int
pfctl_test_altqsupport(int dev,int opts)2036 pfctl_test_altqsupport(int dev, int opts)
2037 {
2038 	struct pfioc_altq pa;
2039 
2040 	if (ioctl(dev, DIOCGETALTQS, &pa)) {
2041 		if (errno == ENODEV) {
2042 			if (opts & PF_OPT_VERBOSE)
2043 				fprintf(stderr, "No ALTQ support in kernel\n"
2044 				    "ALTQ related functions disabled\n");
2045 			return (0);
2046 		} else
2047 			err(1, "DIOCGETALTQS");
2048 	}
2049 	return (1);
2050 }
2051 
2052 int
pfctl_show_anchors(int dev,int opts,char * anchorname)2053 pfctl_show_anchors(int dev, int opts, char *anchorname)
2054 {
2055 	struct pfioc_ruleset	 pr;
2056 	u_int32_t		 mnr, nr;
2057 
2058 	memset(&pr, 0, sizeof(pr));
2059 	memcpy(pr.path, anchorname, sizeof(pr.path));
2060 	if (ioctl(dev, DIOCGETRULESETS, &pr)) {
2061 		if (errno == EINVAL)
2062 			fprintf(stderr, "Anchor '%s' not found.\n",
2063 			    anchorname);
2064 		else
2065 			err(1, "DIOCGETRULESETS");
2066 		return (-1);
2067 	}
2068 	mnr = pr.nr;
2069 	for (nr = 0; nr < mnr; ++nr) {
2070 		char sub[MAXPATHLEN];
2071 
2072 		pr.nr = nr;
2073 		if (ioctl(dev, DIOCGETRULESET, &pr))
2074 			err(1, "DIOCGETRULESET");
2075 		if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
2076 			continue;
2077 		sub[0] = 0;
2078 		if (pr.path[0]) {
2079 			strlcat(sub, pr.path, sizeof(sub));
2080 			strlcat(sub, "/", sizeof(sub));
2081 		}
2082 		strlcat(sub, pr.name, sizeof(sub));
2083 		if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
2084 			printf("  %s\n", sub);
2085 		if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
2086 			return (-1);
2087 	}
2088 	return (0);
2089 }
2090 
2091 const char *
pfctl_lookup_option(char * cmd,const char ** list)2092 pfctl_lookup_option(char *cmd, const char **list)
2093 {
2094 	if (cmd != NULL && *cmd)
2095 		for (; *list; list++)
2096 			if (!strncmp(cmd, *list, strlen(cmd)))
2097 				return (*list);
2098 	return (NULL);
2099 }
2100 
2101 int
main(int argc,char * argv[])2102 main(int argc, char *argv[])
2103 {
2104 	int	 error = 0;
2105 	int	 ch;
2106 	int	 mode = O_RDONLY;
2107 	int	 opts = 0;
2108 	int	 optimize = PF_OPTIMIZE_BASIC;
2109 	char	 anchorname[MAXPATHLEN];
2110 	char	*path;
2111 
2112 	if (argc < 2)
2113 		usage();
2114 
2115 	while ((ch = getopt(argc, argv,
2116 	    "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
2117 		switch (ch) {
2118 		case 'a':
2119 			anchoropt = optarg;
2120 			break;
2121 		case 'd':
2122 			opts |= PF_OPT_DISABLE;
2123 			mode = O_RDWR;
2124 			break;
2125 		case 'D':
2126 			if (pfctl_cmdline_symset(optarg) < 0)
2127 				warnx("could not parse macro definition %s",
2128 				    optarg);
2129 			break;
2130 		case 'e':
2131 			opts |= PF_OPT_ENABLE;
2132 			mode = O_RDWR;
2133 			break;
2134 		case 'q':
2135 			opts |= PF_OPT_QUIET;
2136 			break;
2137 		case 'F':
2138 			clearopt = pfctl_lookup_option(optarg, clearopt_list);
2139 			if (clearopt == NULL) {
2140 				warnx("Unknown flush modifier '%s'", optarg);
2141 				usage();
2142 			}
2143 			mode = O_RDWR;
2144 			break;
2145 		case 'i':
2146 			ifaceopt = optarg;
2147 			break;
2148 		case 'k':
2149 			if (state_killers >= 2) {
2150 				warnx("can only specify -k twice");
2151 				usage();
2152 				/* NOTREACHED */
2153 			}
2154 			state_kill[state_killers++] = optarg;
2155 			mode = O_RDWR;
2156 			break;
2157 		case 'K':
2158 			if (src_node_killers >= 2) {
2159 				warnx("can only specify -K twice");
2160 				usage();
2161 				/* NOTREACHED */
2162 			}
2163 			src_node_kill[src_node_killers++] = optarg;
2164 			mode = O_RDWR;
2165 			break;
2166 		case 'm':
2167 			opts |= PF_OPT_MERGE;
2168 			break;
2169 		case 'n':
2170 			opts |= PF_OPT_NOACTION;
2171 			break;
2172 		case 'N':
2173 			loadopt |= PFCTL_FLAG_NAT;
2174 			break;
2175 		case 'r':
2176 			opts |= PF_OPT_USEDNS;
2177 			break;
2178 		case 'f':
2179 			rulesopt = optarg;
2180 			mode = O_RDWR;
2181 			break;
2182 		case 'g':
2183 			opts |= PF_OPT_DEBUG;
2184 			break;
2185 		case 'A':
2186 			loadopt |= PFCTL_FLAG_ALTQ;
2187 			break;
2188 		case 'R':
2189 			loadopt |= PFCTL_FLAG_FILTER;
2190 			break;
2191 		case 'o':
2192 			optiopt = pfctl_lookup_option(optarg, optiopt_list);
2193 			if (optiopt == NULL) {
2194 				warnx("Unknown optimization '%s'", optarg);
2195 				usage();
2196 			}
2197 			opts |= PF_OPT_OPTIMIZE;
2198 			break;
2199 		case 'O':
2200 			loadopt |= PFCTL_FLAG_OPTION;
2201 			break;
2202 		case 'p':
2203 			pf_device = optarg;
2204 			break;
2205 		case 'P':
2206 			opts |= PF_OPT_NUMERIC;
2207 			break;
2208 		case 's':
2209 			showopt = pfctl_lookup_option(optarg, showopt_list);
2210 			if (showopt == NULL) {
2211 				warnx("Unknown show modifier '%s'", optarg);
2212 				usage();
2213 			}
2214 			break;
2215 		case 't':
2216 			tableopt = optarg;
2217 			break;
2218 		case 'T':
2219 			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
2220 			if (tblcmdopt == NULL) {
2221 				warnx("Unknown table command '%s'", optarg);
2222 				usage();
2223 			}
2224 			break;
2225 		case 'v':
2226 			if (opts & PF_OPT_VERBOSE)
2227 				opts |= PF_OPT_VERBOSE2;
2228 			opts |= PF_OPT_VERBOSE;
2229 			break;
2230 		case 'x':
2231 			debugopt = pfctl_lookup_option(optarg, debugopt_list);
2232 			if (debugopt == NULL) {
2233 				warnx("Unknown debug level '%s'", optarg);
2234 				usage();
2235 			}
2236 			mode = O_RDWR;
2237 			break;
2238 		case 'z':
2239 			opts |= PF_OPT_CLRRULECTRS;
2240 			mode = O_RDWR;
2241 			break;
2242 		case 'h':
2243 			/* FALLTHROUGH */
2244 		default:
2245 			usage();
2246 			/* NOTREACHED */
2247 		}
2248 	}
2249 
2250 	if (tblcmdopt != NULL) {
2251 		argc -= optind;
2252 		argv += optind;
2253 		ch = *tblcmdopt;
2254 		if (ch == 'l') {
2255 			loadopt |= PFCTL_FLAG_TABLE;
2256 			tblcmdopt = NULL;
2257 		} else
2258 			mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
2259 	} else if (argc != optind) {
2260 		warnx("unknown command line argument: %s ...", argv[optind]);
2261 		usage();
2262 		/* NOTREACHED */
2263 	}
2264 	if (loadopt == 0)
2265 		loadopt = ~0;
2266 
2267 	if ((path = calloc(1, MAXPATHLEN)) == NULL)
2268 		errx(1, "pfctl: calloc");
2269 	memset(anchorname, 0, sizeof(anchorname));
2270 	if (anchoropt != NULL) {
2271 		int len = strlen(anchoropt);
2272 
2273 		if (anchoropt[len - 1] == '*') {
2274 			if (len >= 2 && anchoropt[len - 2] == '/')
2275 				anchoropt[len - 2] = '\0';
2276 			else
2277 				anchoropt[len - 1] = '\0';
2278 			opts |= PF_OPT_RECURSE;
2279 		}
2280 		if (strlcpy(anchorname, anchoropt,
2281 		    sizeof(anchorname)) >= sizeof(anchorname))
2282 			errx(1, "anchor name '%s' too long",
2283 			    anchoropt);
2284 		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
2285 	}
2286 
2287 	if ((opts & PF_OPT_NOACTION) == 0) {
2288 		dev = open(pf_device, mode);
2289 		if (dev == -1)
2290 			err(1, "%s", pf_device);
2291 		altqsupport = pfctl_test_altqsupport(dev, opts);
2292 	} else {
2293 		dev = open(pf_device, O_RDONLY);
2294 		if (dev >= 0)
2295 			opts |= PF_OPT_DUMMYACTION;
2296 		/* turn off options */
2297 		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
2298 		clearopt = showopt = debugopt = NULL;
2299 #if !defined(ENABLE_ALTQ)
2300 		altqsupport = 0;
2301 #else
2302 		altqsupport = 1;
2303 #endif
2304 	}
2305 
2306 	if (opts & PF_OPT_DISABLE)
2307 		if (pfctl_disable(dev, opts))
2308 			error = 1;
2309 
2310 	if (showopt != NULL) {
2311 		switch (*showopt) {
2312 		case 'A':
2313 			pfctl_show_anchors(dev, opts, anchorname);
2314 			break;
2315 		case 'r':
2316 			pfctl_load_fingerprints(dev, opts);
2317 			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
2318 			    anchorname, 0);
2319 			break;
2320 		case 'l':
2321 			pfctl_load_fingerprints(dev, opts);
2322 			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
2323 			    anchorname, 0);
2324 			break;
2325 		case 'n':
2326 			pfctl_load_fingerprints(dev, opts);
2327 			pfctl_show_nat(dev, opts, anchorname);
2328 			break;
2329 		case 'q':
2330 			pfctl_show_altq(dev, ifaceopt, opts,
2331 			    opts & PF_OPT_VERBOSE2);
2332 			break;
2333 		case 's':
2334 			pfctl_show_states(dev, ifaceopt, opts);
2335 			break;
2336 		case 'S':
2337 			pfctl_show_src_nodes(dev, opts);
2338 			break;
2339 		case 'i':
2340 			pfctl_show_status(dev, opts);
2341 			break;
2342 		case 'R':
2343 			error = pfctl_show_running(dev);
2344 			break;
2345 		case 't':
2346 			pfctl_show_timeouts(dev, opts);
2347 			break;
2348 		case 'm':
2349 			pfctl_show_limits(dev, opts);
2350 			break;
2351 		case 'a':
2352 			opts |= PF_OPT_SHOWALL;
2353 			pfctl_load_fingerprints(dev, opts);
2354 
2355 			pfctl_show_nat(dev, opts, anchorname);
2356 			pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
2357 			pfctl_show_altq(dev, ifaceopt, opts, 0);
2358 			pfctl_show_states(dev, ifaceopt, opts);
2359 			pfctl_show_src_nodes(dev, opts);
2360 			pfctl_show_status(dev, opts);
2361 			pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
2362 			pfctl_show_timeouts(dev, opts);
2363 			pfctl_show_limits(dev, opts);
2364 			pfctl_show_tables(anchorname, opts);
2365 			pfctl_show_fingerprints(opts);
2366 			break;
2367 		case 'T':
2368 			pfctl_show_tables(anchorname, opts);
2369 			break;
2370 		case 'o':
2371 			pfctl_load_fingerprints(dev, opts);
2372 			pfctl_show_fingerprints(opts);
2373 			break;
2374 		case 'I':
2375 			pfctl_show_ifaces(ifaceopt, opts);
2376 			break;
2377 		}
2378 	}
2379 
2380 	if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
2381 		pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
2382 		    anchorname, 0);
2383 
2384 	if (clearopt != NULL) {
2385 		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2386 			errx(1, "anchor names beginning with '_' cannot "
2387 			    "be modified from the command line");
2388 
2389 		switch (*clearopt) {
2390 		case 'r':
2391 			pfctl_clear_rules(dev, opts, anchorname);
2392 			break;
2393 		case 'n':
2394 			pfctl_clear_nat(dev, opts, anchorname);
2395 			break;
2396 		case 'q':
2397 			pfctl_clear_altq(dev, opts);
2398 			break;
2399 		case 's':
2400 			pfctl_clear_states(dev, ifaceopt, opts);
2401 			break;
2402 		case 'S':
2403 			pfctl_clear_src_nodes(dev, opts);
2404 			break;
2405 		case 'i':
2406 			pfctl_clear_stats(dev, opts);
2407 			break;
2408 		case 'a':
2409 			pfctl_clear_rules(dev, opts, anchorname);
2410 			pfctl_clear_nat(dev, opts, anchorname);
2411 			pfctl_clear_tables(anchorname, opts);
2412 			if (!*anchorname) {
2413 				pfctl_clear_altq(dev, opts);
2414 				pfctl_clear_states(dev, ifaceopt, opts);
2415 				pfctl_clear_src_nodes(dev, opts);
2416 				pfctl_clear_stats(dev, opts);
2417 				pfctl_clear_fingerprints(dev, opts);
2418 				pfctl_clear_interface_flags(dev, opts);
2419 			}
2420 			break;
2421 		case 'o':
2422 			pfctl_clear_fingerprints(dev, opts);
2423 			break;
2424 		case 'T':
2425 			pfctl_clear_tables(anchorname, opts);
2426 			break;
2427 		}
2428 	}
2429 	if (state_killers) {
2430 		if (!strcmp(state_kill[0], "label"))
2431 			pfctl_label_kill_states(dev, ifaceopt, opts);
2432 		else if (!strcmp(state_kill[0], "id"))
2433 			pfctl_id_kill_states(dev, ifaceopt, opts);
2434 		else
2435 			pfctl_net_kill_states(dev, ifaceopt, opts);
2436 	}
2437 
2438 	if (src_node_killers)
2439 		pfctl_kill_src_nodes(dev, ifaceopt, opts);
2440 
2441 	if (tblcmdopt != NULL) {
2442 		error = pfctl_command_tables(argc, argv, tableopt,
2443 		    tblcmdopt, rulesopt, anchorname, opts);
2444 		rulesopt = NULL;
2445 	}
2446 	if (optiopt != NULL) {
2447 		switch (*optiopt) {
2448 		case 'n':
2449 			optimize = 0;
2450 			break;
2451 		case 'b':
2452 			optimize |= PF_OPTIMIZE_BASIC;
2453 			break;
2454 		case 'o':
2455 		case 'p':
2456 			optimize |= PF_OPTIMIZE_PROFILE;
2457 			break;
2458 		}
2459 	}
2460 
2461 	if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
2462 	    !anchorname[0] && !(opts & PF_OPT_NOACTION))
2463 		if (pfctl_get_skip_ifaces())
2464 			error = 1;
2465 
2466 	if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
2467 	    !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
2468 		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
2469 			error = 1;
2470 
2471 	if (rulesopt != NULL) {
2472 		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2473 			errx(1, "anchor names beginning with '_' cannot "
2474 			    "be modified from the command line");
2475 		if (pfctl_rules(dev, rulesopt, opts, optimize,
2476 		    anchorname, NULL))
2477 			error = 1;
2478 		else if (!(opts & PF_OPT_NOACTION) &&
2479 		    (loadopt & PFCTL_FLAG_TABLE))
2480 			warn_namespace_collision(NULL);
2481 	}
2482 
2483 	if (opts & PF_OPT_ENABLE)
2484 		if (pfctl_enable(dev, opts))
2485 			error = 1;
2486 
2487 	if (debugopt != NULL) {
2488 		switch (*debugopt) {
2489 		case 'n':
2490 			pfctl_debug(dev, PF_DEBUG_NONE, opts);
2491 			break;
2492 		case 'u':
2493 			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
2494 			break;
2495 		case 'm':
2496 			pfctl_debug(dev, PF_DEBUG_MISC, opts);
2497 			break;
2498 		case 'l':
2499 			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
2500 			break;
2501 		}
2502 	}
2503 
2504 	exit(error);
2505 }
2506