pfctl.c revision 258485
1223637Sbz/*	$OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */
2126353Smlaier
3126353Smlaier/*
4126353Smlaier * Copyright (c) 2001 Daniel Hartmeier
5130617Smlaier * Copyright (c) 2002,2003 Henning Brauer
6126353Smlaier * All rights reserved.
7126353Smlaier *
8126353Smlaier * Redistribution and use in source and binary forms, with or without
9126353Smlaier * modification, are permitted provided that the following conditions
10126353Smlaier * are met:
11126353Smlaier *
12126353Smlaier *    - Redistributions of source code must retain the above copyright
13126353Smlaier *      notice, this list of conditions and the following disclaimer.
14126353Smlaier *    - Redistributions in binary form must reproduce the above
15126353Smlaier *      copyright notice, this list of conditions and the following
16126353Smlaier *      disclaimer in the documentation and/or other materials provided
17126353Smlaier *      with the distribution.
18126353Smlaier *
19126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20126353Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21126353Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22126353Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23126353Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24126353Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25126353Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26126353Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27126353Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29126353Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30126353Smlaier * POSSIBILITY OF SUCH DAMAGE.
31126353Smlaier *
32126353Smlaier */
33126353Smlaier
34127082Sobrien#include <sys/cdefs.h>
35127082Sobrien__FBSDID("$FreeBSD: head/sbin/pfctl/pfctl.c 258485 2013-11-22 20:13:32Z glebius $");
36127082Sobrien
37126353Smlaier#include <sys/types.h>
38126353Smlaier#include <sys/ioctl.h>
39126353Smlaier#include <sys/socket.h>
40145840Smlaier#include <sys/stat.h>
41223637Sbz#include <sys/endian.h>
42223637Sbz
43126353Smlaier#include <net/if.h>
44126353Smlaier#include <netinet/in.h>
45126353Smlaier#include <net/pfvar.h>
46126353Smlaier#include <arpa/inet.h>
47126353Smlaier#include <altq/altq.h>
48171172Smlaier#include <sys/sysctl.h>
49126353Smlaier
50126353Smlaier#include <err.h>
51126353Smlaier#include <errno.h>
52126353Smlaier#include <fcntl.h>
53126353Smlaier#include <limits.h>
54126353Smlaier#include <netdb.h>
55126353Smlaier#include <stdio.h>
56126353Smlaier#include <stdlib.h>
57126353Smlaier#include <string.h>
58126353Smlaier#include <unistd.h>
59126353Smlaier
60126353Smlaier#include "pfctl_parser.h"
61126353Smlaier#include "pfctl.h"
62126353Smlaier
63126353Smlaiervoid	 usage(void);
64126353Smlaierint	 pfctl_enable(int, int);
65126353Smlaierint	 pfctl_disable(int, int);
66126353Smlaierint	 pfctl_clear_stats(int, int);
67145840Smlaierint	 pfctl_clear_interface_flags(int, int);
68145840Smlaierint	 pfctl_clear_rules(int, int, char *);
69145840Smlaierint	 pfctl_clear_nat(int, int, char *);
70126353Smlaierint	 pfctl_clear_altq(int, int);
71130617Smlaierint	 pfctl_clear_src_nodes(int, int);
72130617Smlaierint	 pfctl_clear_states(int, const char *, int);
73171172Smlaiervoid	 pfctl_addrprefix(char *, struct pf_addr *);
74171172Smlaierint	 pfctl_kill_src_nodes(int, const char *, int);
75223637Sbzint	 pfctl_net_kill_states(int, const char *, int);
76223637Sbzint	 pfctl_label_kill_states(int, const char *, int);
77223637Sbzint	 pfctl_id_kill_states(int, const char *, int);
78145840Smlaiervoid	 pfctl_init_options(struct pfctl *);
79145840Smlaierint	 pfctl_load_options(struct pfctl *);
80145840Smlaierint	 pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
81145840Smlaierint	 pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
82145840Smlaierint	 pfctl_load_debug(struct pfctl *, unsigned int);
83145840Smlaierint	 pfctl_load_logif(struct pfctl *, char *);
84145840Smlaierint	 pfctl_load_hostid(struct pfctl *, unsigned int);
85126353Smlaierint	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
86145840Smlaier	    char *);
87126353Smlaiervoid	 pfctl_print_rule_counters(struct pf_rule *, int);
88171172Smlaierint	 pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
89145840Smlaierint	 pfctl_show_nat(int, int, char *);
90130617Smlaierint	 pfctl_show_src_nodes(int, int);
91130617Smlaierint	 pfctl_show_states(int, const char *, int);
92130617Smlaierint	 pfctl_show_status(int, int);
93130617Smlaierint	 pfctl_show_timeouts(int, int);
94130617Smlaierint	 pfctl_show_limits(int, int);
95145840Smlaiervoid	 pfctl_debug(int, u_int32_t, int);
96126353Smlaierint	 pfctl_test_altqsupport(int, int);
97126353Smlaierint	 pfctl_show_anchors(int, int, char *);
98171172Smlaierint	 pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
99171172Smlaierint	 pfctl_load_ruleset(struct pfctl *, char *,
100171172Smlaier		struct pf_ruleset *, int, int);
101171172Smlaierint	 pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
102126353Smlaierconst char	*pfctl_lookup_option(char *, const char **);
103126353Smlaier
104171172Smlaierstruct pf_anchor_global	 pf_anchors;
105171172Smlaierstruct pf_anchor	 pf_main_anchor;
106171172Smlaier
107126353Smlaierconst char	*clearopt;
108126353Smlaierchar		*rulesopt;
109126353Smlaierconst char	*showopt;
110126353Smlaierconst char	*debugopt;
111126353Smlaierchar		*anchoropt;
112171172Smlaierconst char	*optiopt = NULL;
113130617Smlaierchar		*pf_device = "/dev/pf";
114130617Smlaierchar		*ifaceopt;
115126353Smlaierchar		*tableopt;
116126353Smlaierconst char	*tblcmdopt;
117171172Smlaierint		 src_node_killers;
118171172Smlaierchar		*src_node_kill[2];
119126353Smlaierint		 state_killers;
120126353Smlaierchar		*state_kill[2];
121126353Smlaierint		 loadopt;
122126353Smlaierint		 altqsupport;
123126353Smlaier
124126353Smlaierint		 dev = -1;
125130617Smlaierint		 first_title = 1;
126130617Smlaierint		 labels = 0;
127126353Smlaier
128171172Smlaier#define INDENT(d, o)	do {						\
129171172Smlaier				if (o) {				\
130171172Smlaier					int i;				\
131171172Smlaier					for (i=0; i < d; i++)		\
132171172Smlaier						printf("  ");		\
133171172Smlaier				}					\
134171172Smlaier			} while (0);					\
135171172Smlaier
136171172Smlaier
137126353Smlaierstatic const struct {
138126353Smlaier	const char	*name;
139126353Smlaier	int		index;
140126353Smlaier} pf_limits[] = {
141171172Smlaier	{ "states",		PF_LIMIT_STATES },
142171172Smlaier	{ "src-nodes",		PF_LIMIT_SRC_NODES },
143171172Smlaier	{ "frags",		PF_LIMIT_FRAGS },
144171172Smlaier	{ "table-entries",	PF_LIMIT_TABLE_ENTRIES },
145171172Smlaier	{ NULL,			0 }
146126353Smlaier};
147126353Smlaier
148126353Smlaierstruct pf_hint {
149126353Smlaier	const char	*name;
150126353Smlaier	int		timeout;
151126353Smlaier};
152126353Smlaierstatic const struct pf_hint pf_hint_normal[] = {
153126353Smlaier	{ "tcp.first",		2 * 60 },
154126353Smlaier	{ "tcp.opening",	30 },
155126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
156126353Smlaier	{ "tcp.closing",	15 * 60 },
157126353Smlaier	{ "tcp.finwait",	45 },
158126353Smlaier	{ "tcp.closed",		90 },
159145840Smlaier	{ "tcp.tsdiff",		30 },
160126353Smlaier	{ NULL,			0 }
161126353Smlaier};
162126353Smlaierstatic const struct pf_hint pf_hint_satellite[] = {
163126353Smlaier	{ "tcp.first",		3 * 60 },
164126353Smlaier	{ "tcp.opening",	30 + 5 },
165126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
166126353Smlaier	{ "tcp.closing",	15 * 60 + 5 },
167126353Smlaier	{ "tcp.finwait",	45 + 5 },
168126353Smlaier	{ "tcp.closed",		90 + 5 },
169145840Smlaier	{ "tcp.tsdiff",		60 },
170126353Smlaier	{ NULL,			0 }
171126353Smlaier};
172126353Smlaierstatic const struct pf_hint pf_hint_conservative[] = {
173126353Smlaier	{ "tcp.first",		60 * 60 },
174126353Smlaier	{ "tcp.opening",	15 * 60 },
175126353Smlaier	{ "tcp.established",	5 * 24 * 60 * 60 },
176126353Smlaier	{ "tcp.closing",	60 * 60 },
177126353Smlaier	{ "tcp.finwait",	10 * 60 },
178126353Smlaier	{ "tcp.closed",		3 * 60 },
179145840Smlaier	{ "tcp.tsdiff",		60 },
180126353Smlaier	{ NULL,			0 }
181126353Smlaier};
182126353Smlaierstatic const struct pf_hint pf_hint_aggressive[] = {
183126353Smlaier	{ "tcp.first",		30 },
184126353Smlaier	{ "tcp.opening",	5 },
185126353Smlaier	{ "tcp.established",	5 * 60 * 60 },
186126353Smlaier	{ "tcp.closing",	60 },
187126353Smlaier	{ "tcp.finwait",	30 },
188126353Smlaier	{ "tcp.closed",		30 },
189145840Smlaier	{ "tcp.tsdiff",		10 },
190126353Smlaier	{ NULL,			0 }
191126353Smlaier};
192126353Smlaier
193126353Smlaierstatic const struct {
194126353Smlaier	const char *name;
195126353Smlaier	const struct pf_hint *hint;
196126353Smlaier} pf_hints[] = {
197126353Smlaier	{ "normal",		pf_hint_normal },
198126353Smlaier	{ "satellite",		pf_hint_satellite },
199126353Smlaier	{ "high-latency",	pf_hint_satellite },
200126353Smlaier	{ "conservative",	pf_hint_conservative },
201126353Smlaier	{ "aggressive",		pf_hint_aggressive },
202126353Smlaier	{ NULL,			NULL }
203126353Smlaier};
204126353Smlaier
205126353Smlaierstatic const char *clearopt_list[] = {
206130617Smlaier	"nat", "queue", "rules", "Sources",
207223637Sbz	"states", "info", "Tables", "osfp", "all", NULL
208126353Smlaier};
209126353Smlaier
210126353Smlaierstatic const char *showopt_list[] = {
211223637Sbz	"nat", "queue", "rules", "Anchors", "Sources", "states", "info",
212130617Smlaier	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
213130617Smlaier	"all", NULL
214126353Smlaier};
215126353Smlaier
216126353Smlaierstatic const char *tblcmdopt_list[] = {
217126353Smlaier	"kill", "flush", "add", "delete", "load", "replace", "show",
218171172Smlaier	"test", "zero", "expire", NULL
219126353Smlaier};
220126353Smlaier
221126353Smlaierstatic const char *debugopt_list[] = {
222126353Smlaier	"none", "urgent", "misc", "loud", NULL
223126353Smlaier};
224126353Smlaier
225171172Smlaierstatic const char *optiopt_list[] = {
226223637Sbz	"none", "basic", "profile", NULL
227171172Smlaier};
228126353Smlaier
229126353Smlaiervoid
230126353Smlaierusage(void)
231126353Smlaier{
232126353Smlaier	extern char *__progname;
233126353Smlaier
234258484Sglebius	fprintf(stderr,
235258484Sglebius"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
236258484Sglebius	"\t[-f file] [-i interface] [-K host | network]\n"
237258484Sglebius	"\t[-k host | network | label | id] [-o level] [-p device]\n"
238258484Sglebius	"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
239258484Sglebius	    __progname);
240258484Sglebius
241126353Smlaier	exit(1);
242126353Smlaier}
243126353Smlaier
244126353Smlaierint
245126353Smlaierpfctl_enable(int dev, int opts)
246126353Smlaier{
247126353Smlaier	if (ioctl(dev, DIOCSTART)) {
248126353Smlaier		if (errno == EEXIST)
249126353Smlaier			errx(1, "pf already enabled");
250126355Smlaier		else if (errno == ESRCH)
251126355Smlaier			errx(1, "pfil registeration failed");
252126353Smlaier		else
253126353Smlaier			err(1, "DIOCSTART");
254126353Smlaier	}
255126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
256126353Smlaier		fprintf(stderr, "pf enabled\n");
257126353Smlaier
258126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
259126353Smlaier		if (errno != EEXIST)
260126353Smlaier			err(1, "DIOCSTARTALTQ");
261126353Smlaier
262126353Smlaier	return (0);
263126353Smlaier}
264126353Smlaier
265126353Smlaierint
266126353Smlaierpfctl_disable(int dev, int opts)
267126353Smlaier{
268126353Smlaier	if (ioctl(dev, DIOCSTOP)) {
269126353Smlaier		if (errno == ENOENT)
270126353Smlaier			errx(1, "pf not enabled");
271126353Smlaier		else
272126353Smlaier			err(1, "DIOCSTOP");
273126353Smlaier	}
274126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
275126353Smlaier		fprintf(stderr, "pf disabled\n");
276126353Smlaier
277126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
278126353Smlaier			if (errno != ENOENT)
279126353Smlaier				err(1, "DIOCSTOPALTQ");
280126353Smlaier
281126353Smlaier	return (0);
282126353Smlaier}
283126353Smlaier
284126353Smlaierint
285126353Smlaierpfctl_clear_stats(int dev, int opts)
286126353Smlaier{
287126353Smlaier	if (ioctl(dev, DIOCCLRSTATUS))
288126353Smlaier		err(1, "DIOCCLRSTATUS");
289126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
290126353Smlaier		fprintf(stderr, "pf: statistics cleared\n");
291126353Smlaier	return (0);
292126353Smlaier}
293126353Smlaier
294126353Smlaierint
295145840Smlaierpfctl_clear_interface_flags(int dev, int opts)
296126353Smlaier{
297145840Smlaier	struct pfioc_iface	pi;
298126353Smlaier
299145840Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
300145840Smlaier		bzero(&pi, sizeof(pi));
301171172Smlaier		pi.pfiio_flags = PFI_IFLAG_SKIP;
302126353Smlaier
303145840Smlaier		if (ioctl(dev, DIOCCLRIFFLAG, &pi))
304145840Smlaier			err(1, "DIOCCLRIFFLAG");
305126353Smlaier		if ((opts & PF_OPT_QUIET) == 0)
306145840Smlaier			fprintf(stderr, "pf: interface flags reset\n");
307126353Smlaier	}
308145840Smlaier	return (0);
309145840Smlaier}
310145840Smlaier
311145840Smlaierint
312145840Smlaierpfctl_clear_rules(int dev, int opts, char *anchorname)
313145840Smlaier{
314145840Smlaier	struct pfr_buffer t;
315145840Smlaier
316130617Smlaier	memset(&t, 0, sizeof(t));
317130617Smlaier	t.pfrb_type = PFRB_TRANS;
318145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
319145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
320130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
321130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
322130617Smlaier		err(1, "pfctl_clear_rules");
323126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
324126353Smlaier		fprintf(stderr, "rules cleared\n");
325126353Smlaier	return (0);
326126353Smlaier}
327126353Smlaier
328126353Smlaierint
329145840Smlaierpfctl_clear_nat(int dev, int opts, char *anchorname)
330126353Smlaier{
331130617Smlaier	struct pfr_buffer t;
332126353Smlaier
333130617Smlaier	memset(&t, 0, sizeof(t));
334130617Smlaier	t.pfrb_type = PFRB_TRANS;
335145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
336145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
337145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
338130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
339130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
340130617Smlaier		err(1, "pfctl_clear_nat");
341126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
342126353Smlaier		fprintf(stderr, "nat cleared\n");
343126353Smlaier	return (0);
344126353Smlaier}
345126353Smlaier
346126353Smlaierint
347126353Smlaierpfctl_clear_altq(int dev, int opts)
348126353Smlaier{
349130617Smlaier	struct pfr_buffer t;
350126353Smlaier
351126353Smlaier	if (!altqsupport)
352126353Smlaier		return (-1);
353130617Smlaier	memset(&t, 0, sizeof(t));
354130617Smlaier	t.pfrb_type = PFRB_TRANS;
355145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
356130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
357130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
358130617Smlaier		err(1, "pfctl_clear_altq");
359126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
360126353Smlaier		fprintf(stderr, "altq cleared\n");
361126353Smlaier	return (0);
362126353Smlaier}
363126353Smlaier
364126353Smlaierint
365130617Smlaierpfctl_clear_src_nodes(int dev, int opts)
366126353Smlaier{
367130617Smlaier	if (ioctl(dev, DIOCCLRSRCNODES))
368130617Smlaier		err(1, "DIOCCLRSRCNODES");
369130617Smlaier	if ((opts & PF_OPT_QUIET) == 0)
370130617Smlaier		fprintf(stderr, "source tracking entries cleared\n");
371130617Smlaier	return (0);
372130617Smlaier}
373130617Smlaier
374130617Smlaierint
375130617Smlaierpfctl_clear_states(int dev, const char *iface, int opts)
376130617Smlaier{
377130617Smlaier	struct pfioc_state_kill psk;
378130617Smlaier
379130617Smlaier	memset(&psk, 0, sizeof(psk));
380130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
381130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
382130617Smlaier		errx(1, "invalid interface: %s", iface);
383130617Smlaier
384130617Smlaier	if (ioctl(dev, DIOCCLRSTATES, &psk))
385126353Smlaier		err(1, "DIOCCLRSTATES");
386126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
387223637Sbz		fprintf(stderr, "%d states cleared\n", psk.psk_killed);
388126353Smlaier	return (0);
389126353Smlaier}
390126353Smlaier
391171172Smlaiervoid
392171172Smlaierpfctl_addrprefix(char *addr, struct pf_addr *mask)
393171172Smlaier{
394171172Smlaier	char *p;
395171172Smlaier	const char *errstr;
396171172Smlaier	int prefix, ret_ga, q, r;
397171172Smlaier	struct addrinfo hints, *res;
398171172Smlaier
399171172Smlaier	if ((p = strchr(addr, '/')) == NULL)
400171172Smlaier		return;
401171172Smlaier
402171172Smlaier	*p++ = '\0';
403171172Smlaier	prefix = strtonum(p, 0, 128, &errstr);
404171172Smlaier	if (errstr)
405171172Smlaier		errx(1, "prefix is %s: %s", errstr, p);
406171172Smlaier
407171172Smlaier	bzero(&hints, sizeof(hints));
408171172Smlaier	/* prefix only with numeric addresses */
409171172Smlaier	hints.ai_flags |= AI_NUMERICHOST;
410171172Smlaier
411171172Smlaier	if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
412171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
413171172Smlaier		/* NOTREACHED */
414171172Smlaier	}
415171172Smlaier
416171172Smlaier	if (res->ai_family == AF_INET && prefix > 32)
417171172Smlaier		errx(1, "prefix too long for AF_INET");
418171172Smlaier	else if (res->ai_family == AF_INET6 && prefix > 128)
419171172Smlaier		errx(1, "prefix too long for AF_INET6");
420171172Smlaier
421171172Smlaier	q = prefix >> 3;
422171172Smlaier	r = prefix & 7;
423171172Smlaier	switch (res->ai_family) {
424171172Smlaier	case AF_INET:
425171172Smlaier		bzero(&mask->v4, sizeof(mask->v4));
426171172Smlaier		mask->v4.s_addr = htonl((u_int32_t)
427171172Smlaier		    (0xffffffffffULL << (32 - prefix)));
428171172Smlaier		break;
429171172Smlaier	case AF_INET6:
430171172Smlaier		bzero(&mask->v6, sizeof(mask->v6));
431171172Smlaier		if (q > 0)
432171172Smlaier			memset((void *)&mask->v6, 0xff, q);
433171172Smlaier		if (r > 0)
434171172Smlaier			*((u_char *)&mask->v6 + q) =
435171172Smlaier			    (0xff00 >> r) & 0xff;
436171172Smlaier		break;
437171172Smlaier	}
438171172Smlaier	freeaddrinfo(res);
439171172Smlaier}
440171172Smlaier
441126353Smlaierint
442171172Smlaierpfctl_kill_src_nodes(int dev, const char *iface, int opts)
443171172Smlaier{
444171172Smlaier	struct pfioc_src_node_kill psnk;
445171172Smlaier	struct addrinfo *res[2], *resp[2];
446171172Smlaier	struct sockaddr last_src, last_dst;
447171172Smlaier	int killed, sources, dests;
448171172Smlaier	int ret_ga;
449171172Smlaier
450171172Smlaier	killed = sources = dests = 0;
451171172Smlaier
452171172Smlaier	memset(&psnk, 0, sizeof(psnk));
453171172Smlaier	memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
454171172Smlaier	    sizeof(psnk.psnk_src.addr.v.a.mask));
455171172Smlaier	memset(&last_src, 0xff, sizeof(last_src));
456171172Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
457171172Smlaier
458171172Smlaier	pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
459171172Smlaier
460171172Smlaier	if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
461171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
462171172Smlaier		/* NOTREACHED */
463171172Smlaier	}
464171172Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
465171172Smlaier		if (resp[0]->ai_addr == NULL)
466171172Smlaier			continue;
467171172Smlaier		/* We get lots of duplicates.  Catch the easy ones */
468171172Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
469171172Smlaier			continue;
470171172Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
471171172Smlaier
472171172Smlaier		psnk.psnk_af = resp[0]->ai_family;
473171172Smlaier		sources++;
474171172Smlaier
475171172Smlaier		if (psnk.psnk_af == AF_INET)
476171172Smlaier			psnk.psnk_src.addr.v.a.addr.v4 =
477171172Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
478171172Smlaier		else if (psnk.psnk_af == AF_INET6)
479171172Smlaier			psnk.psnk_src.addr.v.a.addr.v6 =
480171172Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
481171172Smlaier			    sin6_addr;
482171172Smlaier		else
483171172Smlaier			errx(1, "Unknown address family %d", psnk.psnk_af);
484171172Smlaier
485171172Smlaier		if (src_node_killers > 1) {
486171172Smlaier			dests = 0;
487171172Smlaier			memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
488171172Smlaier			    sizeof(psnk.psnk_dst.addr.v.a.mask));
489171172Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
490171172Smlaier			pfctl_addrprefix(src_node_kill[1],
491171172Smlaier			    &psnk.psnk_dst.addr.v.a.mask);
492171172Smlaier			if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
493171172Smlaier			    &res[1]))) {
494171172Smlaier				errx(1, "getaddrinfo: %s",
495171172Smlaier				    gai_strerror(ret_ga));
496171172Smlaier				/* NOTREACHED */
497171172Smlaier			}
498171172Smlaier			for (resp[1] = res[1]; resp[1];
499171172Smlaier			    resp[1] = resp[1]->ai_next) {
500171172Smlaier				if (resp[1]->ai_addr == NULL)
501171172Smlaier					continue;
502171172Smlaier				if (psnk.psnk_af != resp[1]->ai_family)
503171172Smlaier					continue;
504171172Smlaier
505171172Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
506171172Smlaier				    sizeof(last_dst)) == 0)
507171172Smlaier					continue;
508171172Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
509171172Smlaier
510171172Smlaier				dests++;
511171172Smlaier
512171172Smlaier				if (psnk.psnk_af == AF_INET)
513171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v4 =
514171172Smlaier					    ((struct sockaddr_in *)resp[1]->
515171172Smlaier					    ai_addr)->sin_addr;
516171172Smlaier				else if (psnk.psnk_af == AF_INET6)
517171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v6 =
518171172Smlaier					    ((struct sockaddr_in6 *)resp[1]->
519171172Smlaier					    ai_addr)->sin6_addr;
520171172Smlaier				else
521171172Smlaier					errx(1, "Unknown address family %d",
522171172Smlaier					    psnk.psnk_af);
523171172Smlaier
524171172Smlaier				if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
525171172Smlaier					err(1, "DIOCKILLSRCNODES");
526223637Sbz				killed += psnk.psnk_killed;
527171172Smlaier			}
528171172Smlaier			freeaddrinfo(res[1]);
529171172Smlaier		} else {
530171172Smlaier			if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
531171172Smlaier				err(1, "DIOCKILLSRCNODES");
532223637Sbz			killed += psnk.psnk_killed;
533171172Smlaier		}
534171172Smlaier	}
535171172Smlaier
536171172Smlaier	freeaddrinfo(res[0]);
537171172Smlaier
538171172Smlaier	if ((opts & PF_OPT_QUIET) == 0)
539171172Smlaier		fprintf(stderr, "killed %d src nodes from %d sources and %d "
540171172Smlaier		    "destinations\n", killed, sources, dests);
541171172Smlaier	return (0);
542171172Smlaier}
543171172Smlaier
544171172Smlaierint
545223637Sbzpfctl_net_kill_states(int dev, const char *iface, int opts)
546126353Smlaier{
547126353Smlaier	struct pfioc_state_kill psk;
548126353Smlaier	struct addrinfo *res[2], *resp[2];
549126353Smlaier	struct sockaddr last_src, last_dst;
550126353Smlaier	int killed, sources, dests;
551126353Smlaier	int ret_ga;
552126353Smlaier
553126353Smlaier	killed = sources = dests = 0;
554126353Smlaier
555126353Smlaier	memset(&psk, 0, sizeof(psk));
556126353Smlaier	memset(&psk.psk_src.addr.v.a.mask, 0xff,
557126353Smlaier	    sizeof(psk.psk_src.addr.v.a.mask));
558126353Smlaier	memset(&last_src, 0xff, sizeof(last_src));
559126353Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
560130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
561130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
562130617Smlaier		errx(1, "invalid interface: %s", iface);
563126353Smlaier
564171172Smlaier	pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
565171172Smlaier
566126353Smlaier	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
567126353Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
568126353Smlaier		/* NOTREACHED */
569126353Smlaier	}
570126353Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
571126353Smlaier		if (resp[0]->ai_addr == NULL)
572126353Smlaier			continue;
573126353Smlaier		/* We get lots of duplicates.  Catch the easy ones */
574126353Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
575126353Smlaier			continue;
576126353Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
577126353Smlaier
578126353Smlaier		psk.psk_af = resp[0]->ai_family;
579126353Smlaier		sources++;
580126353Smlaier
581126353Smlaier		if (psk.psk_af == AF_INET)
582126353Smlaier			psk.psk_src.addr.v.a.addr.v4 =
583126353Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
584126353Smlaier		else if (psk.psk_af == AF_INET6)
585126353Smlaier			psk.psk_src.addr.v.a.addr.v6 =
586126353Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
587126353Smlaier			    sin6_addr;
588126353Smlaier		else
589126353Smlaier			errx(1, "Unknown address family %d", psk.psk_af);
590126353Smlaier
591126353Smlaier		if (state_killers > 1) {
592126353Smlaier			dests = 0;
593126353Smlaier			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
594126353Smlaier			    sizeof(psk.psk_dst.addr.v.a.mask));
595126353Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
596171172Smlaier			pfctl_addrprefix(state_kill[1],
597171172Smlaier			    &psk.psk_dst.addr.v.a.mask);
598126353Smlaier			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
599126353Smlaier			    &res[1]))) {
600130617Smlaier				errx(1, "getaddrinfo: %s",
601130617Smlaier				    gai_strerror(ret_ga));
602126353Smlaier				/* NOTREACHED */
603126353Smlaier			}
604126353Smlaier			for (resp[1] = res[1]; resp[1];
605126353Smlaier			    resp[1] = resp[1]->ai_next) {
606126353Smlaier				if (resp[1]->ai_addr == NULL)
607126353Smlaier					continue;
608126353Smlaier				if (psk.psk_af != resp[1]->ai_family)
609126353Smlaier					continue;
610126353Smlaier
611126353Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
612126353Smlaier				    sizeof(last_dst)) == 0)
613126353Smlaier					continue;
614126353Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
615126353Smlaier
616126353Smlaier				dests++;
617126353Smlaier
618126353Smlaier				if (psk.psk_af == AF_INET)
619126353Smlaier					psk.psk_dst.addr.v.a.addr.v4 =
620126353Smlaier					    ((struct sockaddr_in *)resp[1]->
621126353Smlaier					    ai_addr)->sin_addr;
622126353Smlaier				else if (psk.psk_af == AF_INET6)
623126353Smlaier					psk.psk_dst.addr.v.a.addr.v6 =
624126353Smlaier					    ((struct sockaddr_in6 *)resp[1]->
625126353Smlaier					    ai_addr)->sin6_addr;
626126353Smlaier				else
627126353Smlaier					errx(1, "Unknown address family %d",
628126353Smlaier					    psk.psk_af);
629126353Smlaier
630126353Smlaier				if (ioctl(dev, DIOCKILLSTATES, &psk))
631126353Smlaier					err(1, "DIOCKILLSTATES");
632223637Sbz				killed += psk.psk_killed;
633126353Smlaier			}
634126353Smlaier			freeaddrinfo(res[1]);
635126353Smlaier		} else {
636126353Smlaier			if (ioctl(dev, DIOCKILLSTATES, &psk))
637126353Smlaier				err(1, "DIOCKILLSTATES");
638223637Sbz			killed += psk.psk_killed;
639126353Smlaier		}
640126353Smlaier	}
641126353Smlaier
642126353Smlaier	freeaddrinfo(res[0]);
643126353Smlaier
644126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
645126353Smlaier		fprintf(stderr, "killed %d states from %d sources and %d "
646126353Smlaier		    "destinations\n", killed, sources, dests);
647126353Smlaier	return (0);
648126353Smlaier}
649126353Smlaier
650126353Smlaierint
651223637Sbzpfctl_label_kill_states(int dev, const char *iface, int opts)
652223637Sbz{
653223637Sbz	struct pfioc_state_kill psk;
654223637Sbz
655223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
656223637Sbz		warnx("no label specified");
657223637Sbz		usage();
658223637Sbz	}
659223637Sbz	memset(&psk, 0, sizeof(psk));
660223637Sbz	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
661223637Sbz	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
662223637Sbz		errx(1, "invalid interface: %s", iface);
663223637Sbz
664223637Sbz	if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
665223637Sbz	    sizeof(psk.psk_label))
666223637Sbz		errx(1, "label too long: %s", state_kill[1]);
667223637Sbz
668223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
669223637Sbz		err(1, "DIOCKILLSTATES");
670223637Sbz
671223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
672223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
673223637Sbz
674223637Sbz	return (0);
675223637Sbz}
676223637Sbz
677223637Sbzint
678223637Sbzpfctl_id_kill_states(int dev, const char *iface, int opts)
679223637Sbz{
680223637Sbz	struct pfioc_state_kill psk;
681223637Sbz
682223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
683223637Sbz		warnx("no id specified");
684223637Sbz		usage();
685223637Sbz	}
686223637Sbz
687223637Sbz	memset(&psk, 0, sizeof(psk));
688223637Sbz	if ((sscanf(state_kill[1], "%jx/%x",
689223637Sbz	    &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
690223637Sbz		HTONL(psk.psk_pfcmp.creatorid);
691223637Sbz	else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
692223637Sbz		psk.psk_pfcmp.creatorid = 0;
693223637Sbz	} else {
694223637Sbz		warnx("wrong id format specified");
695223637Sbz		usage();
696223637Sbz	}
697223637Sbz	if (psk.psk_pfcmp.id == 0) {
698223637Sbz		warnx("cannot kill id 0");
699223637Sbz		usage();
700223637Sbz	}
701223637Sbz
702223637Sbz	psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
703223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
704223637Sbz		err(1, "DIOCKILLSTATES");
705223637Sbz
706223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
707223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
708223637Sbz
709223637Sbz	return (0);
710223637Sbz}
711223637Sbz
712223637Sbzint
713126353Smlaierpfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
714145840Smlaier    u_int32_t ticket, int r_action, char *anchorname)
715126353Smlaier{
716126353Smlaier	struct pfioc_pooladdr pp;
717126353Smlaier	struct pf_pooladdr *pa;
718126353Smlaier	u_int32_t pnr, mpnr;
719126353Smlaier
720126353Smlaier	memset(&pp, 0, sizeof(pp));
721126353Smlaier	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
722126353Smlaier	pp.r_action = r_action;
723126353Smlaier	pp.r_num = nr;
724126353Smlaier	pp.ticket = ticket;
725126353Smlaier	if (ioctl(dev, DIOCGETADDRS, &pp)) {
726126353Smlaier		warn("DIOCGETADDRS");
727126353Smlaier		return (-1);
728126353Smlaier	}
729126353Smlaier	mpnr = pp.nr;
730126353Smlaier	TAILQ_INIT(&pool->list);
731126353Smlaier	for (pnr = 0; pnr < mpnr; ++pnr) {
732126353Smlaier		pp.nr = pnr;
733126353Smlaier		if (ioctl(dev, DIOCGETADDR, &pp)) {
734126353Smlaier			warn("DIOCGETADDR");
735126353Smlaier			return (-1);
736126353Smlaier		}
737126353Smlaier		pa = calloc(1, sizeof(struct pf_pooladdr));
738126353Smlaier		if (pa == NULL)
739126353Smlaier			err(1, "calloc");
740126353Smlaier		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
741126353Smlaier		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
742126353Smlaier	}
743126353Smlaier
744126353Smlaier	return (0);
745126353Smlaier}
746126353Smlaier
747126353Smlaiervoid
748171172Smlaierpfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
749171172Smlaier{
750171172Smlaier	struct pf_pooladdr *pa;
751171172Smlaier
752171172Smlaier	while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
753171172Smlaier		TAILQ_REMOVE(&src->list, pa, entries);
754171172Smlaier		TAILQ_INSERT_TAIL(&dst->list, pa, entries);
755171172Smlaier	}
756171172Smlaier}
757171172Smlaier
758171172Smlaiervoid
759126353Smlaierpfctl_clear_pool(struct pf_pool *pool)
760126353Smlaier{
761126353Smlaier	struct pf_pooladdr *pa;
762126353Smlaier
763126353Smlaier	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
764126353Smlaier		TAILQ_REMOVE(&pool->list, pa, entries);
765126353Smlaier		free(pa);
766126353Smlaier	}
767126353Smlaier}
768126353Smlaier
769126353Smlaiervoid
770126353Smlaierpfctl_print_rule_counters(struct pf_rule *rule, int opts)
771126353Smlaier{
772126353Smlaier	if (opts & PF_OPT_DEBUG) {
773126353Smlaier		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
774126353Smlaier		    "p", "sa", "sp", "da", "dp" };
775126353Smlaier		int i;
776126353Smlaier
777126353Smlaier		printf("  [ Skip steps: ");
778126353Smlaier		for (i = 0; i < PF_SKIP_COUNT; ++i) {
779126353Smlaier			if (rule->skip[i].nr == rule->nr + 1)
780126353Smlaier				continue;
781126353Smlaier			printf("%s=", t[i]);
782126353Smlaier			if (rule->skip[i].nr == -1)
783126353Smlaier				printf("end ");
784126353Smlaier			else
785126353Smlaier				printf("%u ", rule->skip[i].nr);
786126353Smlaier		}
787126353Smlaier		printf("]\n");
788126353Smlaier
789126353Smlaier		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
790126353Smlaier		    rule->qname, rule->qid, rule->pqname, rule->pqid);
791126353Smlaier	}
792171172Smlaier	if (opts & PF_OPT_VERBOSE) {
793127024Smlaier		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
794127024Smlaier			    "Bytes: %-10llu  States: %-6u]\n",
795127024Smlaier			    (unsigned long long)rule->evaluations,
796171172Smlaier			    (unsigned long long)(rule->packets[0] +
797171172Smlaier			    rule->packets[1]),
798171172Smlaier			    (unsigned long long)(rule->bytes[0] +
799223637Sbz			    rule->bytes[1]), rule->states_cur);
800171172Smlaier		if (!(opts & PF_OPT_DEBUG))
801223637Sbz			printf("  [ Inserted: uid %u pid %u "
802223637Sbz			    "State Creations: %-6u]\n",
803223637Sbz			    (unsigned)rule->cuid, (unsigned)rule->cpid,
804223637Sbz			    rule->states_tot);
805171172Smlaier	}
806126353Smlaier}
807126353Smlaier
808130617Smlaiervoid
809130617Smlaierpfctl_print_title(char *title)
810130617Smlaier{
811130617Smlaier	if (!first_title)
812130617Smlaier		printf("\n");
813130617Smlaier	first_title = 0;
814130617Smlaier	printf("%s\n", title);
815130617Smlaier}
816130617Smlaier
817126353Smlaierint
818171172Smlaierpfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
819171172Smlaier    char *anchorname, int depth)
820126353Smlaier{
821126353Smlaier	struct pfioc_rule pr;
822130617Smlaier	u_int32_t nr, mnr, header = 0;
823126353Smlaier	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
824223057Sbz	int numeric = opts & PF_OPT_NUMERIC;
825171172Smlaier	int len = strlen(path);
826171172Smlaier	int brace;
827171172Smlaier	char *p;
828126353Smlaier
829171172Smlaier	if (path[0])
830171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
831171172Smlaier	else
832171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
833171172Smlaier
834126353Smlaier	memset(&pr, 0, sizeof(pr));
835171172Smlaier	memcpy(pr.anchor, path, sizeof(pr.anchor));
836130617Smlaier	if (opts & PF_OPT_SHOWALL) {
837130617Smlaier		pr.rule.action = PF_PASS;
838130617Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
839130617Smlaier			warn("DIOCGETRULES");
840171172Smlaier			goto error;
841130617Smlaier		}
842130617Smlaier		header++;
843130617Smlaier	}
844126353Smlaier	pr.rule.action = PF_SCRUB;
845126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
846126353Smlaier		warn("DIOCGETRULES");
847171172Smlaier		goto error;
848126353Smlaier	}
849130617Smlaier	if (opts & PF_OPT_SHOWALL) {
850171172Smlaier		if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
851130617Smlaier			pfctl_print_title("FILTER RULES:");
852171172Smlaier		else if (format == PFCTL_SHOW_LABELS && labels)
853130617Smlaier			pfctl_print_title("LABEL COUNTERS:");
854130617Smlaier	}
855126353Smlaier	mnr = pr.nr;
856171172Smlaier	if (opts & PF_OPT_CLRRULECTRS)
857171172Smlaier		pr.action = PF_GET_CLR_CNTR;
858171172Smlaier
859126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
860126353Smlaier		pr.nr = nr;
861126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
862126353Smlaier			warn("DIOCGETRULE");
863171172Smlaier			goto error;
864126353Smlaier		}
865126353Smlaier
866126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
867171172Smlaier		    nr, pr.ticket, PF_SCRUB, path) != 0)
868171172Smlaier			goto error;
869126353Smlaier
870126353Smlaier		switch (format) {
871171172Smlaier		case PFCTL_SHOW_LABELS:
872126353Smlaier			break;
873171172Smlaier		case PFCTL_SHOW_RULES:
874130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
875130617Smlaier				labels = 1;
876223057Sbz			print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
877171172Smlaier			printf("\n");
878126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
879171172Smlaier			break;
880171172Smlaier		case PFCTL_SHOW_NOTHING:
881171172Smlaier			break;
882126353Smlaier		}
883126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
884126353Smlaier	}
885126353Smlaier	pr.rule.action = PF_PASS;
886126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
887126353Smlaier		warn("DIOCGETRULES");
888171172Smlaier		goto error;
889126353Smlaier	}
890126353Smlaier	mnr = pr.nr;
891126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
892126353Smlaier		pr.nr = nr;
893126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
894126353Smlaier			warn("DIOCGETRULE");
895171172Smlaier			goto error;
896126353Smlaier		}
897126353Smlaier
898126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
899171172Smlaier		    nr, pr.ticket, PF_PASS, path) != 0)
900171172Smlaier			goto error;
901126353Smlaier
902126353Smlaier		switch (format) {
903171172Smlaier		case PFCTL_SHOW_LABELS:
904126353Smlaier			if (pr.rule.label[0]) {
905223637Sbz				printf("%s %llu %llu %llu %llu"
906223637Sbz				    " %llu %llu %llu %llu\n",
907223637Sbz				    pr.rule.label,
908127024Smlaier				    (unsigned long long)pr.rule.evaluations,
909171172Smlaier				    (unsigned long long)(pr.rule.packets[0] +
910171172Smlaier				    pr.rule.packets[1]),
911171172Smlaier				    (unsigned long long)(pr.rule.bytes[0] +
912171172Smlaier				    pr.rule.bytes[1]),
913171172Smlaier				    (unsigned long long)pr.rule.packets[0],
914171172Smlaier				    (unsigned long long)pr.rule.bytes[0],
915171172Smlaier				    (unsigned long long)pr.rule.packets[1],
916223637Sbz				    (unsigned long long)pr.rule.bytes[1],
917223637Sbz				    (unsigned long long)pr.rule.states_tot);
918126353Smlaier			}
919126353Smlaier			break;
920171172Smlaier		case PFCTL_SHOW_RULES:
921171172Smlaier			brace = 0;
922130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
923130617Smlaier				labels = 1;
924171172Smlaier			INDENT(depth, !(opts & PF_OPT_VERBOSE));
925171172Smlaier			if (pr.anchor_call[0] &&
926171172Smlaier			   ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
927171172Smlaier			   ((void *)p == (void *)pr.anchor_call ||
928171172Smlaier			   *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
929171172Smlaier				brace++;
930171172Smlaier				if ((p = strrchr(pr.anchor_call, '/')) !=
931171172Smlaier				    NULL)
932171172Smlaier					p++;
933171172Smlaier				else
934171172Smlaier					p = &pr.anchor_call[0];
935171172Smlaier			} else
936171172Smlaier				p = &pr.anchor_call[0];
937171172Smlaier
938223057Sbz			print_rule(&pr.rule, p, rule_numbers, numeric);
939171172Smlaier			if (brace)
940171172Smlaier				printf(" {\n");
941171172Smlaier			else
942171172Smlaier				printf("\n");
943126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
944171172Smlaier			if (brace) {
945171172Smlaier				pfctl_show_rules(dev, path, opts, format,
946171172Smlaier				    p, depth + 1);
947171172Smlaier				INDENT(depth, !(opts & PF_OPT_VERBOSE));
948171172Smlaier				printf("}\n");
949171172Smlaier			}
950171172Smlaier			break;
951171172Smlaier		case PFCTL_SHOW_NOTHING:
952171172Smlaier			break;
953126353Smlaier		}
954126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
955126353Smlaier	}
956171172Smlaier	path[len] = '\0';
957126353Smlaier	return (0);
958171172Smlaier
959171172Smlaier error:
960171172Smlaier	path[len] = '\0';
961171172Smlaier	return (-1);
962126353Smlaier}
963126353Smlaier
964126353Smlaierint
965145840Smlaierpfctl_show_nat(int dev, int opts, char *anchorname)
966126353Smlaier{
967126353Smlaier	struct pfioc_rule pr;
968126353Smlaier	u_int32_t mnr, nr;
969126353Smlaier	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
970130617Smlaier	int i, dotitle = opts & PF_OPT_SHOWALL;
971126353Smlaier
972126353Smlaier	memset(&pr, 0, sizeof(pr));
973126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
974126353Smlaier	for (i = 0; i < 3; i++) {
975126353Smlaier		pr.rule.action = nattype[i];
976126353Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
977126353Smlaier			warn("DIOCGETRULES");
978126353Smlaier			return (-1);
979126353Smlaier		}
980126353Smlaier		mnr = pr.nr;
981126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
982126353Smlaier			pr.nr = nr;
983126353Smlaier			if (ioctl(dev, DIOCGETRULE, &pr)) {
984126353Smlaier				warn("DIOCGETRULE");
985126353Smlaier				return (-1);
986126353Smlaier			}
987126353Smlaier			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
988145840Smlaier			    pr.ticket, nattype[i], anchorname) != 0)
989126353Smlaier				return (-1);
990130617Smlaier			if (dotitle) {
991130617Smlaier				pfctl_print_title("TRANSLATION RULES:");
992130617Smlaier				dotitle = 0;
993130617Smlaier			}
994145840Smlaier			print_rule(&pr.rule, pr.anchor_call,
995223057Sbz			    opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
996171172Smlaier			printf("\n");
997126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
998126353Smlaier			pfctl_clear_pool(&pr.rule.rpool);
999126353Smlaier		}
1000126353Smlaier	}
1001126353Smlaier	return (0);
1002126353Smlaier}
1003126353Smlaier
1004126353Smlaierint
1005130617Smlaierpfctl_show_src_nodes(int dev, int opts)
1006126353Smlaier{
1007130617Smlaier	struct pfioc_src_nodes psn;
1008130617Smlaier	struct pf_src_node *p;
1009130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1010223637Sbz	unsigned int len = 0;
1011130617Smlaier	int i;
1012130617Smlaier
1013130617Smlaier	memset(&psn, 0, sizeof(psn));
1014130617Smlaier	for (;;) {
1015130617Smlaier		psn.psn_len = len;
1016130617Smlaier		if (len) {
1017130617Smlaier			newinbuf = realloc(inbuf, len);
1018130617Smlaier			if (newinbuf == NULL)
1019130617Smlaier				err(1, "realloc");
1020130617Smlaier			psn.psn_buf = inbuf = newinbuf;
1021130617Smlaier		}
1022130617Smlaier		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
1023130617Smlaier			warn("DIOCGETSRCNODES");
1024171172Smlaier			free(inbuf);
1025130617Smlaier			return (-1);
1026130617Smlaier		}
1027130617Smlaier		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
1028130617Smlaier			break;
1029130617Smlaier		if (len == 0 && psn.psn_len == 0)
1030171172Smlaier			goto done;
1031130617Smlaier		if (len == 0 && psn.psn_len != 0)
1032130617Smlaier			len = psn.psn_len;
1033130617Smlaier		if (psn.psn_len == 0)
1034171172Smlaier			goto done;	/* no src_nodes */
1035130617Smlaier		len *= 2;
1036130617Smlaier	}
1037130617Smlaier	p = psn.psn_src_nodes;
1038130617Smlaier	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
1039130617Smlaier		pfctl_print_title("SOURCE TRACKING NODES:");
1040130617Smlaier	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
1041130617Smlaier		print_src_node(p, opts);
1042130617Smlaier		p++;
1043130617Smlaier	}
1044171172Smlaierdone:
1045171172Smlaier	free(inbuf);
1046130617Smlaier	return (0);
1047130617Smlaier}
1048130617Smlaier
1049130617Smlaierint
1050130617Smlaierpfctl_show_states(int dev, const char *iface, int opts)
1051130617Smlaier{
1052126353Smlaier	struct pfioc_states ps;
1053223637Sbz	struct pfsync_state *p;
1054130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1055223637Sbz	unsigned int len = 0;
1056130617Smlaier	int i, dotitle = (opts & PF_OPT_SHOWALL);
1057126353Smlaier
1058126353Smlaier	memset(&ps, 0, sizeof(ps));
1059126353Smlaier	for (;;) {
1060126353Smlaier		ps.ps_len = len;
1061126353Smlaier		if (len) {
1062130617Smlaier			newinbuf = realloc(inbuf, len);
1063130617Smlaier			if (newinbuf == NULL)
1064126353Smlaier				err(1, "realloc");
1065130617Smlaier			ps.ps_buf = inbuf = newinbuf;
1066126353Smlaier		}
1067126353Smlaier		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
1068126353Smlaier			warn("DIOCGETSTATES");
1069171172Smlaier			free(inbuf);
1070126353Smlaier			return (-1);
1071126353Smlaier		}
1072126353Smlaier		if (ps.ps_len + sizeof(struct pfioc_states) < len)
1073126353Smlaier			break;
1074126353Smlaier		if (len == 0 && ps.ps_len == 0)
1075171172Smlaier			goto done;
1076126353Smlaier		if (len == 0 && ps.ps_len != 0)
1077126353Smlaier			len = ps.ps_len;
1078126353Smlaier		if (ps.ps_len == 0)
1079171172Smlaier			goto done;	/* no states */
1080126353Smlaier		len *= 2;
1081126353Smlaier	}
1082126353Smlaier	p = ps.ps_states;
1083130617Smlaier	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
1084223637Sbz		if (iface != NULL && strcmp(p->ifname, iface))
1085130617Smlaier			continue;
1086130617Smlaier		if (dotitle) {
1087130617Smlaier			pfctl_print_title("STATES:");
1088130617Smlaier			dotitle = 0;
1089130617Smlaier		}
1090130617Smlaier		print_state(p, opts);
1091126353Smlaier	}
1092171172Smlaierdone:
1093171172Smlaier	free(inbuf);
1094126353Smlaier	return (0);
1095126353Smlaier}
1096126353Smlaier
1097126353Smlaierint
1098130617Smlaierpfctl_show_status(int dev, int opts)
1099126353Smlaier{
1100126353Smlaier	struct pf_status status;
1101126353Smlaier
1102126353Smlaier	if (ioctl(dev, DIOCGETSTATUS, &status)) {
1103126353Smlaier		warn("DIOCGETSTATUS");
1104126353Smlaier		return (-1);
1105126353Smlaier	}
1106130617Smlaier	if (opts & PF_OPT_SHOWALL)
1107130617Smlaier		pfctl_print_title("INFO:");
1108130617Smlaier	print_status(&status, opts);
1109126353Smlaier	return (0);
1110126353Smlaier}
1111126353Smlaier
1112126353Smlaierint
1113130617Smlaierpfctl_show_timeouts(int dev, int opts)
1114126353Smlaier{
1115126353Smlaier	struct pfioc_tm pt;
1116126353Smlaier	int i;
1117126353Smlaier
1118130617Smlaier	if (opts & PF_OPT_SHOWALL)
1119130617Smlaier		pfctl_print_title("TIMEOUTS:");
1120126353Smlaier	memset(&pt, 0, sizeof(pt));
1121126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1122126353Smlaier		pt.timeout = pf_timeouts[i].timeout;
1123126353Smlaier		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
1124126353Smlaier			err(1, "DIOCGETTIMEOUT");
1125126353Smlaier		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
1126145840Smlaier		if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1127145840Smlaier		    pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1128126353Smlaier			printf(" states");
1129126353Smlaier		else
1130126353Smlaier			printf("s");
1131126353Smlaier		printf("\n");
1132126353Smlaier	}
1133126353Smlaier	return (0);
1134126353Smlaier
1135126353Smlaier}
1136126353Smlaier
1137126353Smlaierint
1138130617Smlaierpfctl_show_limits(int dev, int opts)
1139126353Smlaier{
1140126353Smlaier	struct pfioc_limit pl;
1141126353Smlaier	int i;
1142126353Smlaier
1143130617Smlaier	if (opts & PF_OPT_SHOWALL)
1144130617Smlaier		pfctl_print_title("LIMITS:");
1145126353Smlaier	memset(&pl, 0, sizeof(pl));
1146126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1147130617Smlaier		pl.index = pf_limits[i].index;
1148126353Smlaier		if (ioctl(dev, DIOCGETLIMIT, &pl))
1149126353Smlaier			err(1, "DIOCGETLIMIT");
1150171172Smlaier		printf("%-13s ", pf_limits[i].name);
1151126353Smlaier		if (pl.limit == UINT_MAX)
1152126353Smlaier			printf("unlimited\n");
1153126353Smlaier		else
1154171172Smlaier			printf("hard limit %8u\n", pl.limit);
1155126353Smlaier	}
1156126353Smlaier	return (0);
1157126353Smlaier}
1158126353Smlaier
1159126353Smlaier/* callbacks for rule/nat/rdr/addr */
1160126353Smlaierint
1161126353Smlaierpfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
1162126353Smlaier{
1163126353Smlaier	struct pf_pooladdr *pa;
1164126353Smlaier
1165126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1166126353Smlaier		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
1167126353Smlaier			err(1, "DIOCBEGINADDRS");
1168126353Smlaier	}
1169126353Smlaier
1170126353Smlaier	pf->paddr.af = af;
1171126353Smlaier	TAILQ_FOREACH(pa, &p->list, entries) {
1172126353Smlaier		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
1173126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1174126353Smlaier			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
1175126353Smlaier				err(1, "DIOCADDADDR");
1176126353Smlaier		}
1177126353Smlaier	}
1178126353Smlaier	return (0);
1179126353Smlaier}
1180126353Smlaier
1181126353Smlaierint
1182145840Smlaierpfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
1183126353Smlaier{
1184130617Smlaier	u_int8_t		rs_num;
1185171172Smlaier	struct pf_rule		*rule;
1186171172Smlaier	struct pf_ruleset	*rs;
1187171172Smlaier	char 			*p;
1188126353Smlaier
1189171172Smlaier	rs_num = pf_get_ruleset_number(r->action);
1190171172Smlaier	if (rs_num == PF_RULESET_MAX)
1191145840Smlaier		errx(1, "Invalid rule type %d", r->action);
1192126353Smlaier
1193171172Smlaier	rs = &pf->anchor->ruleset;
1194145840Smlaier
1195171172Smlaier	if (anchor_call[0] && r->anchor == NULL) {
1196171172Smlaier		/*
1197171172Smlaier		 * Don't make non-brace anchors part of the main anchor pool.
1198145840Smlaier		 */
1199171172Smlaier		if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1200171172Smlaier			err(1, "pfctl_add_rule: calloc");
1201171172Smlaier
1202171172Smlaier		pf_init_ruleset(&r->anchor->ruleset);
1203171172Smlaier		r->anchor->ruleset.anchor = r->anchor;
1204171172Smlaier		if (strlcpy(r->anchor->path, anchor_call,
1205171172Smlaier		    sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1206223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1207171172Smlaier		if ((p = strrchr(anchor_call, '/')) != NULL) {
1208171172Smlaier			if (!strlen(p))
1209171172Smlaier				err(1, "pfctl_add_rule: bad anchor name %s",
1210171172Smlaier				    anchor_call);
1211171172Smlaier		} else
1212171172Smlaier			p = (char *)anchor_call;
1213171172Smlaier		if (strlcpy(r->anchor->name, p,
1214171172Smlaier		    sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1215223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1216171172Smlaier	}
1217145840Smlaier
1218171172Smlaier	if ((rule = calloc(1, sizeof(*rule))) == NULL)
1219171172Smlaier		err(1, "calloc");
1220171172Smlaier	bcopy(r, rule, sizeof(*rule));
1221171172Smlaier	TAILQ_INIT(&rule->rpool.list);
1222171172Smlaier	pfctl_move_pool(&r->rpool, &rule->rpool);
1223145840Smlaier
1224171172Smlaier	TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1225171172Smlaier	return (0);
1226171172Smlaier}
1227171172Smlaier
1228171172Smlaierint
1229171172Smlaierpfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
1230171172Smlaier{
1231171172Smlaier	int osize = pf->trans->pfrb_size;
1232171172Smlaier
1233171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1234171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1235171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1236171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1237171172Smlaier			return (1);
1238171172Smlaier	}
1239171172Smlaier	if (a == pf->astack[0] && ((altqsupport &&
1240223637Sbz	    (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1241171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1242171172Smlaier			return (2);
1243171172Smlaier	}
1244171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1245171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1246171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1247171172Smlaier			return (3);
1248171172Smlaier	}
1249171172Smlaier	if (pf->loadopt & PFCTL_FLAG_TABLE)
1250171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1251171172Smlaier			return (4);
1252171172Smlaier	if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1253171172Smlaier		return (5);
1254171172Smlaier
1255171172Smlaier	return (0);
1256171172Smlaier}
1257171172Smlaier
1258171172Smlaierint
1259171172Smlaierpfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
1260171172Smlaier    int rs_num, int depth)
1261171172Smlaier{
1262171172Smlaier	struct pf_rule *r;
1263171172Smlaier	int		error, len = strlen(path);
1264171172Smlaier	int		brace = 0;
1265171172Smlaier
1266171172Smlaier	pf->anchor = rs->anchor;
1267171172Smlaier
1268171172Smlaier	if (path[0])
1269171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
1270171172Smlaier	else
1271171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
1272171172Smlaier
1273171172Smlaier	if (depth) {
1274171172Smlaier		if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
1275171172Smlaier			brace++;
1276171172Smlaier			if (pf->opts & PF_OPT_VERBOSE)
1277171172Smlaier				printf(" {\n");
1278171172Smlaier			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1279171172Smlaier			    (error = pfctl_ruleset_trans(pf,
1280171172Smlaier			    path, rs->anchor))) {
1281171172Smlaier				printf("pfctl_load_rulesets: "
1282171172Smlaier				    "pfctl_ruleset_trans %d\n", error);
1283171172Smlaier				goto error;
1284145840Smlaier			}
1285171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1286171172Smlaier			printf("\n");
1287145840Smlaier
1288145840Smlaier	}
1289145840Smlaier
1290171172Smlaier	if (pf->optimize && rs_num == PF_RULESET_FILTER)
1291171172Smlaier		pfctl_optimize_ruleset(pf, rs);
1292171172Smlaier
1293171172Smlaier	while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
1294171172Smlaier		TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
1295171172Smlaier		if ((error = pfctl_load_rule(pf, path, r, depth)))
1296171172Smlaier			goto error;
1297171172Smlaier		if (r->anchor) {
1298171172Smlaier			if ((error = pfctl_load_ruleset(pf, path,
1299171172Smlaier			    &r->anchor->ruleset, rs_num, depth + 1)))
1300171172Smlaier				goto error;
1301171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1302171172Smlaier			printf("\n");
1303171172Smlaier		free(r);
1304171172Smlaier	}
1305171172Smlaier	if (brace && pf->opts & PF_OPT_VERBOSE) {
1306171172Smlaier		INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
1307171172Smlaier		printf("}\n");
1308171172Smlaier	}
1309171172Smlaier	path[len] = '\0';
1310171172Smlaier	return (0);
1311171172Smlaier
1312171172Smlaier error:
1313171172Smlaier	path[len] = '\0';
1314171172Smlaier	return (error);
1315171172Smlaier
1316171172Smlaier}
1317171172Smlaier
1318171172Smlaierint
1319171172Smlaierpfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
1320171172Smlaier{
1321171172Smlaier	u_int8_t		rs_num = pf_get_ruleset_number(r->action);
1322171172Smlaier	char			*name;
1323171172Smlaier	struct pfioc_rule	pr;
1324171172Smlaier	int			len = strlen(path);
1325171172Smlaier
1326171172Smlaier	bzero(&pr, sizeof(pr));
1327171172Smlaier	/* set up anchor before adding to path for anchor_call */
1328171172Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1329171172Smlaier		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
1330171172Smlaier	if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
1331171172Smlaier		errx(1, "pfctl_load_rule: strlcpy");
1332171172Smlaier
1333171172Smlaier	if (r->anchor) {
1334171172Smlaier		if (r->anchor->match) {
1335171172Smlaier			if (path[0])
1336171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1337171172Smlaier				    "/%s", r->anchor->name);
1338171172Smlaier			else
1339171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1340171172Smlaier				    "%s", r->anchor->name);
1341171172Smlaier			name = path;
1342171172Smlaier		} else
1343171172Smlaier			name = r->anchor->path;
1344171172Smlaier	} else
1345171172Smlaier		name = "";
1346171172Smlaier
1347126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1348126353Smlaier		if (pfctl_add_pool(pf, &r->rpool, r->af))
1349126353Smlaier			return (1);
1350130617Smlaier		pr.pool_ticket = pf->paddr.ticket;
1351130617Smlaier		memcpy(&pr.rule, r, sizeof(pr.rule));
1352171172Smlaier		if (r->anchor && strlcpy(pr.anchor_call, name,
1353171172Smlaier		    sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
1354171172Smlaier			errx(1, "pfctl_load_rule: strlcpy");
1355130617Smlaier		if (ioctl(pf->dev, DIOCADDRULE, &pr))
1356126353Smlaier			err(1, "DIOCADDRULE");
1357126353Smlaier	}
1358171172Smlaier
1359171172Smlaier	if (pf->opts & PF_OPT_VERBOSE) {
1360171172Smlaier		INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
1361171172Smlaier		print_rule(r, r->anchor ? r->anchor->name : "",
1362223057Sbz		    pf->opts & PF_OPT_VERBOSE2,
1363223057Sbz		    pf->opts & PF_OPT_NUMERIC);
1364171172Smlaier	}
1365171172Smlaier	path[len] = '\0';
1366126353Smlaier	pfctl_clear_pool(&r->rpool);
1367126353Smlaier	return (0);
1368126353Smlaier}
1369126353Smlaier
1370126353Smlaierint
1371126353Smlaierpfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1372126353Smlaier{
1373126353Smlaier	if (altqsupport &&
1374126353Smlaier	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1375126353Smlaier		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1376126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1377126353Smlaier			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1378126353Smlaier				if (errno == ENXIO)
1379126353Smlaier					errx(1, "qtype not configured");
1380126353Smlaier				else if (errno == ENODEV)
1381126353Smlaier					errx(1, "%s: driver does not support "
1382126353Smlaier					    "altq", a->ifname);
1383126353Smlaier				else
1384126353Smlaier					err(1, "DIOCADDALTQ");
1385126353Smlaier			}
1386126353Smlaier		}
1387126353Smlaier		pfaltq_store(&pf->paltq->altq);
1388126353Smlaier	}
1389126353Smlaier	return (0);
1390126353Smlaier}
1391126353Smlaier
1392126353Smlaierint
1393223637Sbzpfctl_rules(int dev, char *filename, int opts, int optimize,
1394171172Smlaier    char *anchorname, struct pfr_buffer *trans)
1395126353Smlaier{
1396126353Smlaier#define ERR(x) do { warn(x); goto _error; } while(0)
1397126353Smlaier#define ERRX(x) do { warnx(x); goto _error; } while(0)
1398126353Smlaier
1399130617Smlaier	struct pfr_buffer	*t, buf;
1400130617Smlaier	struct pfioc_altq	 pa;
1401130617Smlaier	struct pfctl		 pf;
1402171172Smlaier	struct pf_ruleset	*rs;
1403130617Smlaier	struct pfr_table	 trs;
1404171172Smlaier	char			*path;
1405130617Smlaier	int			 osize;
1406126353Smlaier
1407171172Smlaier	RB_INIT(&pf_anchors);
1408171172Smlaier	memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
1409171172Smlaier	pf_init_ruleset(&pf_main_anchor.ruleset);
1410171172Smlaier	pf_main_anchor.ruleset.anchor = &pf_main_anchor;
1411130617Smlaier	if (trans == NULL) {
1412171172Smlaier		bzero(&buf, sizeof(buf));
1413171172Smlaier		buf.pfrb_type = PFRB_TRANS;
1414171172Smlaier		t = &buf;
1415171172Smlaier		osize = 0;
1416130617Smlaier	} else {
1417171172Smlaier		t = trans;
1418171172Smlaier		osize = t->pfrb_size;
1419130617Smlaier	}
1420130617Smlaier
1421126353Smlaier	memset(&pa, 0, sizeof(pa));
1422126353Smlaier	memset(&pf, 0, sizeof(pf));
1423126353Smlaier	memset(&trs, 0, sizeof(trs));
1424171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
1425171172Smlaier		ERRX("pfctl_rules: calloc");
1426126353Smlaier	if (strlcpy(trs.pfrt_anchor, anchorname,
1427145840Smlaier	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1428126353Smlaier		ERRX("pfctl_rules: strlcpy");
1429126353Smlaier	pf.dev = dev;
1430126353Smlaier	pf.opts = opts;
1431171172Smlaier	pf.optimize = optimize;
1432126353Smlaier	pf.loadopt = loadopt;
1433171172Smlaier
1434171172Smlaier	/* non-brace anchor, create without resolving the path */
1435171172Smlaier	if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
1436171172Smlaier		ERRX("pfctl_rules: calloc");
1437171172Smlaier	rs = &pf.anchor->ruleset;
1438171172Smlaier	pf_init_ruleset(rs);
1439171172Smlaier	rs->anchor = pf.anchor;
1440171172Smlaier	if (strlcpy(pf.anchor->path, anchorname,
1441171172Smlaier	    sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
1442171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1443171172Smlaier	if (strlcpy(pf.anchor->name, anchorname,
1444171172Smlaier	    sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
1445171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1446171172Smlaier
1447171172Smlaier
1448171172Smlaier	pf.astack[0] = pf.anchor;
1449171172Smlaier	pf.asd = 0;
1450130617Smlaier	if (anchorname[0])
1451130617Smlaier		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1452126353Smlaier	pf.paltq = &pa;
1453130617Smlaier	pf.trans = t;
1454145840Smlaier	pfctl_init_options(&pf);
1455130617Smlaier
1456130617Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
1457171172Smlaier		/*
1458171172Smlaier		 * XXX For the time being we need to open transactions for
1459171172Smlaier		 * the main ruleset before parsing, because tables are still
1460171172Smlaier		 * loaded at parse time.
1461171172Smlaier		 */
1462171172Smlaier		if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
1463171172Smlaier			ERRX("pfctl_rules");
1464130617Smlaier		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1465171172Smlaier			pa.ticket =
1466171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
1467130617Smlaier		if (pf.loadopt & PFCTL_FLAG_TABLE)
1468171172Smlaier			pf.astack[0]->ruleset.tticket =
1469171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
1470130617Smlaier	}
1471171172Smlaier
1472223637Sbz	if (parse_config(filename, &pf) < 0) {
1473126353Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1474126353Smlaier			ERRX("Syntax error in config file: "
1475126353Smlaier			    "pf rules not loaded");
1476126353Smlaier		else
1477126353Smlaier			goto _error;
1478126353Smlaier	}
1479171172Smlaier
1480171172Smlaier	if ((pf.loadopt & PFCTL_FLAG_FILTER &&
1481171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
1482171172Smlaier	    (pf.loadopt & PFCTL_FLAG_NAT &&
1483171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
1484171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
1485171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
1486171172Smlaier	    (pf.loadopt & PFCTL_FLAG_FILTER &&
1487171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
1488171172Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1489171172Smlaier			ERRX("Unable to load rules into kernel");
1490171172Smlaier		else
1491171172Smlaier			goto _error;
1492145840Smlaier	}
1493145840Smlaier
1494130617Smlaier	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1495126353Smlaier		if (check_commit_altq(dev, opts) != 0)
1496126353Smlaier			ERRX("errors in altq config");
1497145840Smlaier
1498126353Smlaier	/* process "load anchor" directives */
1499145840Smlaier	if (!anchorname[0])
1500171172Smlaier		if (pfctl_load_anchors(dev, &pf, t) == -1)
1501126353Smlaier			ERRX("load anchors");
1502126353Smlaier
1503145840Smlaier	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1504145840Smlaier		if (!anchorname[0])
1505145840Smlaier			if (pfctl_load_options(&pf))
1506145840Smlaier				goto _error;
1507171172Smlaier		if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
1508130617Smlaier			ERR("DIOCXCOMMIT");
1509145840Smlaier	}
1510126353Smlaier	return (0);
1511126353Smlaier
1512126353Smlaier_error:
1513130617Smlaier	if (trans == NULL) {	/* main ruleset */
1514130617Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1515171172Smlaier			if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
1516130617Smlaier				err(1, "DIOCXROLLBACK");
1517130617Smlaier		exit(1);
1518145840Smlaier	} else {		/* sub ruleset */
1519130617Smlaier		return (-1);
1520145840Smlaier	}
1521126353Smlaier
1522126353Smlaier#undef ERR
1523126353Smlaier#undef ERRX
1524126353Smlaier}
1525126353Smlaier
1526145840SmlaierFILE *
1527145840Smlaierpfctl_fopen(const char *name, const char *mode)
1528145840Smlaier{
1529145840Smlaier	struct stat	 st;
1530145840Smlaier	FILE		*fp;
1531145840Smlaier
1532145840Smlaier	fp = fopen(name, mode);
1533145840Smlaier	if (fp == NULL)
1534145840Smlaier		return (NULL);
1535145840Smlaier	if (fstat(fileno(fp), &st)) {
1536145840Smlaier		fclose(fp);
1537145840Smlaier		return (NULL);
1538145840Smlaier	}
1539145840Smlaier	if (S_ISDIR(st.st_mode)) {
1540145840Smlaier		fclose(fp);
1541145840Smlaier		errno = EISDIR;
1542145840Smlaier		return (NULL);
1543145840Smlaier	}
1544145840Smlaier	return (fp);
1545145840Smlaier}
1546145840Smlaier
1547145840Smlaiervoid
1548145840Smlaierpfctl_init_options(struct pfctl *pf)
1549145840Smlaier{
1550171172Smlaier
1551145840Smlaier	pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1552145840Smlaier	pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1553145840Smlaier	pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1554145840Smlaier	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1555145840Smlaier	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1556145840Smlaier	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1557145840Smlaier	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1558145840Smlaier	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1559145840Smlaier	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1560145840Smlaier	pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1561145840Smlaier	pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1562145840Smlaier	pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1563145840Smlaier	pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1564145840Smlaier	pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1565145840Smlaier	pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1566145840Smlaier	pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1567145840Smlaier	pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1568145840Smlaier	pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1569171172Smlaier	pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
1570171172Smlaier	pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
1571145840Smlaier
1572171172Smlaier	pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
1573171172Smlaier	pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
1574171172Smlaier	pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
1575171172Smlaier	pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
1576145840Smlaier
1577145840Smlaier	pf->debug = PF_DEBUG_URGENT;
1578145840Smlaier}
1579145840Smlaier
1580126353Smlaierint
1581145840Smlaierpfctl_load_options(struct pfctl *pf)
1582126353Smlaier{
1583145840Smlaier	int i, error = 0;
1584126353Smlaier
1585126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1586126353Smlaier		return (0);
1587126353Smlaier
1588145840Smlaier	/* load limits */
1589145840Smlaier	for (i = 0; i < PF_LIMIT_MAX; i++) {
1590145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1591145840Smlaier			continue;
1592145840Smlaier		if (pfctl_load_limit(pf, i, pf->limit[i]))
1593145840Smlaier			error = 1;
1594145840Smlaier	}
1595145840Smlaier
1596171172Smlaier	/*
1597223637Sbz	 * If we've set the limit, but haven't explicitly set adaptive
1598171172Smlaier	 * timeouts, do it now with a start of 60% and end of 120%.
1599171172Smlaier	 */
1600171172Smlaier	if (pf->limit_set[PF_LIMIT_STATES] &&
1601171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_START] &&
1602171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_END]) {
1603171172Smlaier		pf->timeout[PFTM_ADAPTIVE_START] =
1604171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 6;
1605171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
1606171172Smlaier		pf->timeout[PFTM_ADAPTIVE_END] =
1607171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 12;
1608171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
1609171172Smlaier	}
1610171172Smlaier
1611145840Smlaier	/* load timeouts */
1612145840Smlaier	for (i = 0; i < PFTM_MAX; i++) {
1613145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1614145840Smlaier			continue;
1615145840Smlaier		if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1616145840Smlaier			error = 1;
1617145840Smlaier	}
1618145840Smlaier
1619145840Smlaier	/* load debug */
1620145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1621145840Smlaier		if (pfctl_load_debug(pf, pf->debug))
1622145840Smlaier			error = 1;
1623145840Smlaier
1624145840Smlaier	/* load logif */
1625145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1626145840Smlaier		if (pfctl_load_logif(pf, pf->ifname))
1627145840Smlaier			error = 1;
1628145840Smlaier
1629145840Smlaier	/* load hostid */
1630145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1631145840Smlaier		if (pfctl_load_hostid(pf, pf->hostid))
1632145840Smlaier			error = 1;
1633145840Smlaier
1634145840Smlaier	return (error);
1635145840Smlaier}
1636145840Smlaier
1637145840Smlaierint
1638145840Smlaierpfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1639145840Smlaier{
1640145840Smlaier	int i;
1641145840Smlaier
1642145840Smlaier
1643126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1644126353Smlaier		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1645145840Smlaier			pf->limit[pf_limits[i].index] = limit;
1646145840Smlaier			pf->limit_set[pf_limits[i].index] = 1;
1647126353Smlaier			break;
1648126353Smlaier		}
1649126353Smlaier	}
1650126353Smlaier	if (pf_limits[i].name == NULL) {
1651126353Smlaier		warnx("Bad pool name.");
1652126353Smlaier		return (1);
1653126353Smlaier	}
1654126353Smlaier
1655126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1656126353Smlaier		printf("set limit %s %d\n", opt, limit);
1657126353Smlaier
1658126353Smlaier	return (0);
1659126353Smlaier}
1660126353Smlaier
1661126353Smlaierint
1662145840Smlaierpfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1663145840Smlaier{
1664145840Smlaier	struct pfioc_limit pl;
1665145840Smlaier
1666145840Smlaier	memset(&pl, 0, sizeof(pl));
1667145840Smlaier	pl.index = index;
1668145840Smlaier	pl.limit = limit;
1669145840Smlaier	if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1670145840Smlaier		if (errno == EBUSY)
1671145840Smlaier			warnx("Current pool size exceeds requested hard limit");
1672145840Smlaier		else
1673145840Smlaier			warnx("DIOCSETLIMIT");
1674145840Smlaier		return (1);
1675145840Smlaier	}
1676145840Smlaier	return (0);
1677145840Smlaier}
1678145840Smlaier
1679145840Smlaierint
1680126353Smlaierpfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1681126353Smlaier{
1682126353Smlaier	int i;
1683126353Smlaier
1684126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1685126353Smlaier		return (0);
1686126353Smlaier
1687126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1688126353Smlaier		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1689145840Smlaier			pf->timeout[pf_timeouts[i].timeout] = seconds;
1690145840Smlaier			pf->timeout_set[pf_timeouts[i].timeout] = 1;
1691126353Smlaier			break;
1692126353Smlaier		}
1693126353Smlaier	}
1694126353Smlaier
1695126353Smlaier	if (pf_timeouts[i].name == NULL) {
1696126353Smlaier		warnx("Bad timeout name.");
1697126353Smlaier		return (1);
1698126353Smlaier	}
1699126353Smlaier
1700126353Smlaier
1701126353Smlaier	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1702126353Smlaier		printf("set timeout %s %d\n", opt, seconds);
1703126353Smlaier
1704126353Smlaier	return (0);
1705126353Smlaier}
1706126353Smlaier
1707126353Smlaierint
1708145840Smlaierpfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1709145840Smlaier{
1710145840Smlaier	struct pfioc_tm pt;
1711145840Smlaier
1712145840Smlaier	memset(&pt, 0, sizeof(pt));
1713145840Smlaier	pt.timeout = timeout;
1714145840Smlaier	pt.seconds = seconds;
1715145840Smlaier	if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1716145840Smlaier		warnx("DIOCSETTIMEOUT");
1717145840Smlaier		return (1);
1718145840Smlaier	}
1719145840Smlaier	return (0);
1720145840Smlaier}
1721145840Smlaier
1722145840Smlaierint
1723126353Smlaierpfctl_set_optimization(struct pfctl *pf, const char *opt)
1724126353Smlaier{
1725126353Smlaier	const struct pf_hint *hint;
1726126353Smlaier	int i, r;
1727126353Smlaier
1728126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1729126353Smlaier		return (0);
1730126353Smlaier
1731126353Smlaier	for (i = 0; pf_hints[i].name; i++)
1732126353Smlaier		if (strcasecmp(opt, pf_hints[i].name) == 0)
1733126353Smlaier			break;
1734126353Smlaier
1735126353Smlaier	hint = pf_hints[i].hint;
1736126353Smlaier	if (hint == NULL) {
1737171172Smlaier		warnx("invalid state timeouts optimization");
1738126353Smlaier		return (1);
1739126353Smlaier	}
1740126353Smlaier
1741126353Smlaier	for (i = 0; hint[i].name; i++)
1742126353Smlaier		if ((r = pfctl_set_timeout(pf, hint[i].name,
1743126353Smlaier		    hint[i].timeout, 1)))
1744126353Smlaier			return (r);
1745126353Smlaier
1746126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1747126353Smlaier		printf("set optimization %s\n", opt);
1748126353Smlaier
1749126353Smlaier	return (0);
1750126353Smlaier}
1751126353Smlaier
1752126353Smlaierint
1753126353Smlaierpfctl_set_logif(struct pfctl *pf, char *ifname)
1754126353Smlaier{
1755126353Smlaier
1756126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1757126353Smlaier		return (0);
1758126353Smlaier
1759145840Smlaier	if (!strcmp(ifname, "none")) {
1760145840Smlaier		free(pf->ifname);
1761145840Smlaier		pf->ifname = NULL;
1762145840Smlaier	} else {
1763145840Smlaier		pf->ifname = strdup(ifname);
1764145840Smlaier		if (!pf->ifname)
1765145840Smlaier			errx(1, "pfctl_set_logif: strdup");
1766126353Smlaier	}
1767145840Smlaier	pf->ifname_set = 1;
1768126353Smlaier
1769126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1770126353Smlaier		printf("set loginterface %s\n", ifname);
1771126353Smlaier
1772126353Smlaier	return (0);
1773126353Smlaier}
1774126353Smlaier
1775126353Smlaierint
1776145840Smlaierpfctl_load_logif(struct pfctl *pf, char *ifname)
1777145840Smlaier{
1778145840Smlaier	struct pfioc_if pi;
1779145840Smlaier
1780145840Smlaier	memset(&pi, 0, sizeof(pi));
1781145840Smlaier	if (ifname && strlcpy(pi.ifname, ifname,
1782145840Smlaier	    sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1783171172Smlaier		warnx("pfctl_load_logif: strlcpy");
1784145840Smlaier		return (1);
1785145840Smlaier	}
1786145840Smlaier	if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1787145840Smlaier		warnx("DIOCSETSTATUSIF");
1788145840Smlaier		return (1);
1789145840Smlaier	}
1790145840Smlaier	return (0);
1791145840Smlaier}
1792145840Smlaier
1793145840Smlaierint
1794130617Smlaierpfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1795130617Smlaier{
1796130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1797130617Smlaier		return (0);
1798130617Smlaier
1799130617Smlaier	HTONL(hostid);
1800130617Smlaier
1801145840Smlaier	pf->hostid = hostid;
1802145840Smlaier	pf->hostid_set = 1;
1803130617Smlaier
1804130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1805130617Smlaier		printf("set hostid 0x%08x\n", ntohl(hostid));
1806130617Smlaier
1807130617Smlaier	return (0);
1808130617Smlaier}
1809130617Smlaier
1810130617Smlaierint
1811145840Smlaierpfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1812145840Smlaier{
1813145840Smlaier	if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1814145840Smlaier		warnx("DIOCSETHOSTID");
1815145840Smlaier		return (1);
1816145840Smlaier	}
1817145840Smlaier	return (0);
1818145840Smlaier}
1819145840Smlaier
1820145840Smlaierint
1821130617Smlaierpfctl_set_debug(struct pfctl *pf, char *d)
1822130617Smlaier{
1823130617Smlaier	u_int32_t	level;
1824130617Smlaier
1825130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1826130617Smlaier		return (0);
1827130617Smlaier
1828130617Smlaier	if (!strcmp(d, "none"))
1829145840Smlaier		pf->debug = PF_DEBUG_NONE;
1830130617Smlaier	else if (!strcmp(d, "urgent"))
1831145840Smlaier		pf->debug = PF_DEBUG_URGENT;
1832130617Smlaier	else if (!strcmp(d, "misc"))
1833145840Smlaier		pf->debug = PF_DEBUG_MISC;
1834130617Smlaier	else if (!strcmp(d, "loud"))
1835145840Smlaier		pf->debug = PF_DEBUG_NOISY;
1836130617Smlaier	else {
1837130617Smlaier		warnx("unknown debug level \"%s\"", d);
1838130617Smlaier		return (-1);
1839130617Smlaier	}
1840130617Smlaier
1841145840Smlaier	pf->debug_set = 1;
1842145840Smlaier
1843130617Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1844130617Smlaier		if (ioctl(dev, DIOCSETDEBUG, &level))
1845130617Smlaier			err(1, "DIOCSETDEBUG");
1846130617Smlaier
1847130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1848130617Smlaier		printf("set debug %s\n", d);
1849130617Smlaier
1850130617Smlaier	return (0);
1851130617Smlaier}
1852130617Smlaier
1853130617Smlaierint
1854145840Smlaierpfctl_load_debug(struct pfctl *pf, unsigned int level)
1855145840Smlaier{
1856145840Smlaier	if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1857145840Smlaier		warnx("DIOCSETDEBUG");
1858145840Smlaier		return (1);
1859145840Smlaier	}
1860145840Smlaier	return (0);
1861145840Smlaier}
1862145840Smlaier
1863145840Smlaierint
1864145840Smlaierpfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1865145840Smlaier{
1866145840Smlaier	struct pfioc_iface	pi;
1867145840Smlaier
1868145840Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1869145840Smlaier		return (0);
1870145840Smlaier
1871145840Smlaier	bzero(&pi, sizeof(pi));
1872145840Smlaier
1873145840Smlaier	pi.pfiio_flags = flags;
1874145840Smlaier
1875145840Smlaier	if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
1876145840Smlaier	    sizeof(pi.pfiio_name))
1877145840Smlaier		errx(1, "pfctl_set_interface_flags: strlcpy");
1878145840Smlaier
1879145840Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1880145840Smlaier		if (how == 0) {
1881145840Smlaier			if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
1882145840Smlaier				err(1, "DIOCCLRIFFLAG");
1883145840Smlaier		} else {
1884145840Smlaier			if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
1885145840Smlaier				err(1, "DIOCSETIFFLAG");
1886145840Smlaier		}
1887145840Smlaier	}
1888145840Smlaier	return (0);
1889145840Smlaier}
1890145840Smlaier
1891145840Smlaiervoid
1892126353Smlaierpfctl_debug(int dev, u_int32_t level, int opts)
1893126353Smlaier{
1894126353Smlaier	if (ioctl(dev, DIOCSETDEBUG, &level))
1895126353Smlaier		err(1, "DIOCSETDEBUG");
1896126353Smlaier	if ((opts & PF_OPT_QUIET) == 0) {
1897126353Smlaier		fprintf(stderr, "debug level set to '");
1898126353Smlaier		switch (level) {
1899126353Smlaier		case PF_DEBUG_NONE:
1900126353Smlaier			fprintf(stderr, "none");
1901126353Smlaier			break;
1902126353Smlaier		case PF_DEBUG_URGENT:
1903126353Smlaier			fprintf(stderr, "urgent");
1904126353Smlaier			break;
1905126353Smlaier		case PF_DEBUG_MISC:
1906126353Smlaier			fprintf(stderr, "misc");
1907126353Smlaier			break;
1908126353Smlaier		case PF_DEBUG_NOISY:
1909126353Smlaier			fprintf(stderr, "loud");
1910126353Smlaier			break;
1911126353Smlaier		default:
1912126353Smlaier			fprintf(stderr, "<invalid>");
1913126353Smlaier			break;
1914126353Smlaier		}
1915126353Smlaier		fprintf(stderr, "'\n");
1916126353Smlaier	}
1917126353Smlaier}
1918126353Smlaier
1919126353Smlaierint
1920126353Smlaierpfctl_test_altqsupport(int dev, int opts)
1921126353Smlaier{
1922126353Smlaier	struct pfioc_altq pa;
1923126353Smlaier
1924126353Smlaier	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1925126353Smlaier		if (errno == ENODEV) {
1926126353Smlaier			if (!(opts & PF_OPT_QUIET))
1927126353Smlaier				fprintf(stderr, "No ALTQ support in kernel\n"
1928126353Smlaier				    "ALTQ related functions disabled\n");
1929126353Smlaier			return (0);
1930126353Smlaier		} else
1931126353Smlaier			err(1, "DIOCGETALTQS");
1932126353Smlaier	}
1933126353Smlaier	return (1);
1934126353Smlaier}
1935126353Smlaier
1936126353Smlaierint
1937126353Smlaierpfctl_show_anchors(int dev, int opts, char *anchorname)
1938126353Smlaier{
1939145840Smlaier	struct pfioc_ruleset	 pr;
1940145840Smlaier	u_int32_t		 mnr, nr;
1941126353Smlaier
1942145840Smlaier	memset(&pr, 0, sizeof(pr));
1943145840Smlaier	memcpy(pr.path, anchorname, sizeof(pr.path));
1944145840Smlaier	if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1945145840Smlaier		if (errno == EINVAL)
1946145840Smlaier			fprintf(stderr, "Anchor '%s' not found.\n",
1947145840Smlaier			    anchorname);
1948145840Smlaier		else
1949145840Smlaier			err(1, "DIOCGETRULESETS");
1950145840Smlaier		return (-1);
1951145840Smlaier	}
1952145840Smlaier	mnr = pr.nr;
1953145840Smlaier	for (nr = 0; nr < mnr; ++nr) {
1954145840Smlaier		char sub[MAXPATHLEN];
1955126353Smlaier
1956145840Smlaier		pr.nr = nr;
1957145840Smlaier		if (ioctl(dev, DIOCGETRULESET, &pr))
1958145840Smlaier			err(1, "DIOCGETRULESET");
1959145840Smlaier		if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
1960145840Smlaier			continue;
1961145840Smlaier		sub[0] = 0;
1962145840Smlaier		if (pr.path[0]) {
1963145840Smlaier			strlcat(sub, pr.path, sizeof(sub));
1964145840Smlaier			strlcat(sub, "/", sizeof(sub));
1965126353Smlaier		}
1966145840Smlaier		strlcat(sub, pr.name, sizeof(sub));
1967171172Smlaier		if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
1968171172Smlaier			printf("  %s\n", sub);
1969171172Smlaier		if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
1970126353Smlaier			return (-1);
1971126353Smlaier	}
1972126353Smlaier	return (0);
1973126353Smlaier}
1974126353Smlaier
1975126353Smlaierconst char *
1976126353Smlaierpfctl_lookup_option(char *cmd, const char **list)
1977126353Smlaier{
1978126353Smlaier	if (cmd != NULL && *cmd)
1979126353Smlaier		for (; *list; list++)
1980126353Smlaier			if (!strncmp(cmd, *list, strlen(cmd)))
1981126353Smlaier				return (*list);
1982126353Smlaier	return (NULL);
1983126353Smlaier}
1984126353Smlaier
1985126353Smlaierint
1986126353Smlaiermain(int argc, char *argv[])
1987126353Smlaier{
1988171172Smlaier	int	 error = 0;
1989171172Smlaier	int	 ch;
1990171172Smlaier	int	 mode = O_RDONLY;
1991171172Smlaier	int	 opts = 0;
1992223637Sbz	int	 optimize = PF_OPTIMIZE_BASIC;
1993171172Smlaier	char	 anchorname[MAXPATHLEN];
1994171172Smlaier	char	*path;
1995126353Smlaier
1996126353Smlaier	if (argc < 2)
1997126353Smlaier		usage();
1998126353Smlaier
1999130617Smlaier	while ((ch = getopt(argc, argv,
2000223637Sbz	    "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
2001126353Smlaier		switch (ch) {
2002126353Smlaier		case 'a':
2003126353Smlaier			anchoropt = optarg;
2004126353Smlaier			break;
2005126353Smlaier		case 'd':
2006126353Smlaier			opts |= PF_OPT_DISABLE;
2007126353Smlaier			mode = O_RDWR;
2008126353Smlaier			break;
2009126353Smlaier		case 'D':
2010126353Smlaier			if (pfctl_cmdline_symset(optarg) < 0)
2011126353Smlaier				warnx("could not parse macro definition %s",
2012126353Smlaier				    optarg);
2013126353Smlaier			break;
2014126353Smlaier		case 'e':
2015126353Smlaier			opts |= PF_OPT_ENABLE;
2016126353Smlaier			mode = O_RDWR;
2017126353Smlaier			break;
2018126353Smlaier		case 'q':
2019126353Smlaier			opts |= PF_OPT_QUIET;
2020126353Smlaier			break;
2021126353Smlaier		case 'F':
2022126353Smlaier			clearopt = pfctl_lookup_option(optarg, clearopt_list);
2023126353Smlaier			if (clearopt == NULL) {
2024126353Smlaier				warnx("Unknown flush modifier '%s'", optarg);
2025126353Smlaier				usage();
2026126353Smlaier			}
2027126353Smlaier			mode = O_RDWR;
2028126353Smlaier			break;
2029130617Smlaier		case 'i':
2030130617Smlaier			ifaceopt = optarg;
2031130617Smlaier			break;
2032126353Smlaier		case 'k':
2033126353Smlaier			if (state_killers >= 2) {
2034126353Smlaier				warnx("can only specify -k twice");
2035126353Smlaier				usage();
2036126353Smlaier				/* NOTREACHED */
2037126353Smlaier			}
2038126353Smlaier			state_kill[state_killers++] = optarg;
2039126353Smlaier			mode = O_RDWR;
2040126353Smlaier			break;
2041171172Smlaier		case 'K':
2042171172Smlaier			if (src_node_killers >= 2) {
2043171172Smlaier				warnx("can only specify -K twice");
2044171172Smlaier				usage();
2045171172Smlaier				/* NOTREACHED */
2046171172Smlaier			}
2047171172Smlaier			src_node_kill[src_node_killers++] = optarg;
2048171172Smlaier			mode = O_RDWR;
2049171172Smlaier			break;
2050145840Smlaier		case 'm':
2051145840Smlaier			opts |= PF_OPT_MERGE;
2052145840Smlaier			break;
2053126353Smlaier		case 'n':
2054126353Smlaier			opts |= PF_OPT_NOACTION;
2055126353Smlaier			break;
2056126353Smlaier		case 'N':
2057126353Smlaier			loadopt |= PFCTL_FLAG_NAT;
2058126353Smlaier			break;
2059126353Smlaier		case 'r':
2060126353Smlaier			opts |= PF_OPT_USEDNS;
2061126353Smlaier			break;
2062126353Smlaier		case 'f':
2063126353Smlaier			rulesopt = optarg;
2064126353Smlaier			mode = O_RDWR;
2065126353Smlaier			break;
2066126353Smlaier		case 'g':
2067126353Smlaier			opts |= PF_OPT_DEBUG;
2068126353Smlaier			break;
2069126353Smlaier		case 'A':
2070126353Smlaier			loadopt |= PFCTL_FLAG_ALTQ;
2071126353Smlaier			break;
2072126353Smlaier		case 'R':
2073126353Smlaier			loadopt |= PFCTL_FLAG_FILTER;
2074126353Smlaier			break;
2075145840Smlaier		case 'o':
2076223637Sbz			optiopt = pfctl_lookup_option(optarg, optiopt_list);
2077223637Sbz			if (optiopt == NULL) {
2078223637Sbz				warnx("Unknown optimization '%s'", optarg);
2079223637Sbz				usage();
2080171172Smlaier			}
2081171172Smlaier			opts |= PF_OPT_OPTIMIZE;
2082145840Smlaier			break;
2083126353Smlaier		case 'O':
2084126353Smlaier			loadopt |= PFCTL_FLAG_OPTION;
2085126353Smlaier			break;
2086130617Smlaier		case 'p':
2087130617Smlaier			pf_device = optarg;
2088130617Smlaier			break;
2089223057Sbz		case 'P':
2090223057Sbz			opts |= PF_OPT_NUMERIC;
2091223057Sbz			break;
2092126353Smlaier		case 's':
2093126353Smlaier			showopt = pfctl_lookup_option(optarg, showopt_list);
2094126353Smlaier			if (showopt == NULL) {
2095126353Smlaier				warnx("Unknown show modifier '%s'", optarg);
2096126353Smlaier				usage();
2097126353Smlaier			}
2098126353Smlaier			break;
2099126353Smlaier		case 't':
2100126353Smlaier			tableopt = optarg;
2101126353Smlaier			break;
2102126353Smlaier		case 'T':
2103126353Smlaier			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
2104126353Smlaier			if (tblcmdopt == NULL) {
2105126353Smlaier				warnx("Unknown table command '%s'", optarg);
2106126353Smlaier				usage();
2107126353Smlaier			}
2108126353Smlaier			break;
2109126353Smlaier		case 'v':
2110126353Smlaier			if (opts & PF_OPT_VERBOSE)
2111126353Smlaier				opts |= PF_OPT_VERBOSE2;
2112126353Smlaier			opts |= PF_OPT_VERBOSE;
2113126353Smlaier			break;
2114126353Smlaier		case 'x':
2115126353Smlaier			debugopt = pfctl_lookup_option(optarg, debugopt_list);
2116126353Smlaier			if (debugopt == NULL) {
2117126353Smlaier				warnx("Unknown debug level '%s'", optarg);
2118126353Smlaier				usage();
2119126353Smlaier			}
2120126353Smlaier			mode = O_RDWR;
2121126353Smlaier			break;
2122126353Smlaier		case 'z':
2123126353Smlaier			opts |= PF_OPT_CLRRULECTRS;
2124126353Smlaier			mode = O_RDWR;
2125126353Smlaier			break;
2126126353Smlaier		case 'h':
2127126353Smlaier			/* FALLTHROUGH */
2128126353Smlaier		default:
2129126353Smlaier			usage();
2130126353Smlaier			/* NOTREACHED */
2131126353Smlaier		}
2132126353Smlaier	}
2133126353Smlaier
2134126353Smlaier	if (tblcmdopt != NULL) {
2135126353Smlaier		argc -= optind;
2136126353Smlaier		argv += optind;
2137126353Smlaier		ch = *tblcmdopt;
2138126353Smlaier		if (ch == 'l') {
2139126353Smlaier			loadopt |= PFCTL_FLAG_TABLE;
2140126353Smlaier			tblcmdopt = NULL;
2141130617Smlaier		} else
2142171172Smlaier			mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
2143126353Smlaier	} else if (argc != optind) {
2144126353Smlaier		warnx("unknown command line argument: %s ...", argv[optind]);
2145126353Smlaier		usage();
2146126353Smlaier		/* NOTREACHED */
2147126353Smlaier	}
2148126353Smlaier	if (loadopt == 0)
2149126353Smlaier		loadopt = ~0;
2150126353Smlaier
2151171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
2152171172Smlaier		errx(1, "pfctl: calloc");
2153126353Smlaier	memset(anchorname, 0, sizeof(anchorname));
2154126353Smlaier	if (anchoropt != NULL) {
2155171172Smlaier		int len = strlen(anchoropt);
2156171172Smlaier
2157171172Smlaier		if (anchoropt[len - 1] == '*') {
2158171172Smlaier			if (len >= 2 && anchoropt[len - 2] == '/')
2159171172Smlaier				anchoropt[len - 2] = '\0';
2160171172Smlaier			else
2161171172Smlaier				anchoropt[len - 1] = '\0';
2162171172Smlaier			opts |= PF_OPT_RECURSE;
2163171172Smlaier		}
2164145840Smlaier		if (strlcpy(anchorname, anchoropt,
2165145840Smlaier		    sizeof(anchorname)) >= sizeof(anchorname))
2166145840Smlaier			errx(1, "anchor name '%s' too long",
2167145840Smlaier			    anchoropt);
2168126353Smlaier		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
2169126353Smlaier	}
2170126353Smlaier
2171126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
2172130617Smlaier		dev = open(pf_device, mode);
2173126353Smlaier		if (dev == -1)
2174130617Smlaier			err(1, "%s", pf_device);
2175126353Smlaier		altqsupport = pfctl_test_altqsupport(dev, opts);
2176126353Smlaier	} else {
2177130617Smlaier		dev = open(pf_device, O_RDONLY);
2178130617Smlaier		if (dev >= 0)
2179130617Smlaier			opts |= PF_OPT_DUMMYACTION;
2180126353Smlaier		/* turn off options */
2181126353Smlaier		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
2182126353Smlaier		clearopt = showopt = debugopt = NULL;
2183258485Sglebius#if !defined(ENABLE_ALTQ)
2184126355Smlaier		altqsupport = 0;
2185126355Smlaier#else
2186126353Smlaier		altqsupport = 1;
2187126355Smlaier#endif
2188126353Smlaier	}
2189126353Smlaier
2190126353Smlaier	if (opts & PF_OPT_DISABLE)
2191126353Smlaier		if (pfctl_disable(dev, opts))
2192126353Smlaier			error = 1;
2193126353Smlaier
2194126353Smlaier	if (showopt != NULL) {
2195126353Smlaier		switch (*showopt) {
2196126353Smlaier		case 'A':
2197126353Smlaier			pfctl_show_anchors(dev, opts, anchorname);
2198126353Smlaier			break;
2199126353Smlaier		case 'r':
2200126353Smlaier			pfctl_load_fingerprints(dev, opts);
2201171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
2202171172Smlaier			    anchorname, 0);
2203126353Smlaier			break;
2204126353Smlaier		case 'l':
2205126353Smlaier			pfctl_load_fingerprints(dev, opts);
2206171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
2207171172Smlaier			    anchorname, 0);
2208126353Smlaier			break;
2209126353Smlaier		case 'n':
2210126353Smlaier			pfctl_load_fingerprints(dev, opts);
2211145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2212126353Smlaier			break;
2213126353Smlaier		case 'q':
2214130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts,
2215130617Smlaier			    opts & PF_OPT_VERBOSE2);
2216126353Smlaier			break;
2217126353Smlaier		case 's':
2218130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2219126353Smlaier			break;
2220130617Smlaier		case 'S':
2221130617Smlaier			pfctl_show_src_nodes(dev, opts);
2222130617Smlaier			break;
2223126353Smlaier		case 'i':
2224130617Smlaier			pfctl_show_status(dev, opts);
2225126353Smlaier			break;
2226126353Smlaier		case 't':
2227130617Smlaier			pfctl_show_timeouts(dev, opts);
2228126353Smlaier			break;
2229126353Smlaier		case 'm':
2230130617Smlaier			pfctl_show_limits(dev, opts);
2231126353Smlaier			break;
2232126353Smlaier		case 'a':
2233130617Smlaier			opts |= PF_OPT_SHOWALL;
2234126353Smlaier			pfctl_load_fingerprints(dev, opts);
2235126353Smlaier
2236145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2237171172Smlaier			pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
2238130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts, 0);
2239130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2240130617Smlaier			pfctl_show_src_nodes(dev, opts);
2241130617Smlaier			pfctl_show_status(dev, opts);
2242171172Smlaier			pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
2243130617Smlaier			pfctl_show_timeouts(dev, opts);
2244130617Smlaier			pfctl_show_limits(dev, opts);
2245145840Smlaier			pfctl_show_tables(anchorname, opts);
2246126353Smlaier			pfctl_show_fingerprints(opts);
2247126353Smlaier			break;
2248126353Smlaier		case 'T':
2249145840Smlaier			pfctl_show_tables(anchorname, opts);
2250126353Smlaier			break;
2251126353Smlaier		case 'o':
2252126353Smlaier			pfctl_load_fingerprints(dev, opts);
2253126353Smlaier			pfctl_show_fingerprints(opts);
2254126353Smlaier			break;
2255130617Smlaier		case 'I':
2256130617Smlaier			pfctl_show_ifaces(ifaceopt, opts);
2257130617Smlaier			break;
2258126353Smlaier		}
2259126353Smlaier	}
2260126353Smlaier
2261171172Smlaier	if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
2262171172Smlaier		pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
2263171172Smlaier		    anchorname, 0);
2264171172Smlaier
2265126353Smlaier	if (clearopt != NULL) {
2266171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2267171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2268171172Smlaier			    "be modified from the command line");
2269171172Smlaier
2270126353Smlaier		switch (*clearopt) {
2271126353Smlaier		case 'r':
2272145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2273126353Smlaier			break;
2274126353Smlaier		case 'n':
2275145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2276126353Smlaier			break;
2277126353Smlaier		case 'q':
2278126353Smlaier			pfctl_clear_altq(dev, opts);
2279126353Smlaier			break;
2280126353Smlaier		case 's':
2281130617Smlaier			pfctl_clear_states(dev, ifaceopt, opts);
2282126353Smlaier			break;
2283130617Smlaier		case 'S':
2284130617Smlaier			pfctl_clear_src_nodes(dev, opts);
2285130617Smlaier			break;
2286126353Smlaier		case 'i':
2287126353Smlaier			pfctl_clear_stats(dev, opts);
2288126353Smlaier			break;
2289126353Smlaier		case 'a':
2290145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2291145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2292145840Smlaier			pfctl_clear_tables(anchorname, opts);
2293145840Smlaier			if (!*anchorname) {
2294130617Smlaier				pfctl_clear_altq(dev, opts);
2295130617Smlaier				pfctl_clear_states(dev, ifaceopt, opts);
2296130617Smlaier				pfctl_clear_src_nodes(dev, opts);
2297130617Smlaier				pfctl_clear_stats(dev, opts);
2298130617Smlaier				pfctl_clear_fingerprints(dev, opts);
2299145840Smlaier				pfctl_clear_interface_flags(dev, opts);
2300130617Smlaier			}
2301126353Smlaier			break;
2302126353Smlaier		case 'o':
2303126353Smlaier			pfctl_clear_fingerprints(dev, opts);
2304126353Smlaier			break;
2305126353Smlaier		case 'T':
2306145840Smlaier			pfctl_clear_tables(anchorname, opts);
2307126353Smlaier			break;
2308126353Smlaier		}
2309126353Smlaier	}
2310223637Sbz	if (state_killers) {
2311223637Sbz		if (!strcmp(state_kill[0], "label"))
2312223637Sbz			pfctl_label_kill_states(dev, ifaceopt, opts);
2313223637Sbz		else if (!strcmp(state_kill[0], "id"))
2314223637Sbz			pfctl_id_kill_states(dev, ifaceopt, opts);
2315223637Sbz		else
2316223637Sbz			pfctl_net_kill_states(dev, ifaceopt, opts);
2317223637Sbz	}
2318126353Smlaier
2319171172Smlaier	if (src_node_killers)
2320171172Smlaier		pfctl_kill_src_nodes(dev, ifaceopt, opts);
2321171172Smlaier
2322126353Smlaier	if (tblcmdopt != NULL) {
2323126353Smlaier		error = pfctl_command_tables(argc, argv, tableopt,
2324145840Smlaier		    tblcmdopt, rulesopt, anchorname, opts);
2325126353Smlaier		rulesopt = NULL;
2326126353Smlaier	}
2327171172Smlaier	if (optiopt != NULL) {
2328171172Smlaier		switch (*optiopt) {
2329171172Smlaier		case 'n':
2330171172Smlaier			optimize = 0;
2331171172Smlaier			break;
2332171172Smlaier		case 'b':
2333171172Smlaier			optimize |= PF_OPTIMIZE_BASIC;
2334171172Smlaier			break;
2335171172Smlaier		case 'o':
2336171172Smlaier		case 'p':
2337171172Smlaier			optimize |= PF_OPTIMIZE_PROFILE;
2338171172Smlaier			break;
2339171172Smlaier		}
2340171172Smlaier	}
2341126353Smlaier
2342171172Smlaier	if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
2343171172Smlaier	    !anchorname[0])
2344145840Smlaier		if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
2345145840Smlaier			error = 1;
2346145840Smlaier
2347145840Smlaier	if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
2348145840Smlaier	    !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
2349126353Smlaier		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
2350126353Smlaier			error = 1;
2351126353Smlaier
2352126353Smlaier	if (rulesopt != NULL) {
2353171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2354171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2355171172Smlaier			    "be modified from the command line");
2356223637Sbz		if (pfctl_rules(dev, rulesopt, opts, optimize,
2357171172Smlaier		    anchorname, NULL))
2358126353Smlaier			error = 1;
2359126353Smlaier		else if (!(opts & PF_OPT_NOACTION) &&
2360126353Smlaier		    (loadopt & PFCTL_FLAG_TABLE))
2361126353Smlaier			warn_namespace_collision(NULL);
2362126353Smlaier	}
2363126353Smlaier
2364126353Smlaier	if (opts & PF_OPT_ENABLE)
2365126353Smlaier		if (pfctl_enable(dev, opts))
2366126353Smlaier			error = 1;
2367126353Smlaier
2368126353Smlaier	if (debugopt != NULL) {
2369126353Smlaier		switch (*debugopt) {
2370126353Smlaier		case 'n':
2371126353Smlaier			pfctl_debug(dev, PF_DEBUG_NONE, opts);
2372126353Smlaier			break;
2373126353Smlaier		case 'u':
2374126353Smlaier			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
2375126353Smlaier			break;
2376126353Smlaier		case 'm':
2377126353Smlaier			pfctl_debug(dev, PF_DEBUG_MISC, opts);
2378126353Smlaier			break;
2379126353Smlaier		case 'l':
2380126353Smlaier			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
2381126353Smlaier			break;
2382126353Smlaier		}
2383126353Smlaier	}
2384126353Smlaier
2385126353Smlaier	exit(error);
2386126353Smlaier}
2387