xref: /dragonfly/usr.sbin/pfctl/pfctl.c (revision 5153f92b)
1 /*	$OpenBSD: pfctl.c,v 1.213 2004/03/20 09:31:42 david Exp $ */
2 /*	$DragonFly: src/usr.sbin/pfctl/pfctl.c,v 1.1 2004/09/21 21:25:28 joerg Exp $ */
3 
4 /*
5  * Copyright (c) 2001 Daniel Hartmeier
6  * Copyright (c) 2002,2003 Henning Brauer
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *    - Redistributions of source code must retain the above copyright
14  *      notice, this list of conditions and the following disclaimer.
15  *    - Redistributions in binary form must reproduce the above
16  *      copyright notice, this list of conditions and the following
17  *      disclaimer in the documentation and/or other materials provided
18  *      with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 #include <sys/param.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38 
39 #include <net/if.h>
40 #include <netinet/in.h>
41 #include <net/pf/pfvar.h>
42 #include <arpa/inet.h>
43 #ifndef __DragonFly__
44 #include <altq/altq.h>
45 #endif
46 
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <limits.h>
51 #include <netdb.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 #include "pfctl_parser.h"
58 #include "pfctl.h"
59 
60 void	 usage(void);
61 int	 pfctl_enable(int, int);
62 int	 pfctl_disable(int, int);
63 int	 pfctl_clear_stats(int, int);
64 int	 pfctl_clear_rules(int, int, char *, char *);
65 int	 pfctl_clear_nat(int, int, char *, char *);
66 int	 pfctl_clear_altq(int, int);
67 int	 pfctl_clear_src_nodes(int, int);
68 int	 pfctl_clear_states(int, const char *, int);
69 int	 pfctl_kill_states(int, const char *, int);
70 int	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
71 	    char *, char *);
72 void	 pfctl_print_rule_counters(struct pf_rule *, int);
73 int	 pfctl_show_rules(int, int, int, char *, char *);
74 int	 pfctl_show_nat(int, int, char *, char *);
75 int	 pfctl_show_src_nodes(int, int);
76 int	 pfctl_show_states(int, const char *, int);
77 int	 pfctl_show_status(int, int);
78 int	 pfctl_show_timeouts(int, int);
79 int	 pfctl_show_limits(int, int);
80 int	 pfctl_debug(int, u_int32_t, int);
81 int	 pfctl_clear_rule_counters(int, int);
82 int	 pfctl_test_altqsupport(int, int);
83 int	 pfctl_show_anchors(int, int, char *);
84 const char	*pfctl_lookup_option(char *, const char **);
85 
86 const char	*clearopt;
87 char		*rulesopt;
88 const char	*showopt;
89 const char	*debugopt;
90 char		*anchoropt;
91 const char	*pf_device = "/dev/pf";
92 char		*ifaceopt;
93 char		*tableopt;
94 const char	*tblcmdopt;
95 int		 state_killers;
96 char		*state_kill[2];
97 int		 loadopt;
98 int		 altqsupport;
99 
100 int		 dev_fd = -1;
101 int		 first_title = 1;
102 int		 labels = 0;
103 
104 const char	*infile;
105 
106 static const struct {
107 	const char	*name;
108 	int		index;
109 } pf_limits[] = {
110 	{ "states",	PF_LIMIT_STATES },
111 	{ "src-nodes",	PF_LIMIT_SRC_NODES },
112 	{ "frags",	PF_LIMIT_FRAGS },
113 	{ NULL,		0 }
114 };
115 
116 struct pf_hint {
117 	const char	*name;
118 	int		timeout;
119 };
120 static const struct pf_hint pf_hint_normal[] = {
121 	{ "tcp.first",		2 * 60 },
122 	{ "tcp.opening",	30 },
123 	{ "tcp.established",	24 * 60 * 60 },
124 	{ "tcp.closing",	15 * 60 },
125 	{ "tcp.finwait",	45 },
126 	{ "tcp.closed",		90 },
127 	{ NULL,			0 }
128 };
129 static const struct pf_hint pf_hint_satellite[] = {
130 	{ "tcp.first",		3 * 60 },
131 	{ "tcp.opening",	30 + 5 },
132 	{ "tcp.established",	24 * 60 * 60 },
133 	{ "tcp.closing",	15 * 60 + 5 },
134 	{ "tcp.finwait",	45 + 5 },
135 	{ "tcp.closed",		90 + 5 },
136 	{ NULL,			0 }
137 };
138 static const struct pf_hint pf_hint_conservative[] = {
139 	{ "tcp.first",		60 * 60 },
140 	{ "tcp.opening",	15 * 60 },
141 	{ "tcp.established",	5 * 24 * 60 * 60 },
142 	{ "tcp.closing",	60 * 60 },
143 	{ "tcp.finwait",	10 * 60 },
144 	{ "tcp.closed",		3 * 60 },
145 	{ NULL,			0 }
146 };
147 static const struct pf_hint pf_hint_aggressive[] = {
148 	{ "tcp.first",		30 },
149 	{ "tcp.opening",	5 },
150 	{ "tcp.established",	5 * 60 * 60 },
151 	{ "tcp.closing",	60 },
152 	{ "tcp.finwait",	30 },
153 	{ "tcp.closed",		30 },
154 	{ NULL,			0 }
155 };
156 
157 static const struct {
158 	const char *name;
159 	const struct pf_hint *hint;
160 } pf_hints[] = {
161 	{ "normal",		pf_hint_normal },
162 	{ "satellite",		pf_hint_satellite },
163 	{ "high-latency",	pf_hint_satellite },
164 	{ "conservative",	pf_hint_conservative },
165 	{ "aggressive",		pf_hint_aggressive },
166 	{ NULL,			NULL }
167 };
168 
169 static const char *clearopt_list[] = {
170 	"nat", "queue", "rules", "Sources",
171 	"state", "info", "Tables", "osfp", "all", NULL
172 };
173 
174 static const char *showopt_list[] = {
175 	"nat", "queue", "rules", "Anchors", "Sources", "state", "info",
176 	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
177 	"all", NULL
178 };
179 
180 static const char *tblcmdopt_list[] = {
181 	"kill", "flush", "add", "delete", "load", "replace", "show",
182 	"test", "zero", NULL
183 };
184 
185 static const char *debugopt_list[] = {
186 	"none", "urgent", "misc", "loud", NULL
187 };
188 
189 
190 void
191 usage(void)
192 {
193 	fprintf(stderr, "usage: %s [-AdeghNnOqRrvz] ", getprogname());
194 	fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n");
195 	fprintf(stderr, "             ");
196 	fprintf(stderr, "[-F modifier] [-f file] [-i interface] ");
197 	fprintf(stderr, "[-k host] [-p device]\n");
198 	fprintf(stderr, "             ");
199 	fprintf(stderr, "[-s modifier] [-T command [address ...]] ");
200 	fprintf(stderr, "[-t table] [-x level]\n");
201 	exit(1);
202 }
203 
204 int
205 pfctl_enable(int dev, int opts)
206 {
207 	if (ioctl(dev, DIOCSTART)) {
208 		if (errno == EEXIST)
209 			errx(1, "pf already enabled");
210 		else
211 			err(1, "DIOCSTART");
212 	}
213 	if ((opts & PF_OPT_QUIET) == 0)
214 		fprintf(stderr, "pf enabled\n");
215 
216 	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
217 		if (errno != EEXIST)
218 			err(1, "DIOCSTARTALTQ");
219 
220 	return (0);
221 }
222 
223 int
224 pfctl_disable(int dev, int opts)
225 {
226 	if (ioctl(dev, DIOCSTOP)) {
227 		if (errno == ENOENT)
228 			errx(1, "pf not enabled");
229 		else
230 			err(1, "DIOCSTOP");
231 	}
232 	if ((opts & PF_OPT_QUIET) == 0)
233 		fprintf(stderr, "pf disabled\n");
234 
235 	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
236 			if (errno != ENOENT)
237 				err(1, "DIOCSTOPALTQ");
238 
239 	return (0);
240 }
241 
242 int
243 pfctl_clear_stats(int dev, int opts)
244 {
245 	if (ioctl(dev, DIOCCLRSTATUS))
246 		err(1, "DIOCCLRSTATUS");
247 	if ((opts & PF_OPT_QUIET) == 0)
248 		fprintf(stderr, "pf: statistics cleared\n");
249 	return (0);
250 }
251 
252 int
253 pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
254 {
255 	struct pfr_buffer t;
256 
257 	if (*anchorname && !*rulesetname) {
258 		struct pfioc_ruleset pr;
259 		int mnr, nr, r;
260 
261 		memset(&pr, 0, sizeof(pr));
262 		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
263 		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
264 			if (errno == EINVAL)
265 				fprintf(stderr, "No rulesets in anchor '%s'.\n",
266 				    anchorname);
267 			else
268 				err(1, "DIOCGETRULESETS");
269 			return (-1);
270 		}
271 		mnr = pr.nr;
272 		for (nr = mnr - 1; nr >= 0; --nr) {
273 			pr.nr = nr;
274 			if (ioctl(dev, DIOCGETRULESET, &pr))
275 				err(1, "DIOCGETRULESET");
276 			r = pfctl_clear_rules(dev, opts | PF_OPT_QUIET,
277 			    anchorname, pr.name);
278 			if (r)
279 				return (r);
280 		}
281 		if ((opts & PF_OPT_QUIET) == 0)
282 			fprintf(stderr, "rules cleared\n");
283 		return (0);
284 	}
285 	memset(&t, 0, sizeof(t));
286 	t.pfrb_type = PFRB_TRANS;
287 	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname, rulesetname) ||
288 	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname, rulesetname) ||
289 	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
290 	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
291 		err(1, "pfctl_clear_rules");
292 	if ((opts & PF_OPT_QUIET) == 0)
293 		fprintf(stderr, "rules cleared\n");
294 	return (0);
295 }
296 
297 int
298 pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
299 {
300 	struct pfr_buffer t;
301 
302 	if (*anchorname && !*rulesetname) {
303 		struct pfioc_ruleset pr;
304 		int mnr, nr, r;
305 
306 		memset(&pr, 0, sizeof(pr));
307 		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
308 		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
309 			if (errno == EINVAL)
310 				fprintf(stderr, "No rulesets in anchor '%s'.\n",
311 				    anchorname);
312 			else
313 				err(1, "DIOCGETRULESETS");
314 			return (-1);
315 		}
316 		mnr = pr.nr;
317 		for (nr = mnr - 1; nr >= 0; --nr) {
318 			pr.nr = nr;
319 			if (ioctl(dev, DIOCGETRULESET, &pr))
320 				err(1, "DIOCGETRULESET");
321 			r = pfctl_clear_nat(dev, opts | PF_OPT_QUIET,
322 			    anchorname, pr.name);
323 			if (r)
324 				return (r);
325 		}
326 		if ((opts & PF_OPT_QUIET) == 0)
327 			fprintf(stderr, "nat cleared\n");
328 		return (0);
329 	}
330 	memset(&t, 0, sizeof(t));
331 	t.pfrb_type = PFRB_TRANS;
332 	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname, rulesetname) ||
333 	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname, rulesetname) ||
334 	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname, rulesetname) ||
335 	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
336 	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
337 		err(1, "pfctl_clear_nat");
338 	if ((opts & PF_OPT_QUIET) == 0)
339 		fprintf(stderr, "nat cleared\n");
340 	return (0);
341 }
342 
343 #ifndef __DragonFly__
344 int
345 pfctl_clear_altq(int dev, int opts)
346 {
347 	struct pfr_buffer t;
348 
349 	if (!altqsupport)
350 		return (-1);
351 	memset(&t, 0, sizeof(t));
352 	t.pfrb_type = PFRB_TRANS;
353 	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "", "") ||
354 	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
355 	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
356 		err(1, "pfctl_clear_altq");
357 	if ((opts & PF_OPT_QUIET) == 0)
358 		fprintf(stderr, "altq cleared\n");
359 	return (0);
360 }
361 #endif
362 
363 int
364 pfctl_clear_src_nodes(int dev, int opts)
365 {
366 	if (ioctl(dev, DIOCCLRSRCNODES))
367 		err(1, "DIOCCLRSRCNODES");
368 	if ((opts & PF_OPT_QUIET) == 0)
369 		fprintf(stderr, "source tracking entries cleared\n");
370 	return (0);
371 }
372 
373 int
374 pfctl_clear_states(int dev, const char *iface, int opts)
375 {
376 	struct pfioc_state_kill psk;
377 
378 	memset(&psk, 0, sizeof(psk));
379 	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
380 	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
381 		errx(1, "invalid interface: %s", iface);
382 
383 	if (ioctl(dev, DIOCCLRSTATES, &psk))
384 		err(1, "DIOCCLRSTATES");
385 	if ((opts & PF_OPT_QUIET) == 0)
386 		fprintf(stderr, "%d states cleared\n", psk.psk_af);
387 	return (0);
388 }
389 
390 int
391 pfctl_kill_states(int dev, const char *iface, int opts)
392 {
393 	struct pfioc_state_kill psk;
394 	struct addrinfo *res[2], *resp[2];
395 	struct sockaddr last_src, last_dst;
396 	int killed, sources, dests;
397 	int ret_ga;
398 
399 	killed = sources = dests = 0;
400 
401 	memset(&psk, 0, sizeof(psk));
402 	memset(&psk.psk_src.addr.v.a.mask, 0xff,
403 	    sizeof(psk.psk_src.addr.v.a.mask));
404 	memset(&last_src, 0xff, sizeof(last_src));
405 	memset(&last_dst, 0xff, sizeof(last_dst));
406 	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
407 	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
408 		errx(1, "invalid interface: %s", iface);
409 
410 	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
411 		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
412 		/* NOTREACHED */
413 	}
414 	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
415 		if (resp[0]->ai_addr == NULL)
416 			continue;
417 		/* We get lots of duplicates.  Catch the easy ones */
418 		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
419 			continue;
420 		last_src = *(struct sockaddr *)resp[0]->ai_addr;
421 
422 		psk.psk_af = resp[0]->ai_family;
423 		sources++;
424 
425 		if (psk.psk_af == AF_INET)
426 			psk.psk_src.addr.v.a.addr.v4 =
427 			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
428 		else if (psk.psk_af == AF_INET6)
429 			psk.psk_src.addr.v.a.addr.v6 =
430 			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
431 			    sin6_addr;
432 		else
433 			errx(1, "Unknown address family %d", psk.psk_af);
434 
435 		if (state_killers > 1) {
436 			dests = 0;
437 			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
438 			    sizeof(psk.psk_dst.addr.v.a.mask));
439 			memset(&last_dst, 0xff, sizeof(last_dst));
440 			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
441 			    &res[1]))) {
442 				errx(1, "getaddrinfo: %s",
443 				    gai_strerror(ret_ga));
444 				/* NOTREACHED */
445 			}
446 			for (resp[1] = res[1]; resp[1];
447 			    resp[1] = resp[1]->ai_next) {
448 				if (resp[1]->ai_addr == NULL)
449 					continue;
450 				if (psk.psk_af != resp[1]->ai_family)
451 					continue;
452 
453 				if (memcmp(&last_dst, resp[1]->ai_addr,
454 				    sizeof(last_dst)) == 0)
455 					continue;
456 				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
457 
458 				dests++;
459 
460 				if (psk.psk_af == AF_INET)
461 					psk.psk_dst.addr.v.a.addr.v4 =
462 					    ((struct sockaddr_in *)resp[1]->
463 					    ai_addr)->sin_addr;
464 				else if (psk.psk_af == AF_INET6)
465 					psk.psk_dst.addr.v.a.addr.v6 =
466 					    ((struct sockaddr_in6 *)resp[1]->
467 					    ai_addr)->sin6_addr;
468 				else
469 					errx(1, "Unknown address family %d",
470 					    psk.psk_af);
471 
472 				if (ioctl(dev, DIOCKILLSTATES, &psk))
473 					err(1, "DIOCKILLSTATES");
474 				killed += psk.psk_af;
475 				/* fixup psk.psk_af */
476 				psk.psk_af = resp[1]->ai_family;
477 			}
478 			freeaddrinfo(res[1]);
479 		} else {
480 			if (ioctl(dev, DIOCKILLSTATES, &psk))
481 				err(1, "DIOCKILLSTATES");
482 			killed += psk.psk_af;
483 			/* fixup psk.psk_af */
484 			psk.psk_af = res[0]->ai_family;
485 		}
486 	}
487 
488 	freeaddrinfo(res[0]);
489 
490 	if ((opts & PF_OPT_QUIET) == 0)
491 		fprintf(stderr, "killed %d states from %d sources and %d "
492 		    "destinations\n", killed, sources, dests);
493 	return (0);
494 }
495 
496 int
497 pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
498     u_int32_t ticket, int r_action, char *anchorname, char *rulesetname)
499 {
500 	struct pfioc_pooladdr pp;
501 	struct pf_pooladdr *pa;
502 	u_int32_t pnr, mpnr;
503 
504 	memset(&pp, 0, sizeof(pp));
505 	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
506 	memcpy(pp.ruleset, rulesetname, sizeof(pp.ruleset));
507 	pp.r_action = r_action;
508 	pp.r_num = nr;
509 	pp.ticket = ticket;
510 	if (ioctl(dev, DIOCGETADDRS, &pp)) {
511 		warn("DIOCGETADDRS");
512 		return (-1);
513 	}
514 	mpnr = pp.nr;
515 	TAILQ_INIT(&pool->list);
516 	for (pnr = 0; pnr < mpnr; ++pnr) {
517 		pp.nr = pnr;
518 		if (ioctl(dev, DIOCGETADDR, &pp)) {
519 			warn("DIOCGETADDR");
520 			return (-1);
521 		}
522 		pa = calloc(1, sizeof(struct pf_pooladdr));
523 		if (pa == NULL)
524 			err(1, "calloc");
525 		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
526 		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
527 	}
528 
529 	return (0);
530 }
531 
532 void
533 pfctl_clear_pool(struct pf_pool *pool)
534 {
535 	struct pf_pooladdr *pa;
536 
537 	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
538 		TAILQ_REMOVE(&pool->list, pa, entries);
539 		free(pa);
540 	}
541 }
542 
543 void
544 pfctl_print_rule_counters(struct pf_rule *rule, int opts)
545 {
546 	if (opts & PF_OPT_DEBUG) {
547 		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
548 		    "p", "sa", "sp", "da", "dp" };
549 		int i;
550 
551 		printf("  [ Skip steps: ");
552 		for (i = 0; i < PF_SKIP_COUNT; ++i) {
553 			if (rule->skip[i].nr == rule->nr + 1)
554 				continue;
555 			printf("%s=", t[i]);
556 			if (rule->skip[i].nr == (uint32_t)(-1))
557 				printf("end ");
558 			else
559 				printf("%u ", rule->skip[i].nr);
560 		}
561 		printf("]\n");
562 
563 		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
564 		    rule->qname, rule->qid, rule->pqname, rule->pqid);
565 	}
566 	if (opts & PF_OPT_VERBOSE)
567 		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
568 			    "Bytes: %-10llu  States: %-6u]\n",
569 			    (unsigned long long)rule->evaluations,
570 			    (unsigned long long)rule->packets,
571 			    (unsigned long long)rule->bytes, rule->states);
572 }
573 
574 void
575 pfctl_print_title(const char *title)
576 {
577 	if (!first_title)
578 		printf("\n");
579 	first_title = 0;
580 	printf("%s\n", title);
581 }
582 
583 int
584 pfctl_show_rules(int dev, int opts, int format, char *anchorname,
585     char *rulesetname)
586 {
587 	struct pfioc_rule pr;
588 	u_int32_t nr, mnr, header = 0;
589 	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
590 
591 	if (*anchorname && !*rulesetname) {
592 		struct pfioc_ruleset pr2;
593 		int r;
594 
595 		memset(&pr2, 0, sizeof(pr2));
596 		memcpy(pr2.anchor, anchorname, sizeof(pr2.anchor));
597 		if (ioctl(dev, DIOCGETRULESETS, &pr2)) {
598 			if (errno == EINVAL)
599 				fprintf(stderr, "No rulesets in anchor '%s'.\n",
600 				    anchorname);
601 			else
602 				err(1, "DIOCGETRULESETS");
603 			return (-1);
604 		}
605 		if (opts & PF_OPT_SHOWALL && pr2.nr)
606 			pfctl_print_title("FILTER RULES:");
607 		mnr = pr2.nr;
608 		for (nr = 0; nr < mnr; ++nr) {
609 			pr2.nr = nr;
610 			if (ioctl(dev, DIOCGETRULESET, &pr2))
611 				err(1, "DIOCGETRULESET");
612 			r = pfctl_show_rules(dev, opts, format, anchorname,
613 			    pr2.name);
614 			if (r)
615 				return (r);
616 		}
617 		return (0);
618 	}
619 
620 	memset(&pr, 0, sizeof(pr));
621 	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
622 	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
623 	if (opts & PF_OPT_SHOWALL) {
624 		pr.rule.action = PF_PASS;
625 		if (ioctl(dev, DIOCGETRULES, &pr)) {
626 			warn("DIOCGETRULES");
627 			return (-1);
628 		}
629 		header++;
630 	}
631 	pr.rule.action = PF_SCRUB;
632 	if (ioctl(dev, DIOCGETRULES, &pr)) {
633 		warn("DIOCGETRULES");
634 		return (-1);
635 	}
636 	if (opts & PF_OPT_SHOWALL) {
637 		if (format == 0 && (pr.nr > 0 || header))
638 			pfctl_print_title("FILTER RULES:");
639 		else if (format == 1 && labels)
640 			pfctl_print_title("LABEL COUNTERS:");
641 	}
642 	mnr = pr.nr;
643 	for (nr = 0; nr < mnr; ++nr) {
644 		pr.nr = nr;
645 		if (ioctl(dev, DIOCGETRULE, &pr)) {
646 			warn("DIOCGETRULE");
647 			return (-1);
648 		}
649 
650 		if (pfctl_get_pool(dev, &pr.rule.rpool,
651 		    nr, pr.ticket, PF_SCRUB, anchorname, rulesetname) != 0)
652 			return (-1);
653 
654 		switch (format) {
655 		case 1:
656 			if (pr.rule.label[0]) {
657 				printf("%s ", pr.rule.label);
658 				printf("%llu %llu %llu\n",
659 				    (unsigned long long)pr.rule.evaluations,
660 				    (unsigned long long)pr.rule.packets,
661 				    (unsigned long long)pr.rule.bytes);
662 			}
663 			break;
664 		default:
665 			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
666 				labels = 1;
667 			print_rule(&pr.rule, rule_numbers);
668 			pfctl_print_rule_counters(&pr.rule, opts);
669 		}
670 		pfctl_clear_pool(&pr.rule.rpool);
671 	}
672 	pr.rule.action = PF_PASS;
673 	if (ioctl(dev, DIOCGETRULES, &pr)) {
674 		warn("DIOCGETRULES");
675 		return (-1);
676 	}
677 	mnr = pr.nr;
678 	for (nr = 0; nr < mnr; ++nr) {
679 		pr.nr = nr;
680 		if (ioctl(dev, DIOCGETRULE, &pr)) {
681 			warn("DIOCGETRULE");
682 			return (-1);
683 		}
684 
685 		if (pfctl_get_pool(dev, &pr.rule.rpool,
686 		    nr, pr.ticket, PF_PASS, anchorname, rulesetname) != 0)
687 			return (-1);
688 
689 		switch (format) {
690 		case 1:
691 			if (pr.rule.label[0]) {
692 				printf("%s ", pr.rule.label);
693 				printf("%llu %llu %llu\n",
694 				    (unsigned long long)pr.rule.evaluations,
695 				    (unsigned long long)pr.rule.packets,
696 				    (unsigned long long)pr.rule.bytes);
697 			}
698 			break;
699 		default:
700 			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
701 				labels = 1;
702 			print_rule(&pr.rule, rule_numbers);
703 			pfctl_print_rule_counters(&pr.rule, opts);
704 		}
705 		pfctl_clear_pool(&pr.rule.rpool);
706 	}
707 	return (0);
708 }
709 
710 int
711 pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname)
712 {
713 	struct pfioc_rule pr;
714 	u_int32_t mnr, nr;
715 	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
716 	int i, dotitle = opts & PF_OPT_SHOWALL;
717 
718 	if (*anchorname && !*rulesetname) {
719 		struct pfioc_ruleset pr2;
720 		int r;
721 
722 		memset(&pr2, 0, sizeof(pr2));
723 		memcpy(pr2.anchor, anchorname, sizeof(pr2.anchor));
724 		if (ioctl(dev, DIOCGETRULESETS, &pr2)) {
725 			if (errno == EINVAL)
726 				fprintf(stderr, "No rulesets in anchor '%s'.\n",
727 				    anchorname);
728 			else
729 				err(1, "DIOCGETRULESETS");
730 			return (-1);
731 		}
732 		mnr = pr2.nr;
733 		for (nr = 0; nr < mnr; ++nr) {
734 			pr2.nr = nr;
735 			if (ioctl(dev, DIOCGETRULESET, &pr2))
736 				err(1, "DIOCGETRULESET");
737 			r = pfctl_show_nat(dev, opts, anchorname, pr2.name);
738 			if (r)
739 				return (r);
740 		}
741 		return (0);
742 	}
743 
744 	memset(&pr, 0, sizeof(pr));
745 	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
746 	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
747 	for (i = 0; i < 3; i++) {
748 		pr.rule.action = nattype[i];
749 		if (ioctl(dev, DIOCGETRULES, &pr)) {
750 			warn("DIOCGETRULES");
751 			return (-1);
752 		}
753 		mnr = pr.nr;
754 		for (nr = 0; nr < mnr; ++nr) {
755 			pr.nr = nr;
756 			if (ioctl(dev, DIOCGETRULE, &pr)) {
757 				warn("DIOCGETRULE");
758 				return (-1);
759 			}
760 			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
761 			    pr.ticket, nattype[i], anchorname,
762 			    rulesetname) != 0)
763 				return (-1);
764 			if (dotitle) {
765 				pfctl_print_title("TRANSLATION RULES:");
766 				dotitle = 0;
767 			}
768 			print_rule(&pr.rule, opts & PF_OPT_VERBOSE2);
769 			pfctl_print_rule_counters(&pr.rule, opts);
770 			pfctl_clear_pool(&pr.rule.rpool);
771 		}
772 	}
773 	return (0);
774 }
775 
776 int
777 pfctl_show_src_nodes(int dev, int opts)
778 {
779 	struct pfioc_src_nodes psn;
780 	struct pf_src_node *p;
781 	char *inbuf = NULL, *newinbuf = NULL;
782 	unsigned len = 0;
783 	int i;
784 
785 	memset(&psn, 0, sizeof(psn));
786 	for (;;) {
787 		psn.psn_len = len;
788 		if (len) {
789 			newinbuf = realloc(inbuf, len);
790 			if (newinbuf == NULL)
791 				err(1, "realloc");
792 			psn.psn_buf = inbuf = newinbuf;
793 		}
794 		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
795 			warn("DIOCGETSRCNODES");
796 			return (-1);
797 		}
798 		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
799 			break;
800 		if (len == 0 && psn.psn_len == 0)
801 			return (0);
802 		if (len == 0 && psn.psn_len != 0)
803 			len = psn.psn_len;
804 		if (psn.psn_len == 0)
805 			return (0);	/* no src_nodes */
806 		len *= 2;
807 	}
808 	p = psn.psn_src_nodes;
809 	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
810 		pfctl_print_title("SOURCE TRACKING NODES:");
811 	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
812 		print_src_node(p, opts);
813 		p++;
814 	}
815 	return (0);
816 }
817 
818 int
819 pfctl_show_states(int dev, const char *iface, int opts)
820 {
821 	struct pfioc_states ps;
822 	struct pf_state *p;
823 	char *inbuf = NULL, *newinbuf = NULL;
824 	unsigned len = 0;
825 	int i, dotitle = (opts & PF_OPT_SHOWALL);
826 
827 	memset(&ps, 0, sizeof(ps));
828 	for (;;) {
829 		ps.ps_len = len;
830 		if (len) {
831 			newinbuf = realloc(inbuf, len);
832 			if (newinbuf == NULL)
833 				err(1, "realloc");
834 			ps.ps_buf = inbuf = newinbuf;
835 		}
836 		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
837 			warn("DIOCGETSTATES");
838 			return (-1);
839 		}
840 		if (ps.ps_len + sizeof(struct pfioc_states) < len)
841 			break;
842 		if (len == 0 && ps.ps_len == 0)
843 			return (0);
844 		if (len == 0 && ps.ps_len != 0)
845 			len = ps.ps_len;
846 		if (ps.ps_len == 0)
847 			return (0);	/* no states */
848 		len *= 2;
849 	}
850 	p = ps.ps_states;
851 	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
852 		if (iface != NULL && strcmp(p->u.ifname, iface))
853 			continue;
854 		if (dotitle) {
855 			pfctl_print_title("STATES:");
856 			dotitle = 0;
857 		}
858 		print_state(p, opts);
859 	}
860 	return (0);
861 }
862 
863 int
864 pfctl_show_status(int dev, int opts)
865 {
866 	struct pf_status status;
867 
868 	if (ioctl(dev, DIOCGETSTATUS, &status)) {
869 		warn("DIOCGETSTATUS");
870 		return (-1);
871 	}
872 	if (opts & PF_OPT_SHOWALL)
873 		pfctl_print_title("INFO:");
874 	print_status(&status, opts);
875 	return (0);
876 }
877 
878 int
879 pfctl_show_timeouts(int dev, int opts)
880 {
881 	struct pfioc_tm pt;
882 	int i;
883 
884 	if (opts & PF_OPT_SHOWALL)
885 		pfctl_print_title("TIMEOUTS:");
886 	memset(&pt, 0, sizeof(pt));
887 	for (i = 0; pf_timeouts[i].name; i++) {
888 		pt.timeout = pf_timeouts[i].timeout;
889 		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
890 			err(1, "DIOCGETTIMEOUT");
891 		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
892 		if (i >= PFTM_ADAPTIVE_START && i <= PFTM_ADAPTIVE_END)
893 			printf(" states");
894 		else
895 			printf("s");
896 		printf("\n");
897 	}
898 	return (0);
899 
900 }
901 
902 int
903 pfctl_show_limits(int dev, int opts)
904 {
905 	struct pfioc_limit pl;
906 	int i;
907 
908 	if (opts & PF_OPT_SHOWALL)
909 		pfctl_print_title("LIMITS:");
910 	memset(&pl, 0, sizeof(pl));
911 	for (i = 0; pf_limits[i].name; i++) {
912 		pl.index = pf_limits[i].index;
913 		if (ioctl(dev, DIOCGETLIMIT, &pl))
914 			err(1, "DIOCGETLIMIT");
915 		printf("%-10s ", pf_limits[i].name);
916 		if (pl.limit == UINT_MAX)
917 			printf("unlimited\n");
918 		else
919 			printf("hard limit %6u\n", pl.limit);
920 	}
921 	return (0);
922 }
923 
924 /* callbacks for rule/nat/rdr/addr */
925 int
926 pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
927 {
928 	struct pf_pooladdr *pa;
929 
930 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
931 		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
932 			err(1, "DIOCBEGINADDRS");
933 	}
934 
935 	pf->paddr.af = af;
936 	TAILQ_FOREACH(pa, &p->list, entries) {
937 		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
938 		if ((pf->opts & PF_OPT_NOACTION) == 0) {
939 			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
940 				err(1, "DIOCADDADDR");
941 		}
942 	}
943 	return (0);
944 }
945 
946 int
947 pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
948 {
949 	u_int8_t		rs_num;
950 	struct pfioc_rule	pr;
951 
952 	switch (r->action) {
953 	case PF_SCRUB:
954 		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
955 			return (0);
956 		rs_num = PF_RULESET_SCRUB;
957 		break;
958 	case PF_DROP:
959 	case PF_PASS:
960 		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
961 			return (0);
962 		rs_num = PF_RULESET_FILTER;
963 		break;
964 	case PF_NAT:
965 	case PF_NONAT:
966 		if ((loadopt & PFCTL_FLAG_NAT) == 0)
967 			return (0);
968 		rs_num = PF_RULESET_NAT;
969 		break;
970 	case PF_RDR:
971 	case PF_NORDR:
972 		if ((loadopt & PFCTL_FLAG_NAT) == 0)
973 			return (0);
974 		rs_num = PF_RULESET_RDR;
975 		break;
976 	case PF_BINAT:
977 	case PF_NOBINAT:
978 		if ((loadopt & PFCTL_FLAG_NAT) == 0)
979 			return (0);
980 		rs_num = PF_RULESET_BINAT;
981 		break;
982 	default:
983 		errx(1, "Invalid rule type");
984 		break;
985 	}
986 
987 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
988 		bzero(&pr, sizeof(pr));
989 		if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >=
990 		    sizeof(pr.anchor) ||
991 		    strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset)) >=
992 		    sizeof(pr.ruleset))
993 			errx(1, "pfctl_add_rule: strlcpy");
994 		if (pfctl_add_pool(pf, &r->rpool, r->af))
995 			return (1);
996 		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor,
997 		    pf->ruleset);
998 		pr.pool_ticket = pf->paddr.ticket;
999 		memcpy(&pr.rule, r, sizeof(pr.rule));
1000 		if (ioctl(pf->dev, DIOCADDRULE, &pr))
1001 			err(1, "DIOCADDRULE");
1002 	}
1003 	if (pf->opts & PF_OPT_VERBOSE)
1004 		print_rule(r, pf->opts & PF_OPT_VERBOSE2);
1005 	pfctl_clear_pool(&r->rpool);
1006 	return (0);
1007 }
1008 
1009 #ifndef __DragonFly__
1010 int
1011 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1012 {
1013 	if (altqsupport &&
1014 	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1015 		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1016 		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1017 			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1018 				if (errno == ENXIO)
1019 					errx(1, "qtype not configured");
1020 				else if (errno == ENODEV)
1021 					errx(1, "%s: driver does not support "
1022 					    "altq", a->ifname);
1023 				else
1024 					err(1, "DIOCADDALTQ");
1025 			}
1026 		}
1027 		pfaltq_store(&pf->paltq->altq);
1028 	}
1029 	return (0);
1030 }
1031 #endif
1032 
1033 int
1034 pfctl_rules(int dev, char *filename, int opts, char *anchorname,
1035     char *rulesetname, struct pfr_buffer *trans)
1036 {
1037 #define ERR(x) do { warn(x); goto _error; } while(0)
1038 #define ERRX(x) do { warnx(x); goto _error; } while(0)
1039 
1040 	FILE			*fin;
1041 	struct pfr_buffer	*t, buf;
1042 	struct pfioc_altq	 pa;
1043 	struct pfctl		 pf;
1044 	struct pfr_table	 trs;
1045 	int			 osize;
1046 
1047 	if (trans == NULL) {
1048 	    bzero(&buf, sizeof(buf));
1049 	    buf.pfrb_type = PFRB_TRANS;
1050 	    t = &buf;
1051 	    osize = 0;
1052 	} else {
1053 	    t = trans;
1054 	    osize = t->pfrb_size;
1055 	}
1056 
1057 	memset(&pa, 0, sizeof(pa));
1058 	memset(&pf, 0, sizeof(pf));
1059 	memset(&trs, 0, sizeof(trs));
1060 	if (strlcpy(trs.pfrt_anchor, anchorname,
1061 	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) ||
1062 	    strlcpy(trs.pfrt_ruleset, rulesetname,
1063 	    sizeof(trs.pfrt_ruleset)) >= sizeof(trs.pfrt_ruleset))
1064 		ERRX("pfctl_rules: strlcpy");
1065 	if (strcmp(filename, "-") == 0) {
1066 		fin = stdin;
1067 		infile = "stdin";
1068 	} else {
1069 		if ((fin = fopen(filename, "r")) == NULL) {
1070 			warn("%s", filename);
1071 			return (1);
1072 		}
1073 		infile = filename;
1074 	}
1075 	pf.dev = dev;
1076 	pf.opts = opts;
1077 	pf.loadopt = loadopt;
1078 	if (anchorname[0])
1079 		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1080 	pf.paltq = &pa;
1081 	pf.trans = t;
1082 	pf.rule_nr = 0;
1083 	pf.anchor = anchorname;
1084 	pf.ruleset = rulesetname;
1085 
1086 	if ((opts & PF_OPT_NOACTION) == 0) {
1087 		if ((pf.loadopt & PFCTL_FLAG_NAT) != 0) {
1088 			if (pfctl_add_trans(t, PF_RULESET_NAT, anchorname,
1089 			    rulesetname) ||
1090 			    pfctl_add_trans(t, PF_RULESET_BINAT, anchorname,
1091 			    rulesetname) ||
1092 			    pfctl_add_trans(t, PF_RULESET_RDR, anchorname,
1093 			    rulesetname))
1094 				ERR("pfctl_rules");
1095 		}
1096 		if (((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1097 			if (pfctl_add_trans(t, PF_RULESET_ALTQ, anchorname,
1098 			    rulesetname))
1099 				ERR("pfctl_rules");
1100 		}
1101 		if ((pf.loadopt & PFCTL_FLAG_FILTER) != 0) {
1102 			if (pfctl_add_trans(t, PF_RULESET_SCRUB, anchorname,
1103 			    rulesetname) ||
1104 			    pfctl_add_trans(t, PF_RULESET_FILTER, anchorname,
1105 			    rulesetname))
1106 				ERR("pfctl_rules");
1107 		}
1108 		if (pf.loadopt & PFCTL_FLAG_TABLE) {
1109 			if (pfctl_add_trans(t, PF_RULESET_TABLE, anchorname,
1110 			    rulesetname))
1111 				ERR("pfctl_rules");
1112 		}
1113 		if (pfctl_trans(dev, t, DIOCXBEGIN, osize))
1114 			ERR("DIOCXBEGIN");
1115 		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1116 			pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ,
1117 			    anchorname, rulesetname);
1118 		if (pf.loadopt & PFCTL_FLAG_TABLE)
1119 			pf.tticket = pfctl_get_ticket(t, PF_RULESET_TABLE,
1120 			    anchorname, rulesetname);
1121 	}
1122 	if (parse_rules(fin, &pf) < 0) {
1123 		if ((opts & PF_OPT_NOACTION) == 0)
1124 			ERRX("Syntax error in config file: "
1125 			    "pf rules not loaded");
1126 		else
1127 			goto _error;
1128 	}
1129 	#ifndef __DragonFly__
1130 	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1131 		if (check_commit_altq(dev, opts) != 0)
1132 			ERRX("errors in altq config");
1133 	#endif
1134 	if (fin != stdin)
1135 		fclose(fin);
1136 
1137 	/* process "load anchor" directives */
1138 	if (!anchorname[0] && !rulesetname[0])
1139 		if (pfctl_load_anchors(dev, opts, t) == -1)
1140 			ERRX("load anchors");
1141 
1142 	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0)
1143 		if (pfctl_trans(dev, t, DIOCXCOMMIT, 0))
1144 			ERR("DIOCXCOMMIT");
1145 	return (0);
1146 
1147 _error:
1148 	if (trans == NULL) {	/* main ruleset */
1149 		if ((opts & PF_OPT_NOACTION) == 0)
1150 			if (pfctl_trans(dev, t, DIOCXROLLBACK, 0))
1151 				err(1, "DIOCXROLLBACK");
1152 		exit(1);
1153 	} else			/* sub ruleset */
1154 		return (-1);
1155 
1156 #undef ERR
1157 #undef ERRX
1158 }
1159 
1160 int
1161 pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1162 {
1163 	struct pfioc_limit pl;
1164 	int i;
1165 
1166 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1167 		return (0);
1168 
1169 	memset(&pl, 0, sizeof(pl));
1170 	for (i = 0; pf_limits[i].name; i++) {
1171 		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1172 			pl.index = pf_limits[i].index;
1173 			pl.limit = limit;
1174 			if ((pf->opts & PF_OPT_NOACTION) == 0) {
1175 				if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1176 					if (errno == EBUSY) {
1177 						warnx("Current pool "
1178 						    "size exceeds requested "
1179 						    "hard limit");
1180 						return (1);
1181 					} else
1182 						err(1, "DIOCSETLIMIT");
1183 				}
1184 			}
1185 			break;
1186 		}
1187 	}
1188 	if (pf_limits[i].name == NULL) {
1189 		warnx("Bad pool name.");
1190 		return (1);
1191 	}
1192 
1193 	if (pf->opts & PF_OPT_VERBOSE)
1194 		printf("set limit %s %d\n", opt, limit);
1195 
1196 	return (0);
1197 }
1198 
1199 int
1200 pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1201 {
1202 	struct pfioc_tm pt;
1203 	int i;
1204 
1205 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1206 		return (0);
1207 
1208 	memset(&pt, 0, sizeof(pt));
1209 	for (i = 0; pf_timeouts[i].name; i++) {
1210 		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1211 			pt.timeout = pf_timeouts[i].timeout;
1212 			break;
1213 		}
1214 	}
1215 
1216 	if (pf_timeouts[i].name == NULL) {
1217 		warnx("Bad timeout name.");
1218 		return (1);
1219 	}
1220 
1221 	pt.seconds = seconds;
1222 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1223 		if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt))
1224 			err(1, "DIOCSETTIMEOUT");
1225 	}
1226 
1227 	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1228 		printf("set timeout %s %d\n", opt, seconds);
1229 
1230 	return (0);
1231 }
1232 
1233 int
1234 pfctl_set_optimization(struct pfctl *pf, const char *opt)
1235 {
1236 	const struct pf_hint *hint;
1237 	int i, r;
1238 
1239 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1240 		return (0);
1241 
1242 	for (i = 0; pf_hints[i].name; i++)
1243 		if (strcasecmp(opt, pf_hints[i].name) == 0)
1244 			break;
1245 
1246 	hint = pf_hints[i].hint;
1247 	if (hint == NULL) {
1248 		warnx("Bad hint name.");
1249 		return (1);
1250 	}
1251 
1252 	for (i = 0; hint[i].name; i++)
1253 		if ((r = pfctl_set_timeout(pf, hint[i].name,
1254 		    hint[i].timeout, 1)))
1255 			return (r);
1256 
1257 	if (pf->opts & PF_OPT_VERBOSE)
1258 		printf("set optimization %s\n", opt);
1259 
1260 	return (0);
1261 }
1262 
1263 int
1264 pfctl_set_logif(struct pfctl *pf, char *ifname)
1265 {
1266 	struct pfioc_if pi;
1267 
1268 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1269 		return (0);
1270 
1271 	memset(&pi, 0, sizeof(pi));
1272 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1273 		if (!strcmp(ifname, "none"))
1274 			bzero(pi.ifname, sizeof(pi.ifname));
1275 		else {
1276 			if (strlcpy(pi.ifname, ifname,
1277 			    sizeof(pi.ifname)) >= sizeof(pi.ifname))
1278 				errx(1, "pfctl_set_logif: strlcpy");
1279 		}
1280 		if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi))
1281 			err(1, "DIOCSETSTATUSIF");
1282 	}
1283 
1284 	if (pf->opts & PF_OPT_VERBOSE)
1285 		printf("set loginterface %s\n", ifname);
1286 
1287 	return (0);
1288 }
1289 
1290 int
1291 pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1292 {
1293 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1294 		return (0);
1295 
1296 	htonl(hostid);
1297 
1298 	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1299 		if (ioctl(dev_fd, DIOCSETHOSTID, &hostid))
1300 			err(1, "DIOCSETHOSTID");
1301 	}
1302 
1303 	if (pf->opts & PF_OPT_VERBOSE)
1304 		printf("set hostid 0x%08x\n", ntohl(hostid));
1305 
1306 	return (0);
1307 }
1308 
1309 int
1310 pfctl_set_debug(struct pfctl *pf, char *d)
1311 {
1312 	u_int32_t	level;
1313 
1314 	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1315 		return (0);
1316 
1317 	if (!strcmp(d, "none"))
1318 		level = PF_DEBUG_NONE;
1319 	else if (!strcmp(d, "urgent"))
1320 		level = PF_DEBUG_URGENT;
1321 	else if (!strcmp(d, "misc"))
1322 		level = PF_DEBUG_MISC;
1323 	else if (!strcmp(d, "loud"))
1324 		level = PF_DEBUG_NOISY;
1325 	else {
1326 		warnx("unknown debug level \"%s\"", d);
1327 		return (-1);
1328 	}
1329 
1330 	if ((pf->opts & PF_OPT_NOACTION) == 0)
1331 		if (ioctl(dev_fd, DIOCSETDEBUG, &level))
1332 			err(1, "DIOCSETDEBUG");
1333 
1334 	if (pf->opts & PF_OPT_VERBOSE)
1335 		printf("set debug %s\n", d);
1336 
1337 	return (0);
1338 }
1339 
1340 int
1341 pfctl_debug(int dev, u_int32_t level, int opts)
1342 {
1343 	if (ioctl(dev, DIOCSETDEBUG, &level))
1344 		err(1, "DIOCSETDEBUG");
1345 	if ((opts & PF_OPT_QUIET) == 0) {
1346 		fprintf(stderr, "debug level set to '");
1347 		switch (level) {
1348 		case PF_DEBUG_NONE:
1349 			fprintf(stderr, "none");
1350 			break;
1351 		case PF_DEBUG_URGENT:
1352 			fprintf(stderr, "urgent");
1353 			break;
1354 		case PF_DEBUG_MISC:
1355 			fprintf(stderr, "misc");
1356 			break;
1357 		case PF_DEBUG_NOISY:
1358 			fprintf(stderr, "loud");
1359 			break;
1360 		default:
1361 			fprintf(stderr, "<invalid>");
1362 			break;
1363 		}
1364 		fprintf(stderr, "'\n");
1365 	}
1366 	return (0);
1367 }
1368 
1369 int
1370 pfctl_clear_rule_counters(int dev, int opts)
1371 {
1372 	if (ioctl(dev, DIOCCLRRULECTRS))
1373 		err(1, "DIOCCLRRULECTRS");
1374 	if ((opts & PF_OPT_QUIET) == 0)
1375 		fprintf(stderr, "pf: rule counters cleared\n");
1376 	return (0);
1377 }
1378 
1379 int
1380 pfctl_test_altqsupport(int dev, int opts)
1381 {
1382 	struct pfioc_altq pa;
1383 
1384 	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1385 		if (errno == ENODEV) {
1386 			if (!(opts & PF_OPT_QUIET))
1387 				fprintf(stderr, "No ALTQ support in kernel\n"
1388 				    "ALTQ related functions disabled\n");
1389 			return (0);
1390 		} else
1391 			err(1, "DIOCGETALTQS");
1392 	}
1393 	return (1);
1394 }
1395 
1396 int
1397 pfctl_show_anchors(int dev, int opts, char *anchorname)
1398 {
1399 	u_int32_t nr, mnr;
1400 
1401 	if (!*anchorname) {
1402 		struct pfioc_anchor pa;
1403 
1404 		memset(&pa, 0, sizeof(pa));
1405 		if (ioctl(dev, DIOCGETANCHORS, &pa)) {
1406 			warn("DIOCGETANCHORS");
1407 			return (-1);
1408 		}
1409 		mnr = pa.nr;
1410 		for (nr = 0; nr < mnr; ++nr) {
1411 			pa.nr = nr;
1412 			if (ioctl(dev, DIOCGETANCHOR, &pa)) {
1413 				warn("DIOCGETANCHOR");
1414 				return (-1);
1415 			}
1416 			if (!(opts & PF_OPT_VERBOSE) &&
1417 			    !strcmp(pa.name, PF_RESERVED_ANCHOR))
1418 				continue;
1419 			printf("  %s\n", pa.name);
1420 		}
1421 	} else {
1422 		struct pfioc_ruleset pr;
1423 
1424 		memset(&pr, 0, sizeof(pr));
1425 		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
1426 		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1427 			if (errno == EINVAL)
1428 				fprintf(stderr, "No rulesets in anchor '%s'.\n",
1429 				    anchorname);
1430 			else
1431 				err(1, "DIOCGETRULESETS");
1432 			return (-1);
1433 		}
1434 		mnr = pr.nr;
1435 		for (nr = 0; nr < mnr; ++nr) {
1436 			pr.nr = nr;
1437 			if (ioctl(dev, DIOCGETRULESET, &pr))
1438 				err(1, "DIOCGETRULESET");
1439 			printf("  %s:%s\n", pr.anchor, pr.name);
1440 		}
1441 	}
1442 	return (0);
1443 }
1444 
1445 const char *
1446 pfctl_lookup_option(char *cmd, const char **list)
1447 {
1448 	if (cmd != NULL && *cmd)
1449 		for (; *list; list++)
1450 			if (!strncmp(cmd, *list, strlen(cmd)))
1451 				return (*list);
1452 	return (NULL);
1453 }
1454 
1455 int
1456 main(int argc, char *argv[])
1457 {
1458 	int	error = 0;
1459 	int	ch;
1460 	int	mode = O_RDONLY;
1461 	int	opts = 0;
1462 	char	anchorname[PF_ANCHOR_NAME_SIZE];
1463 	char	rulesetname[PF_RULESET_NAME_SIZE];
1464 
1465 	if (argc < 2)
1466 		usage();
1467 
1468 	while ((ch = getopt(argc, argv,
1469 	    "a:AdD:eqf:F:ghi:k:nNOp:rRs:t:T:vx:z")) != -1) {
1470 		switch (ch) {
1471 		case 'a':
1472 			anchoropt = optarg;
1473 			break;
1474 		case 'd':
1475 			opts |= PF_OPT_DISABLE;
1476 			mode = O_RDWR;
1477 			break;
1478 		case 'D':
1479 			if (pfctl_cmdline_symset(optarg) < 0)
1480 				warnx("could not parse macro definition %s",
1481 				    optarg);
1482 			break;
1483 		case 'e':
1484 			opts |= PF_OPT_ENABLE;
1485 			mode = O_RDWR;
1486 			break;
1487 		case 'q':
1488 			opts |= PF_OPT_QUIET;
1489 			break;
1490 		case 'F':
1491 			clearopt = pfctl_lookup_option(optarg, clearopt_list);
1492 			if (clearopt == NULL) {
1493 				warnx("Unknown flush modifier '%s'", optarg);
1494 				usage();
1495 			}
1496 			mode = O_RDWR;
1497 			break;
1498 		case 'i':
1499 			ifaceopt = optarg;
1500 			break;
1501 		case 'k':
1502 			if (state_killers >= 2) {
1503 				warnx("can only specify -k twice");
1504 				usage();
1505 				/* NOTREACHED */
1506 			}
1507 			state_kill[state_killers++] = optarg;
1508 			mode = O_RDWR;
1509 			break;
1510 		case 'n':
1511 			opts |= PF_OPT_NOACTION;
1512 			break;
1513 		case 'N':
1514 			loadopt |= PFCTL_FLAG_NAT;
1515 			break;
1516 		case 'r':
1517 			opts |= PF_OPT_USEDNS;
1518 			break;
1519 		case 'f':
1520 			rulesopt = optarg;
1521 			mode = O_RDWR;
1522 			break;
1523 		case 'g':
1524 			opts |= PF_OPT_DEBUG;
1525 			break;
1526 		case 'A':
1527 			loadopt |= PFCTL_FLAG_ALTQ;
1528 			break;
1529 		case 'R':
1530 			loadopt |= PFCTL_FLAG_FILTER;
1531 			break;
1532 		case 'O':
1533 			loadopt |= PFCTL_FLAG_OPTION;
1534 			break;
1535 		case 'p':
1536 			pf_device = optarg;
1537 			break;
1538 		case 's':
1539 			showopt = pfctl_lookup_option(optarg, showopt_list);
1540 			if (showopt == NULL) {
1541 				warnx("Unknown show modifier '%s'", optarg);
1542 				usage();
1543 			}
1544 			break;
1545 		case 't':
1546 			tableopt = optarg;
1547 			break;
1548 		case 'T':
1549 			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
1550 			if (tblcmdopt == NULL) {
1551 				warnx("Unknown table command '%s'", optarg);
1552 				usage();
1553 			}
1554 			break;
1555 		case 'v':
1556 			if (opts & PF_OPT_VERBOSE)
1557 				opts |= PF_OPT_VERBOSE2;
1558 			opts |= PF_OPT_VERBOSE;
1559 			break;
1560 		case 'x':
1561 			debugopt = pfctl_lookup_option(optarg, debugopt_list);
1562 			if (debugopt == NULL) {
1563 				warnx("Unknown debug level '%s'", optarg);
1564 				usage();
1565 			}
1566 			mode = O_RDWR;
1567 			break;
1568 		case 'z':
1569 			opts |= PF_OPT_CLRRULECTRS;
1570 			mode = O_RDWR;
1571 			break;
1572 		case 'h':
1573 			/* FALLTHROUGH */
1574 		default:
1575 			usage();
1576 			/* NOTREACHED */
1577 		}
1578 	}
1579 
1580 	if (tblcmdopt != NULL) {
1581 		argc -= optind;
1582 		argv += optind;
1583 		ch = *tblcmdopt;
1584 		if (ch == 'l') {
1585 			loadopt |= PFCTL_FLAG_TABLE;
1586 			tblcmdopt = NULL;
1587 		} else
1588 			mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY;
1589 	} else if (argc != optind) {
1590 		warnx("unknown command line argument: %s ...", argv[optind]);
1591 		usage();
1592 		/* NOTREACHED */
1593 	}
1594 	if (loadopt == 0)
1595 		loadopt = ~0;
1596 
1597 	memset(anchorname, 0, sizeof(anchorname));
1598 	memset(rulesetname, 0, sizeof(rulesetname));
1599 	if (anchoropt != NULL) {
1600 		char *t;
1601 
1602 		if ((t = strchr(anchoropt, ':')) == NULL) {
1603 			if (strlcpy(anchorname, anchoropt,
1604 			    sizeof(anchorname)) >= sizeof(anchorname))
1605 				errx(1, "anchor name '%s' too long",
1606 				    anchoropt);
1607 		} else {
1608 			char *p;
1609 
1610 			if ((p = strdup(anchoropt)) == NULL)
1611 				err(1, "anchoropt: strdup");
1612 			t = strsep(&p, ":");
1613 			if (*t == '\0' || *p == '\0')
1614 				errx(1, "anchor '%s' invalid", anchoropt);
1615 			if (strlcpy(anchorname, t, sizeof(anchorname)) >=
1616 			    sizeof(anchorname))
1617 				errx(1, "anchor name '%s' too long", t);
1618 			if (strlcpy(rulesetname, p, sizeof(rulesetname)) >=
1619 			    sizeof(rulesetname))
1620 				errx(1, "ruleset name '%s' too long", p);
1621 			free(t); /* not p */
1622 		}
1623 		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
1624 	}
1625 
1626 	if ((opts & PF_OPT_NOACTION) == 0) {
1627 		dev_fd = open(pf_device, mode);
1628 		if (dev_fd == -1)
1629 			err(1, "%s", pf_device);
1630 		altqsupport = pfctl_test_altqsupport(dev_fd, opts);
1631 	} else {
1632 		dev_fd = open(pf_device, O_RDONLY);
1633 		if (dev_fd >= 0)
1634 			opts |= PF_OPT_DUMMYACTION;
1635 		/* turn off options */
1636 		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
1637 		clearopt = showopt = debugopt = NULL;
1638 		altqsupport = 1;
1639 	}
1640 
1641 	if (opts & PF_OPT_DISABLE)
1642 		if (pfctl_disable(dev_fd, opts))
1643 			error = 1;
1644 
1645 	if (showopt != NULL) {
1646 		switch (*showopt) {
1647 		case 'A':
1648 			pfctl_show_anchors(dev_fd, opts, anchorname);
1649 			break;
1650 		case 'r':
1651 			pfctl_load_fingerprints(dev_fd, opts);
1652 			pfctl_show_rules(dev_fd, opts, 0, anchorname,
1653 			    rulesetname);
1654 			break;
1655 		case 'l':
1656 			pfctl_load_fingerprints(dev_fd, opts);
1657 			pfctl_show_rules(dev_fd, opts, 1, anchorname,
1658 			    rulesetname);
1659 			break;
1660 		case 'n':
1661 			pfctl_load_fingerprints(dev_fd, opts);
1662 			pfctl_show_nat(dev_fd, opts, anchorname, rulesetname);
1663 			break;
1664 #ifndef __DragonFly__
1665 		case 'q':
1666 			pfctl_show_altq(dev_fd, ifaceopt, opts,
1667 			    opts & PF_OPT_VERBOSE2);
1668 			break;
1669 #endif
1670 		case 's':
1671 			pfctl_show_states(dev_fd, ifaceopt, opts);
1672 			break;
1673 		case 'S':
1674 			pfctl_show_src_nodes(dev_fd, opts);
1675 			break;
1676 		case 'i':
1677 			pfctl_show_status(dev_fd, opts);
1678 			break;
1679 		case 't':
1680 			pfctl_show_timeouts(dev_fd, opts);
1681 			break;
1682 		case 'm':
1683 			pfctl_show_limits(dev_fd, opts);
1684 			break;
1685 		case 'a':
1686 			opts |= PF_OPT_SHOWALL;
1687 			pfctl_load_fingerprints(dev_fd, opts);
1688 
1689 			pfctl_show_nat(dev_fd, opts, anchorname, rulesetname);
1690 			pfctl_show_rules(dev_fd, opts, 0, anchorname,
1691 			    rulesetname);
1692 #ifndef __DragonFly__
1693 			pfctl_show_altq(dev_fd, ifaceopt, opts, 0);
1694 #endif
1695 			pfctl_show_states(dev_fd, ifaceopt, opts);
1696 			pfctl_show_src_nodes(dev_fd, opts);
1697 			pfctl_show_status(dev_fd, opts);
1698 			pfctl_show_rules(dev_fd, opts, 1, anchorname, rulesetname);
1699 			pfctl_show_timeouts(dev_fd, opts);
1700 			pfctl_show_limits(dev_fd, opts);
1701 			pfctl_show_tables(anchorname, rulesetname, opts);
1702 			pfctl_show_fingerprints(opts);
1703 			break;
1704 		case 'T':
1705 			pfctl_show_tables(anchorname, rulesetname, opts);
1706 			break;
1707 		case 'o':
1708 			pfctl_load_fingerprints(dev_fd, opts);
1709 			pfctl_show_fingerprints(opts);
1710 			break;
1711 		case 'I':
1712 			pfctl_show_ifaces(ifaceopt, opts);
1713 			break;
1714 		}
1715 	}
1716 
1717 	if (clearopt != NULL) {
1718 		switch (*clearopt) {
1719 		case 'r':
1720 			pfctl_clear_rules(dev_fd, opts, anchorname, rulesetname);
1721 			break;
1722 		case 'n':
1723 			pfctl_clear_nat(dev_fd, opts, anchorname, rulesetname);
1724 			break;
1725 #ifndef __DragonFly__
1726 		case 'q':
1727 			pfctl_clear_altq(dev_fd, opts);
1728 			break;
1729 #endif
1730 		case 's':
1731 			pfctl_clear_states(dev_fd, ifaceopt, opts);
1732 			break;
1733 		case 'S':
1734 			pfctl_clear_src_nodes(dev_fd, opts);
1735 			break;
1736 		case 'i':
1737 			pfctl_clear_stats(dev_fd, opts);
1738 			break;
1739 		case 'a':
1740 			pfctl_clear_rules(dev_fd, opts, anchorname, rulesetname);
1741 			pfctl_clear_nat(dev_fd, opts, anchorname, rulesetname);
1742 			pfctl_clear_tables(anchorname, rulesetname, opts);
1743 			if (!*anchorname && !*rulesetname) {
1744 #ifndef __DragonFly__
1745 				pfctl_clear_altq(dev_fd, opts);
1746 #endif
1747 				pfctl_clear_states(dev_fd, ifaceopt, opts);
1748 				pfctl_clear_src_nodes(dev_fd, opts);
1749 				pfctl_clear_stats(dev_fd, opts);
1750 				pfctl_clear_fingerprints(dev_fd, opts);
1751 			}
1752 			break;
1753 		case 'o':
1754 			pfctl_clear_fingerprints(dev_fd, opts);
1755 			break;
1756 		case 'T':
1757 			pfctl_clear_tables(anchorname, rulesetname, opts);
1758 			break;
1759 		}
1760 	}
1761 	if (state_killers)
1762 		pfctl_kill_states(dev_fd, ifaceopt, opts);
1763 
1764 	if (tblcmdopt != NULL) {
1765 		error = pfctl_command_tables(argc, argv, tableopt,
1766 		    tblcmdopt, rulesopt, anchorname, rulesetname, opts);
1767 		rulesopt = NULL;
1768 	}
1769 
1770 	if (rulesopt != NULL)
1771 		if (pfctl_file_fingerprints(dev_fd, opts, PF_OSFP_FILE))
1772 			error = 1;
1773 
1774 	if (rulesopt != NULL) {
1775 		if (pfctl_rules(dev_fd, rulesopt, opts, anchorname, rulesetname,
1776 		    NULL))
1777 			error = 1;
1778 		else if (!(opts & PF_OPT_NOACTION) &&
1779 		    (loadopt & PFCTL_FLAG_TABLE))
1780 			warn_namespace_collision(NULL);
1781 	}
1782 
1783 	if (opts & PF_OPT_ENABLE)
1784 		if (pfctl_enable(dev_fd, opts))
1785 			error = 1;
1786 
1787 	if (debugopt != NULL) {
1788 		switch (*debugopt) {
1789 		case 'n':
1790 			pfctl_debug(dev_fd, PF_DEBUG_NONE, opts);
1791 			break;
1792 		case 'u':
1793 			pfctl_debug(dev_fd, PF_DEBUG_URGENT, opts);
1794 			break;
1795 		case 'm':
1796 			pfctl_debug(dev_fd, PF_DEBUG_MISC, opts);
1797 			break;
1798 		case 'l':
1799 			pfctl_debug(dev_fd, PF_DEBUG_NOISY, opts);
1800 			break;
1801 		}
1802 	}
1803 
1804 	if (opts & PF_OPT_CLRRULECTRS) {
1805 		if (pfctl_clear_rule_counters(dev_fd, opts))
1806 			error = 1;
1807 	}
1808 	exit(error);
1809 }
1810