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