pfctl.c revision 262799
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 262799 2014-03-05 19:26:22Z 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>
55262799Sglebius#include <stdint.h>
56126353Smlaier#include <stdio.h>
57126353Smlaier#include <stdlib.h>
58126353Smlaier#include <string.h>
59126353Smlaier#include <unistd.h>
60126353Smlaier
61126353Smlaier#include "pfctl_parser.h"
62126353Smlaier#include "pfctl.h"
63126353Smlaier
64126353Smlaiervoid	 usage(void);
65126353Smlaierint	 pfctl_enable(int, int);
66126353Smlaierint	 pfctl_disable(int, int);
67126353Smlaierint	 pfctl_clear_stats(int, int);
68145840Smlaierint	 pfctl_clear_interface_flags(int, int);
69145840Smlaierint	 pfctl_clear_rules(int, int, char *);
70145840Smlaierint	 pfctl_clear_nat(int, int, char *);
71126353Smlaierint	 pfctl_clear_altq(int, int);
72130617Smlaierint	 pfctl_clear_src_nodes(int, int);
73130617Smlaierint	 pfctl_clear_states(int, const char *, int);
74171172Smlaiervoid	 pfctl_addrprefix(char *, struct pf_addr *);
75171172Smlaierint	 pfctl_kill_src_nodes(int, const char *, int);
76223637Sbzint	 pfctl_net_kill_states(int, const char *, int);
77223637Sbzint	 pfctl_label_kill_states(int, const char *, int);
78223637Sbzint	 pfctl_id_kill_states(int, const char *, int);
79145840Smlaiervoid	 pfctl_init_options(struct pfctl *);
80145840Smlaierint	 pfctl_load_options(struct pfctl *);
81145840Smlaierint	 pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
82145840Smlaierint	 pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
83145840Smlaierint	 pfctl_load_debug(struct pfctl *, unsigned int);
84145840Smlaierint	 pfctl_load_logif(struct pfctl *, char *);
85145840Smlaierint	 pfctl_load_hostid(struct pfctl *, unsigned int);
86126353Smlaierint	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
87145840Smlaier	    char *);
88126353Smlaiervoid	 pfctl_print_rule_counters(struct pf_rule *, int);
89171172Smlaierint	 pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
90145840Smlaierint	 pfctl_show_nat(int, int, char *);
91130617Smlaierint	 pfctl_show_src_nodes(int, int);
92130617Smlaierint	 pfctl_show_states(int, const char *, int);
93130617Smlaierint	 pfctl_show_status(int, int);
94130617Smlaierint	 pfctl_show_timeouts(int, int);
95130617Smlaierint	 pfctl_show_limits(int, int);
96145840Smlaiervoid	 pfctl_debug(int, u_int32_t, int);
97126353Smlaierint	 pfctl_test_altqsupport(int, int);
98126353Smlaierint	 pfctl_show_anchors(int, int, char *);
99171172Smlaierint	 pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
100171172Smlaierint	 pfctl_load_ruleset(struct pfctl *, char *,
101171172Smlaier		struct pf_ruleset *, int, int);
102171172Smlaierint	 pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
103126353Smlaierconst char	*pfctl_lookup_option(char *, const char **);
104126353Smlaier
105171172Smlaierstruct pf_anchor_global	 pf_anchors;
106171172Smlaierstruct pf_anchor	 pf_main_anchor;
107171172Smlaier
108126353Smlaierconst char	*clearopt;
109126353Smlaierchar		*rulesopt;
110126353Smlaierconst char	*showopt;
111126353Smlaierconst char	*debugopt;
112126353Smlaierchar		*anchoropt;
113171172Smlaierconst char	*optiopt = NULL;
114130617Smlaierchar		*pf_device = "/dev/pf";
115130617Smlaierchar		*ifaceopt;
116126353Smlaierchar		*tableopt;
117126353Smlaierconst char	*tblcmdopt;
118171172Smlaierint		 src_node_killers;
119171172Smlaierchar		*src_node_kill[2];
120126353Smlaierint		 state_killers;
121126353Smlaierchar		*state_kill[2];
122126353Smlaierint		 loadopt;
123126353Smlaierint		 altqsupport;
124126353Smlaier
125126353Smlaierint		 dev = -1;
126130617Smlaierint		 first_title = 1;
127130617Smlaierint		 labels = 0;
128126353Smlaier
129171172Smlaier#define INDENT(d, o)	do {						\
130171172Smlaier				if (o) {				\
131171172Smlaier					int i;				\
132171172Smlaier					for (i=0; i < d; i++)		\
133171172Smlaier						printf("  ");		\
134171172Smlaier				}					\
135171172Smlaier			} while (0);					\
136171172Smlaier
137171172Smlaier
138126353Smlaierstatic const struct {
139126353Smlaier	const char	*name;
140126353Smlaier	int		index;
141126353Smlaier} pf_limits[] = {
142171172Smlaier	{ "states",		PF_LIMIT_STATES },
143171172Smlaier	{ "src-nodes",		PF_LIMIT_SRC_NODES },
144171172Smlaier	{ "frags",		PF_LIMIT_FRAGS },
145171172Smlaier	{ "table-entries",	PF_LIMIT_TABLE_ENTRIES },
146171172Smlaier	{ NULL,			0 }
147126353Smlaier};
148126353Smlaier
149126353Smlaierstruct pf_hint {
150126353Smlaier	const char	*name;
151126353Smlaier	int		timeout;
152126353Smlaier};
153126353Smlaierstatic const struct pf_hint pf_hint_normal[] = {
154126353Smlaier	{ "tcp.first",		2 * 60 },
155126353Smlaier	{ "tcp.opening",	30 },
156126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
157126353Smlaier	{ "tcp.closing",	15 * 60 },
158126353Smlaier	{ "tcp.finwait",	45 },
159126353Smlaier	{ "tcp.closed",		90 },
160145840Smlaier	{ "tcp.tsdiff",		30 },
161126353Smlaier	{ NULL,			0 }
162126353Smlaier};
163126353Smlaierstatic const struct pf_hint pf_hint_satellite[] = {
164126353Smlaier	{ "tcp.first",		3 * 60 },
165126353Smlaier	{ "tcp.opening",	30 + 5 },
166126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
167126353Smlaier	{ "tcp.closing",	15 * 60 + 5 },
168126353Smlaier	{ "tcp.finwait",	45 + 5 },
169126353Smlaier	{ "tcp.closed",		90 + 5 },
170145840Smlaier	{ "tcp.tsdiff",		60 },
171126353Smlaier	{ NULL,			0 }
172126353Smlaier};
173126353Smlaierstatic const struct pf_hint pf_hint_conservative[] = {
174126353Smlaier	{ "tcp.first",		60 * 60 },
175126353Smlaier	{ "tcp.opening",	15 * 60 },
176126353Smlaier	{ "tcp.established",	5 * 24 * 60 * 60 },
177126353Smlaier	{ "tcp.closing",	60 * 60 },
178126353Smlaier	{ "tcp.finwait",	10 * 60 },
179126353Smlaier	{ "tcp.closed",		3 * 60 },
180145840Smlaier	{ "tcp.tsdiff",		60 },
181126353Smlaier	{ NULL,			0 }
182126353Smlaier};
183126353Smlaierstatic const struct pf_hint pf_hint_aggressive[] = {
184126353Smlaier	{ "tcp.first",		30 },
185126353Smlaier	{ "tcp.opening",	5 },
186126353Smlaier	{ "tcp.established",	5 * 60 * 60 },
187126353Smlaier	{ "tcp.closing",	60 },
188126353Smlaier	{ "tcp.finwait",	30 },
189126353Smlaier	{ "tcp.closed",		30 },
190145840Smlaier	{ "tcp.tsdiff",		10 },
191126353Smlaier	{ NULL,			0 }
192126353Smlaier};
193126353Smlaier
194126353Smlaierstatic const struct {
195126353Smlaier	const char *name;
196126353Smlaier	const struct pf_hint *hint;
197126353Smlaier} pf_hints[] = {
198126353Smlaier	{ "normal",		pf_hint_normal },
199126353Smlaier	{ "satellite",		pf_hint_satellite },
200126353Smlaier	{ "high-latency",	pf_hint_satellite },
201126353Smlaier	{ "conservative",	pf_hint_conservative },
202126353Smlaier	{ "aggressive",		pf_hint_aggressive },
203126353Smlaier	{ NULL,			NULL }
204126353Smlaier};
205126353Smlaier
206126353Smlaierstatic const char *clearopt_list[] = {
207130617Smlaier	"nat", "queue", "rules", "Sources",
208223637Sbz	"states", "info", "Tables", "osfp", "all", NULL
209126353Smlaier};
210126353Smlaier
211126353Smlaierstatic const char *showopt_list[] = {
212223637Sbz	"nat", "queue", "rules", "Anchors", "Sources", "states", "info",
213130617Smlaier	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
214130617Smlaier	"all", NULL
215126353Smlaier};
216126353Smlaier
217126353Smlaierstatic const char *tblcmdopt_list[] = {
218126353Smlaier	"kill", "flush", "add", "delete", "load", "replace", "show",
219171172Smlaier	"test", "zero", "expire", NULL
220126353Smlaier};
221126353Smlaier
222126353Smlaierstatic const char *debugopt_list[] = {
223126353Smlaier	"none", "urgent", "misc", "loud", NULL
224126353Smlaier};
225126353Smlaier
226171172Smlaierstatic const char *optiopt_list[] = {
227223637Sbz	"none", "basic", "profile", NULL
228171172Smlaier};
229126353Smlaier
230126353Smlaiervoid
231126353Smlaierusage(void)
232126353Smlaier{
233126353Smlaier	extern char *__progname;
234126353Smlaier
235258484Sglebius	fprintf(stderr,
236258484Sglebius"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
237258484Sglebius	"\t[-f file] [-i interface] [-K host | network]\n"
238258484Sglebius	"\t[-k host | network | label | id] [-o level] [-p device]\n"
239258484Sglebius	"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
240258484Sglebius	    __progname);
241258484Sglebius
242126353Smlaier	exit(1);
243126353Smlaier}
244126353Smlaier
245126353Smlaierint
246126353Smlaierpfctl_enable(int dev, int opts)
247126353Smlaier{
248126353Smlaier	if (ioctl(dev, DIOCSTART)) {
249126353Smlaier		if (errno == EEXIST)
250126353Smlaier			errx(1, "pf already enabled");
251126355Smlaier		else if (errno == ESRCH)
252126355Smlaier			errx(1, "pfil registeration failed");
253126353Smlaier		else
254126353Smlaier			err(1, "DIOCSTART");
255126353Smlaier	}
256126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
257126353Smlaier		fprintf(stderr, "pf enabled\n");
258126353Smlaier
259126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
260126353Smlaier		if (errno != EEXIST)
261126353Smlaier			err(1, "DIOCSTARTALTQ");
262126353Smlaier
263126353Smlaier	return (0);
264126353Smlaier}
265126353Smlaier
266126353Smlaierint
267126353Smlaierpfctl_disable(int dev, int opts)
268126353Smlaier{
269126353Smlaier	if (ioctl(dev, DIOCSTOP)) {
270126353Smlaier		if (errno == ENOENT)
271126353Smlaier			errx(1, "pf not enabled");
272126353Smlaier		else
273126353Smlaier			err(1, "DIOCSTOP");
274126353Smlaier	}
275126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
276126353Smlaier		fprintf(stderr, "pf disabled\n");
277126353Smlaier
278126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
279126353Smlaier			if (errno != ENOENT)
280126353Smlaier				err(1, "DIOCSTOPALTQ");
281126353Smlaier
282126353Smlaier	return (0);
283126353Smlaier}
284126353Smlaier
285126353Smlaierint
286126353Smlaierpfctl_clear_stats(int dev, int opts)
287126353Smlaier{
288126353Smlaier	if (ioctl(dev, DIOCCLRSTATUS))
289126353Smlaier		err(1, "DIOCCLRSTATUS");
290126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
291126353Smlaier		fprintf(stderr, "pf: statistics cleared\n");
292126353Smlaier	return (0);
293126353Smlaier}
294126353Smlaier
295126353Smlaierint
296145840Smlaierpfctl_clear_interface_flags(int dev, int opts)
297126353Smlaier{
298145840Smlaier	struct pfioc_iface	pi;
299126353Smlaier
300145840Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
301145840Smlaier		bzero(&pi, sizeof(pi));
302171172Smlaier		pi.pfiio_flags = PFI_IFLAG_SKIP;
303126353Smlaier
304145840Smlaier		if (ioctl(dev, DIOCCLRIFFLAG, &pi))
305145840Smlaier			err(1, "DIOCCLRIFFLAG");
306126353Smlaier		if ((opts & PF_OPT_QUIET) == 0)
307145840Smlaier			fprintf(stderr, "pf: interface flags reset\n");
308126353Smlaier	}
309145840Smlaier	return (0);
310145840Smlaier}
311145840Smlaier
312145840Smlaierint
313145840Smlaierpfctl_clear_rules(int dev, int opts, char *anchorname)
314145840Smlaier{
315145840Smlaier	struct pfr_buffer t;
316145840Smlaier
317130617Smlaier	memset(&t, 0, sizeof(t));
318130617Smlaier	t.pfrb_type = PFRB_TRANS;
319145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
320145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
321130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
322130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
323130617Smlaier		err(1, "pfctl_clear_rules");
324126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
325126353Smlaier		fprintf(stderr, "rules cleared\n");
326126353Smlaier	return (0);
327126353Smlaier}
328126353Smlaier
329126353Smlaierint
330145840Smlaierpfctl_clear_nat(int dev, int opts, char *anchorname)
331126353Smlaier{
332130617Smlaier	struct pfr_buffer t;
333126353Smlaier
334130617Smlaier	memset(&t, 0, sizeof(t));
335130617Smlaier	t.pfrb_type = PFRB_TRANS;
336145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
337145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
338145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
339130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
340130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
341130617Smlaier		err(1, "pfctl_clear_nat");
342126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
343126353Smlaier		fprintf(stderr, "nat cleared\n");
344126353Smlaier	return (0);
345126353Smlaier}
346126353Smlaier
347126353Smlaierint
348126353Smlaierpfctl_clear_altq(int dev, int opts)
349126353Smlaier{
350130617Smlaier	struct pfr_buffer t;
351126353Smlaier
352126353Smlaier	if (!altqsupport)
353126353Smlaier		return (-1);
354130617Smlaier	memset(&t, 0, sizeof(t));
355130617Smlaier	t.pfrb_type = PFRB_TRANS;
356145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
357130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
358130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
359130617Smlaier		err(1, "pfctl_clear_altq");
360126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
361126353Smlaier		fprintf(stderr, "altq cleared\n");
362126353Smlaier	return (0);
363126353Smlaier}
364126353Smlaier
365126353Smlaierint
366130617Smlaierpfctl_clear_src_nodes(int dev, int opts)
367126353Smlaier{
368130617Smlaier	if (ioctl(dev, DIOCCLRSRCNODES))
369130617Smlaier		err(1, "DIOCCLRSRCNODES");
370130617Smlaier	if ((opts & PF_OPT_QUIET) == 0)
371130617Smlaier		fprintf(stderr, "source tracking entries cleared\n");
372130617Smlaier	return (0);
373130617Smlaier}
374130617Smlaier
375130617Smlaierint
376130617Smlaierpfctl_clear_states(int dev, const char *iface, int opts)
377130617Smlaier{
378130617Smlaier	struct pfioc_state_kill psk;
379130617Smlaier
380130617Smlaier	memset(&psk, 0, sizeof(psk));
381130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
382130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
383130617Smlaier		errx(1, "invalid interface: %s", iface);
384130617Smlaier
385130617Smlaier	if (ioctl(dev, DIOCCLRSTATES, &psk))
386126353Smlaier		err(1, "DIOCCLRSTATES");
387126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
388223637Sbz		fprintf(stderr, "%d states cleared\n", psk.psk_killed);
389126353Smlaier	return (0);
390126353Smlaier}
391126353Smlaier
392171172Smlaiervoid
393171172Smlaierpfctl_addrprefix(char *addr, struct pf_addr *mask)
394171172Smlaier{
395171172Smlaier	char *p;
396171172Smlaier	const char *errstr;
397171172Smlaier	int prefix, ret_ga, q, r;
398171172Smlaier	struct addrinfo hints, *res;
399171172Smlaier
400171172Smlaier	if ((p = strchr(addr, '/')) == NULL)
401171172Smlaier		return;
402171172Smlaier
403171172Smlaier	*p++ = '\0';
404171172Smlaier	prefix = strtonum(p, 0, 128, &errstr);
405171172Smlaier	if (errstr)
406171172Smlaier		errx(1, "prefix is %s: %s", errstr, p);
407171172Smlaier
408171172Smlaier	bzero(&hints, sizeof(hints));
409171172Smlaier	/* prefix only with numeric addresses */
410171172Smlaier	hints.ai_flags |= AI_NUMERICHOST;
411171172Smlaier
412171172Smlaier	if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
413171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
414171172Smlaier		/* NOTREACHED */
415171172Smlaier	}
416171172Smlaier
417171172Smlaier	if (res->ai_family == AF_INET && prefix > 32)
418171172Smlaier		errx(1, "prefix too long for AF_INET");
419171172Smlaier	else if (res->ai_family == AF_INET6 && prefix > 128)
420171172Smlaier		errx(1, "prefix too long for AF_INET6");
421171172Smlaier
422171172Smlaier	q = prefix >> 3;
423171172Smlaier	r = prefix & 7;
424171172Smlaier	switch (res->ai_family) {
425171172Smlaier	case AF_INET:
426171172Smlaier		bzero(&mask->v4, sizeof(mask->v4));
427171172Smlaier		mask->v4.s_addr = htonl((u_int32_t)
428171172Smlaier		    (0xffffffffffULL << (32 - prefix)));
429171172Smlaier		break;
430171172Smlaier	case AF_INET6:
431171172Smlaier		bzero(&mask->v6, sizeof(mask->v6));
432171172Smlaier		if (q > 0)
433171172Smlaier			memset((void *)&mask->v6, 0xff, q);
434171172Smlaier		if (r > 0)
435171172Smlaier			*((u_char *)&mask->v6 + q) =
436171172Smlaier			    (0xff00 >> r) & 0xff;
437171172Smlaier		break;
438171172Smlaier	}
439171172Smlaier	freeaddrinfo(res);
440171172Smlaier}
441171172Smlaier
442126353Smlaierint
443171172Smlaierpfctl_kill_src_nodes(int dev, const char *iface, int opts)
444171172Smlaier{
445171172Smlaier	struct pfioc_src_node_kill psnk;
446171172Smlaier	struct addrinfo *res[2], *resp[2];
447171172Smlaier	struct sockaddr last_src, last_dst;
448171172Smlaier	int killed, sources, dests;
449171172Smlaier	int ret_ga;
450171172Smlaier
451171172Smlaier	killed = sources = dests = 0;
452171172Smlaier
453171172Smlaier	memset(&psnk, 0, sizeof(psnk));
454171172Smlaier	memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
455171172Smlaier	    sizeof(psnk.psnk_src.addr.v.a.mask));
456171172Smlaier	memset(&last_src, 0xff, sizeof(last_src));
457171172Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
458171172Smlaier
459171172Smlaier	pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
460171172Smlaier
461171172Smlaier	if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
462171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
463171172Smlaier		/* NOTREACHED */
464171172Smlaier	}
465171172Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
466171172Smlaier		if (resp[0]->ai_addr == NULL)
467171172Smlaier			continue;
468171172Smlaier		/* We get lots of duplicates.  Catch the easy ones */
469171172Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
470171172Smlaier			continue;
471171172Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
472171172Smlaier
473171172Smlaier		psnk.psnk_af = resp[0]->ai_family;
474171172Smlaier		sources++;
475171172Smlaier
476171172Smlaier		if (psnk.psnk_af == AF_INET)
477171172Smlaier			psnk.psnk_src.addr.v.a.addr.v4 =
478171172Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
479171172Smlaier		else if (psnk.psnk_af == AF_INET6)
480171172Smlaier			psnk.psnk_src.addr.v.a.addr.v6 =
481171172Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
482171172Smlaier			    sin6_addr;
483171172Smlaier		else
484171172Smlaier			errx(1, "Unknown address family %d", psnk.psnk_af);
485171172Smlaier
486171172Smlaier		if (src_node_killers > 1) {
487171172Smlaier			dests = 0;
488171172Smlaier			memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
489171172Smlaier			    sizeof(psnk.psnk_dst.addr.v.a.mask));
490171172Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
491171172Smlaier			pfctl_addrprefix(src_node_kill[1],
492171172Smlaier			    &psnk.psnk_dst.addr.v.a.mask);
493171172Smlaier			if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
494171172Smlaier			    &res[1]))) {
495171172Smlaier				errx(1, "getaddrinfo: %s",
496171172Smlaier				    gai_strerror(ret_ga));
497171172Smlaier				/* NOTREACHED */
498171172Smlaier			}
499171172Smlaier			for (resp[1] = res[1]; resp[1];
500171172Smlaier			    resp[1] = resp[1]->ai_next) {
501171172Smlaier				if (resp[1]->ai_addr == NULL)
502171172Smlaier					continue;
503171172Smlaier				if (psnk.psnk_af != resp[1]->ai_family)
504171172Smlaier					continue;
505171172Smlaier
506171172Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
507171172Smlaier				    sizeof(last_dst)) == 0)
508171172Smlaier					continue;
509171172Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
510171172Smlaier
511171172Smlaier				dests++;
512171172Smlaier
513171172Smlaier				if (psnk.psnk_af == AF_INET)
514171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v4 =
515171172Smlaier					    ((struct sockaddr_in *)resp[1]->
516171172Smlaier					    ai_addr)->sin_addr;
517171172Smlaier				else if (psnk.psnk_af == AF_INET6)
518171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v6 =
519171172Smlaier					    ((struct sockaddr_in6 *)resp[1]->
520171172Smlaier					    ai_addr)->sin6_addr;
521171172Smlaier				else
522171172Smlaier					errx(1, "Unknown address family %d",
523171172Smlaier					    psnk.psnk_af);
524171172Smlaier
525171172Smlaier				if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
526171172Smlaier					err(1, "DIOCKILLSRCNODES");
527223637Sbz				killed += psnk.psnk_killed;
528171172Smlaier			}
529171172Smlaier			freeaddrinfo(res[1]);
530171172Smlaier		} else {
531171172Smlaier			if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
532171172Smlaier				err(1, "DIOCKILLSRCNODES");
533223637Sbz			killed += psnk.psnk_killed;
534171172Smlaier		}
535171172Smlaier	}
536171172Smlaier
537171172Smlaier	freeaddrinfo(res[0]);
538171172Smlaier
539171172Smlaier	if ((opts & PF_OPT_QUIET) == 0)
540171172Smlaier		fprintf(stderr, "killed %d src nodes from %d sources and %d "
541171172Smlaier		    "destinations\n", killed, sources, dests);
542171172Smlaier	return (0);
543171172Smlaier}
544171172Smlaier
545171172Smlaierint
546223637Sbzpfctl_net_kill_states(int dev, const char *iface, int opts)
547126353Smlaier{
548126353Smlaier	struct pfioc_state_kill psk;
549126353Smlaier	struct addrinfo *res[2], *resp[2];
550126353Smlaier	struct sockaddr last_src, last_dst;
551126353Smlaier	int killed, sources, dests;
552126353Smlaier	int ret_ga;
553126353Smlaier
554126353Smlaier	killed = sources = dests = 0;
555126353Smlaier
556126353Smlaier	memset(&psk, 0, sizeof(psk));
557126353Smlaier	memset(&psk.psk_src.addr.v.a.mask, 0xff,
558126353Smlaier	    sizeof(psk.psk_src.addr.v.a.mask));
559126353Smlaier	memset(&last_src, 0xff, sizeof(last_src));
560126353Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
561130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
562130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
563130617Smlaier		errx(1, "invalid interface: %s", iface);
564126353Smlaier
565171172Smlaier	pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
566171172Smlaier
567126353Smlaier	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
568126353Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
569126353Smlaier		/* NOTREACHED */
570126353Smlaier	}
571126353Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
572126353Smlaier		if (resp[0]->ai_addr == NULL)
573126353Smlaier			continue;
574126353Smlaier		/* We get lots of duplicates.  Catch the easy ones */
575126353Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
576126353Smlaier			continue;
577126353Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
578126353Smlaier
579126353Smlaier		psk.psk_af = resp[0]->ai_family;
580126353Smlaier		sources++;
581126353Smlaier
582126353Smlaier		if (psk.psk_af == AF_INET)
583126353Smlaier			psk.psk_src.addr.v.a.addr.v4 =
584126353Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
585126353Smlaier		else if (psk.psk_af == AF_INET6)
586126353Smlaier			psk.psk_src.addr.v.a.addr.v6 =
587126353Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
588126353Smlaier			    sin6_addr;
589126353Smlaier		else
590126353Smlaier			errx(1, "Unknown address family %d", psk.psk_af);
591126353Smlaier
592126353Smlaier		if (state_killers > 1) {
593126353Smlaier			dests = 0;
594126353Smlaier			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
595126353Smlaier			    sizeof(psk.psk_dst.addr.v.a.mask));
596126353Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
597171172Smlaier			pfctl_addrprefix(state_kill[1],
598171172Smlaier			    &psk.psk_dst.addr.v.a.mask);
599126353Smlaier			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
600126353Smlaier			    &res[1]))) {
601130617Smlaier				errx(1, "getaddrinfo: %s",
602130617Smlaier				    gai_strerror(ret_ga));
603126353Smlaier				/* NOTREACHED */
604126353Smlaier			}
605126353Smlaier			for (resp[1] = res[1]; resp[1];
606126353Smlaier			    resp[1] = resp[1]->ai_next) {
607126353Smlaier				if (resp[1]->ai_addr == NULL)
608126353Smlaier					continue;
609126353Smlaier				if (psk.psk_af != resp[1]->ai_family)
610126353Smlaier					continue;
611126353Smlaier
612126353Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
613126353Smlaier				    sizeof(last_dst)) == 0)
614126353Smlaier					continue;
615126353Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
616126353Smlaier
617126353Smlaier				dests++;
618126353Smlaier
619126353Smlaier				if (psk.psk_af == AF_INET)
620126353Smlaier					psk.psk_dst.addr.v.a.addr.v4 =
621126353Smlaier					    ((struct sockaddr_in *)resp[1]->
622126353Smlaier					    ai_addr)->sin_addr;
623126353Smlaier				else if (psk.psk_af == AF_INET6)
624126353Smlaier					psk.psk_dst.addr.v.a.addr.v6 =
625126353Smlaier					    ((struct sockaddr_in6 *)resp[1]->
626126353Smlaier					    ai_addr)->sin6_addr;
627126353Smlaier				else
628126353Smlaier					errx(1, "Unknown address family %d",
629126353Smlaier					    psk.psk_af);
630126353Smlaier
631126353Smlaier				if (ioctl(dev, DIOCKILLSTATES, &psk))
632126353Smlaier					err(1, "DIOCKILLSTATES");
633223637Sbz				killed += psk.psk_killed;
634126353Smlaier			}
635126353Smlaier			freeaddrinfo(res[1]);
636126353Smlaier		} else {
637126353Smlaier			if (ioctl(dev, DIOCKILLSTATES, &psk))
638126353Smlaier				err(1, "DIOCKILLSTATES");
639223637Sbz			killed += psk.psk_killed;
640126353Smlaier		}
641126353Smlaier	}
642126353Smlaier
643126353Smlaier	freeaddrinfo(res[0]);
644126353Smlaier
645126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
646126353Smlaier		fprintf(stderr, "killed %d states from %d sources and %d "
647126353Smlaier		    "destinations\n", killed, sources, dests);
648126353Smlaier	return (0);
649126353Smlaier}
650126353Smlaier
651126353Smlaierint
652223637Sbzpfctl_label_kill_states(int dev, const char *iface, int opts)
653223637Sbz{
654223637Sbz	struct pfioc_state_kill psk;
655223637Sbz
656223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
657223637Sbz		warnx("no label specified");
658223637Sbz		usage();
659223637Sbz	}
660223637Sbz	memset(&psk, 0, sizeof(psk));
661223637Sbz	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
662223637Sbz	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
663223637Sbz		errx(1, "invalid interface: %s", iface);
664223637Sbz
665223637Sbz	if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
666223637Sbz	    sizeof(psk.psk_label))
667223637Sbz		errx(1, "label too long: %s", state_kill[1]);
668223637Sbz
669223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
670223637Sbz		err(1, "DIOCKILLSTATES");
671223637Sbz
672223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
673223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
674223637Sbz
675223637Sbz	return (0);
676223637Sbz}
677223637Sbz
678223637Sbzint
679223637Sbzpfctl_id_kill_states(int dev, const char *iface, int opts)
680223637Sbz{
681223637Sbz	struct pfioc_state_kill psk;
682223637Sbz
683223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
684223637Sbz		warnx("no id specified");
685223637Sbz		usage();
686223637Sbz	}
687223637Sbz
688223637Sbz	memset(&psk, 0, sizeof(psk));
689223637Sbz	if ((sscanf(state_kill[1], "%jx/%x",
690223637Sbz	    &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
691223637Sbz		HTONL(psk.psk_pfcmp.creatorid);
692223637Sbz	else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
693223637Sbz		psk.psk_pfcmp.creatorid = 0;
694223637Sbz	} else {
695223637Sbz		warnx("wrong id format specified");
696223637Sbz		usage();
697223637Sbz	}
698223637Sbz	if (psk.psk_pfcmp.id == 0) {
699223637Sbz		warnx("cannot kill id 0");
700223637Sbz		usage();
701223637Sbz	}
702223637Sbz
703223637Sbz	psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
704223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
705223637Sbz		err(1, "DIOCKILLSTATES");
706223637Sbz
707223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
708223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
709223637Sbz
710223637Sbz	return (0);
711223637Sbz}
712223637Sbz
713223637Sbzint
714126353Smlaierpfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
715145840Smlaier    u_int32_t ticket, int r_action, char *anchorname)
716126353Smlaier{
717126353Smlaier	struct pfioc_pooladdr pp;
718126353Smlaier	struct pf_pooladdr *pa;
719126353Smlaier	u_int32_t pnr, mpnr;
720126353Smlaier
721126353Smlaier	memset(&pp, 0, sizeof(pp));
722126353Smlaier	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
723126353Smlaier	pp.r_action = r_action;
724126353Smlaier	pp.r_num = nr;
725126353Smlaier	pp.ticket = ticket;
726126353Smlaier	if (ioctl(dev, DIOCGETADDRS, &pp)) {
727126353Smlaier		warn("DIOCGETADDRS");
728126353Smlaier		return (-1);
729126353Smlaier	}
730126353Smlaier	mpnr = pp.nr;
731126353Smlaier	TAILQ_INIT(&pool->list);
732126353Smlaier	for (pnr = 0; pnr < mpnr; ++pnr) {
733126353Smlaier		pp.nr = pnr;
734126353Smlaier		if (ioctl(dev, DIOCGETADDR, &pp)) {
735126353Smlaier			warn("DIOCGETADDR");
736126353Smlaier			return (-1);
737126353Smlaier		}
738126353Smlaier		pa = calloc(1, sizeof(struct pf_pooladdr));
739126353Smlaier		if (pa == NULL)
740126353Smlaier			err(1, "calloc");
741126353Smlaier		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
742126353Smlaier		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
743126353Smlaier	}
744126353Smlaier
745126353Smlaier	return (0);
746126353Smlaier}
747126353Smlaier
748126353Smlaiervoid
749171172Smlaierpfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
750171172Smlaier{
751171172Smlaier	struct pf_pooladdr *pa;
752171172Smlaier
753171172Smlaier	while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
754171172Smlaier		TAILQ_REMOVE(&src->list, pa, entries);
755171172Smlaier		TAILQ_INSERT_TAIL(&dst->list, pa, entries);
756171172Smlaier	}
757171172Smlaier}
758171172Smlaier
759171172Smlaiervoid
760126353Smlaierpfctl_clear_pool(struct pf_pool *pool)
761126353Smlaier{
762126353Smlaier	struct pf_pooladdr *pa;
763126353Smlaier
764126353Smlaier	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
765126353Smlaier		TAILQ_REMOVE(&pool->list, pa, entries);
766126353Smlaier		free(pa);
767126353Smlaier	}
768126353Smlaier}
769126353Smlaier
770126353Smlaiervoid
771126353Smlaierpfctl_print_rule_counters(struct pf_rule *rule, int opts)
772126353Smlaier{
773126353Smlaier	if (opts & PF_OPT_DEBUG) {
774126353Smlaier		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
775126353Smlaier		    "p", "sa", "sp", "da", "dp" };
776126353Smlaier		int i;
777126353Smlaier
778126353Smlaier		printf("  [ Skip steps: ");
779126353Smlaier		for (i = 0; i < PF_SKIP_COUNT; ++i) {
780126353Smlaier			if (rule->skip[i].nr == rule->nr + 1)
781126353Smlaier				continue;
782126353Smlaier			printf("%s=", t[i]);
783126353Smlaier			if (rule->skip[i].nr == -1)
784126353Smlaier				printf("end ");
785126353Smlaier			else
786126353Smlaier				printf("%u ", rule->skip[i].nr);
787126353Smlaier		}
788126353Smlaier		printf("]\n");
789126353Smlaier
790126353Smlaier		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
791126353Smlaier		    rule->qname, rule->qid, rule->pqname, rule->pqid);
792126353Smlaier	}
793171172Smlaier	if (opts & PF_OPT_VERBOSE) {
794127024Smlaier		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
795262799Sglebius			    "Bytes: %-10llu  States: %-6ju]\n",
796127024Smlaier			    (unsigned long long)rule->evaluations,
797171172Smlaier			    (unsigned long long)(rule->packets[0] +
798171172Smlaier			    rule->packets[1]),
799171172Smlaier			    (unsigned long long)(rule->bytes[0] +
800262799Sglebius			    rule->bytes[1]), (uintmax_t)rule->u_states_cur);
801171172Smlaier		if (!(opts & PF_OPT_DEBUG))
802223637Sbz			printf("  [ Inserted: uid %u pid %u "
803262799Sglebius			    "State Creations: %-6ju]\n",
804223637Sbz			    (unsigned)rule->cuid, (unsigned)rule->cpid,
805262799Sglebius			    (uintmax_t)rule->u_states_tot);
806171172Smlaier	}
807126353Smlaier}
808126353Smlaier
809130617Smlaiervoid
810130617Smlaierpfctl_print_title(char *title)
811130617Smlaier{
812130617Smlaier	if (!first_title)
813130617Smlaier		printf("\n");
814130617Smlaier	first_title = 0;
815130617Smlaier	printf("%s\n", title);
816130617Smlaier}
817130617Smlaier
818126353Smlaierint
819171172Smlaierpfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
820171172Smlaier    char *anchorname, int depth)
821126353Smlaier{
822126353Smlaier	struct pfioc_rule pr;
823130617Smlaier	u_int32_t nr, mnr, header = 0;
824126353Smlaier	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
825223057Sbz	int numeric = opts & PF_OPT_NUMERIC;
826171172Smlaier	int len = strlen(path);
827171172Smlaier	int brace;
828171172Smlaier	char *p;
829126353Smlaier
830171172Smlaier	if (path[0])
831171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
832171172Smlaier	else
833171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
834171172Smlaier
835126353Smlaier	memset(&pr, 0, sizeof(pr));
836171172Smlaier	memcpy(pr.anchor, path, sizeof(pr.anchor));
837130617Smlaier	if (opts & PF_OPT_SHOWALL) {
838130617Smlaier		pr.rule.action = PF_PASS;
839130617Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
840130617Smlaier			warn("DIOCGETRULES");
841171172Smlaier			goto error;
842130617Smlaier		}
843130617Smlaier		header++;
844130617Smlaier	}
845126353Smlaier	pr.rule.action = PF_SCRUB;
846126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
847126353Smlaier		warn("DIOCGETRULES");
848171172Smlaier		goto error;
849126353Smlaier	}
850130617Smlaier	if (opts & PF_OPT_SHOWALL) {
851171172Smlaier		if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
852130617Smlaier			pfctl_print_title("FILTER RULES:");
853171172Smlaier		else if (format == PFCTL_SHOW_LABELS && labels)
854130617Smlaier			pfctl_print_title("LABEL COUNTERS:");
855130617Smlaier	}
856126353Smlaier	mnr = pr.nr;
857171172Smlaier	if (opts & PF_OPT_CLRRULECTRS)
858171172Smlaier		pr.action = PF_GET_CLR_CNTR;
859171172Smlaier
860126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
861126353Smlaier		pr.nr = nr;
862126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
863126353Smlaier			warn("DIOCGETRULE");
864171172Smlaier			goto error;
865126353Smlaier		}
866126353Smlaier
867126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
868171172Smlaier		    nr, pr.ticket, PF_SCRUB, path) != 0)
869171172Smlaier			goto error;
870126353Smlaier
871126353Smlaier		switch (format) {
872171172Smlaier		case PFCTL_SHOW_LABELS:
873126353Smlaier			break;
874171172Smlaier		case PFCTL_SHOW_RULES:
875130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
876130617Smlaier				labels = 1;
877223057Sbz			print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
878171172Smlaier			printf("\n");
879126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
880171172Smlaier			break;
881171172Smlaier		case PFCTL_SHOW_NOTHING:
882171172Smlaier			break;
883126353Smlaier		}
884126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
885126353Smlaier	}
886126353Smlaier	pr.rule.action = PF_PASS;
887126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
888126353Smlaier		warn("DIOCGETRULES");
889171172Smlaier		goto error;
890126353Smlaier	}
891126353Smlaier	mnr = pr.nr;
892126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
893126353Smlaier		pr.nr = nr;
894126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
895126353Smlaier			warn("DIOCGETRULE");
896171172Smlaier			goto error;
897126353Smlaier		}
898126353Smlaier
899126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
900171172Smlaier		    nr, pr.ticket, PF_PASS, path) != 0)
901171172Smlaier			goto error;
902126353Smlaier
903126353Smlaier		switch (format) {
904171172Smlaier		case PFCTL_SHOW_LABELS:
905126353Smlaier			if (pr.rule.label[0]) {
906223637Sbz				printf("%s %llu %llu %llu %llu"
907262799Sglebius				    " %llu %llu %llu %ju\n",
908223637Sbz				    pr.rule.label,
909127024Smlaier				    (unsigned long long)pr.rule.evaluations,
910171172Smlaier				    (unsigned long long)(pr.rule.packets[0] +
911171172Smlaier				    pr.rule.packets[1]),
912171172Smlaier				    (unsigned long long)(pr.rule.bytes[0] +
913171172Smlaier				    pr.rule.bytes[1]),
914171172Smlaier				    (unsigned long long)pr.rule.packets[0],
915171172Smlaier				    (unsigned long long)pr.rule.bytes[0],
916171172Smlaier				    (unsigned long long)pr.rule.packets[1],
917223637Sbz				    (unsigned long long)pr.rule.bytes[1],
918262799Sglebius				    (uintmax_t)pr.rule.u_states_tot);
919126353Smlaier			}
920126353Smlaier			break;
921171172Smlaier		case PFCTL_SHOW_RULES:
922171172Smlaier			brace = 0;
923130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
924130617Smlaier				labels = 1;
925171172Smlaier			INDENT(depth, !(opts & PF_OPT_VERBOSE));
926171172Smlaier			if (pr.anchor_call[0] &&
927171172Smlaier			   ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
928171172Smlaier			   ((void *)p == (void *)pr.anchor_call ||
929171172Smlaier			   *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
930171172Smlaier				brace++;
931171172Smlaier				if ((p = strrchr(pr.anchor_call, '/')) !=
932171172Smlaier				    NULL)
933171172Smlaier					p++;
934171172Smlaier				else
935171172Smlaier					p = &pr.anchor_call[0];
936171172Smlaier			} else
937171172Smlaier				p = &pr.anchor_call[0];
938171172Smlaier
939223057Sbz			print_rule(&pr.rule, p, rule_numbers, numeric);
940171172Smlaier			if (brace)
941171172Smlaier				printf(" {\n");
942171172Smlaier			else
943171172Smlaier				printf("\n");
944126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
945171172Smlaier			if (brace) {
946171172Smlaier				pfctl_show_rules(dev, path, opts, format,
947171172Smlaier				    p, depth + 1);
948171172Smlaier				INDENT(depth, !(opts & PF_OPT_VERBOSE));
949171172Smlaier				printf("}\n");
950171172Smlaier			}
951171172Smlaier			break;
952171172Smlaier		case PFCTL_SHOW_NOTHING:
953171172Smlaier			break;
954126353Smlaier		}
955126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
956126353Smlaier	}
957171172Smlaier	path[len] = '\0';
958126353Smlaier	return (0);
959171172Smlaier
960171172Smlaier error:
961171172Smlaier	path[len] = '\0';
962171172Smlaier	return (-1);
963126353Smlaier}
964126353Smlaier
965126353Smlaierint
966145840Smlaierpfctl_show_nat(int dev, int opts, char *anchorname)
967126353Smlaier{
968126353Smlaier	struct pfioc_rule pr;
969126353Smlaier	u_int32_t mnr, nr;
970126353Smlaier	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
971130617Smlaier	int i, dotitle = opts & PF_OPT_SHOWALL;
972126353Smlaier
973126353Smlaier	memset(&pr, 0, sizeof(pr));
974126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
975126353Smlaier	for (i = 0; i < 3; i++) {
976126353Smlaier		pr.rule.action = nattype[i];
977126353Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
978126353Smlaier			warn("DIOCGETRULES");
979126353Smlaier			return (-1);
980126353Smlaier		}
981126353Smlaier		mnr = pr.nr;
982126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
983126353Smlaier			pr.nr = nr;
984126353Smlaier			if (ioctl(dev, DIOCGETRULE, &pr)) {
985126353Smlaier				warn("DIOCGETRULE");
986126353Smlaier				return (-1);
987126353Smlaier			}
988126353Smlaier			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
989145840Smlaier			    pr.ticket, nattype[i], anchorname) != 0)
990126353Smlaier				return (-1);
991130617Smlaier			if (dotitle) {
992130617Smlaier				pfctl_print_title("TRANSLATION RULES:");
993130617Smlaier				dotitle = 0;
994130617Smlaier			}
995145840Smlaier			print_rule(&pr.rule, pr.anchor_call,
996223057Sbz			    opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
997171172Smlaier			printf("\n");
998126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
999126353Smlaier			pfctl_clear_pool(&pr.rule.rpool);
1000126353Smlaier		}
1001126353Smlaier	}
1002126353Smlaier	return (0);
1003126353Smlaier}
1004126353Smlaier
1005126353Smlaierint
1006130617Smlaierpfctl_show_src_nodes(int dev, int opts)
1007126353Smlaier{
1008130617Smlaier	struct pfioc_src_nodes psn;
1009130617Smlaier	struct pf_src_node *p;
1010130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1011223637Sbz	unsigned int len = 0;
1012130617Smlaier	int i;
1013130617Smlaier
1014130617Smlaier	memset(&psn, 0, sizeof(psn));
1015130617Smlaier	for (;;) {
1016130617Smlaier		psn.psn_len = len;
1017130617Smlaier		if (len) {
1018130617Smlaier			newinbuf = realloc(inbuf, len);
1019130617Smlaier			if (newinbuf == NULL)
1020130617Smlaier				err(1, "realloc");
1021130617Smlaier			psn.psn_buf = inbuf = newinbuf;
1022130617Smlaier		}
1023130617Smlaier		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
1024130617Smlaier			warn("DIOCGETSRCNODES");
1025171172Smlaier			free(inbuf);
1026130617Smlaier			return (-1);
1027130617Smlaier		}
1028130617Smlaier		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
1029130617Smlaier			break;
1030130617Smlaier		if (len == 0 && psn.psn_len == 0)
1031171172Smlaier			goto done;
1032130617Smlaier		if (len == 0 && psn.psn_len != 0)
1033130617Smlaier			len = psn.psn_len;
1034130617Smlaier		if (psn.psn_len == 0)
1035171172Smlaier			goto done;	/* no src_nodes */
1036130617Smlaier		len *= 2;
1037130617Smlaier	}
1038130617Smlaier	p = psn.psn_src_nodes;
1039130617Smlaier	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
1040130617Smlaier		pfctl_print_title("SOURCE TRACKING NODES:");
1041130617Smlaier	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
1042130617Smlaier		print_src_node(p, opts);
1043130617Smlaier		p++;
1044130617Smlaier	}
1045171172Smlaierdone:
1046171172Smlaier	free(inbuf);
1047130617Smlaier	return (0);
1048130617Smlaier}
1049130617Smlaier
1050130617Smlaierint
1051130617Smlaierpfctl_show_states(int dev, const char *iface, int opts)
1052130617Smlaier{
1053126353Smlaier	struct pfioc_states ps;
1054223637Sbz	struct pfsync_state *p;
1055130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1056223637Sbz	unsigned int len = 0;
1057130617Smlaier	int i, dotitle = (opts & PF_OPT_SHOWALL);
1058126353Smlaier
1059126353Smlaier	memset(&ps, 0, sizeof(ps));
1060126353Smlaier	for (;;) {
1061126353Smlaier		ps.ps_len = len;
1062126353Smlaier		if (len) {
1063130617Smlaier			newinbuf = realloc(inbuf, len);
1064130617Smlaier			if (newinbuf == NULL)
1065126353Smlaier				err(1, "realloc");
1066130617Smlaier			ps.ps_buf = inbuf = newinbuf;
1067126353Smlaier		}
1068126353Smlaier		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
1069126353Smlaier			warn("DIOCGETSTATES");
1070171172Smlaier			free(inbuf);
1071126353Smlaier			return (-1);
1072126353Smlaier		}
1073126353Smlaier		if (ps.ps_len + sizeof(struct pfioc_states) < len)
1074126353Smlaier			break;
1075126353Smlaier		if (len == 0 && ps.ps_len == 0)
1076171172Smlaier			goto done;
1077126353Smlaier		if (len == 0 && ps.ps_len != 0)
1078126353Smlaier			len = ps.ps_len;
1079126353Smlaier		if (ps.ps_len == 0)
1080171172Smlaier			goto done;	/* no states */
1081126353Smlaier		len *= 2;
1082126353Smlaier	}
1083126353Smlaier	p = ps.ps_states;
1084130617Smlaier	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
1085223637Sbz		if (iface != NULL && strcmp(p->ifname, iface))
1086130617Smlaier			continue;
1087130617Smlaier		if (dotitle) {
1088130617Smlaier			pfctl_print_title("STATES:");
1089130617Smlaier			dotitle = 0;
1090130617Smlaier		}
1091130617Smlaier		print_state(p, opts);
1092126353Smlaier	}
1093171172Smlaierdone:
1094171172Smlaier	free(inbuf);
1095126353Smlaier	return (0);
1096126353Smlaier}
1097126353Smlaier
1098126353Smlaierint
1099130617Smlaierpfctl_show_status(int dev, int opts)
1100126353Smlaier{
1101126353Smlaier	struct pf_status status;
1102126353Smlaier
1103126353Smlaier	if (ioctl(dev, DIOCGETSTATUS, &status)) {
1104126353Smlaier		warn("DIOCGETSTATUS");
1105126353Smlaier		return (-1);
1106126353Smlaier	}
1107130617Smlaier	if (opts & PF_OPT_SHOWALL)
1108130617Smlaier		pfctl_print_title("INFO:");
1109130617Smlaier	print_status(&status, opts);
1110126353Smlaier	return (0);
1111126353Smlaier}
1112126353Smlaier
1113126353Smlaierint
1114130617Smlaierpfctl_show_timeouts(int dev, int opts)
1115126353Smlaier{
1116126353Smlaier	struct pfioc_tm pt;
1117126353Smlaier	int i;
1118126353Smlaier
1119130617Smlaier	if (opts & PF_OPT_SHOWALL)
1120130617Smlaier		pfctl_print_title("TIMEOUTS:");
1121126353Smlaier	memset(&pt, 0, sizeof(pt));
1122126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1123126353Smlaier		pt.timeout = pf_timeouts[i].timeout;
1124126353Smlaier		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
1125126353Smlaier			err(1, "DIOCGETTIMEOUT");
1126126353Smlaier		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
1127145840Smlaier		if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1128145840Smlaier		    pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1129126353Smlaier			printf(" states");
1130126353Smlaier		else
1131126353Smlaier			printf("s");
1132126353Smlaier		printf("\n");
1133126353Smlaier	}
1134126353Smlaier	return (0);
1135126353Smlaier
1136126353Smlaier}
1137126353Smlaier
1138126353Smlaierint
1139130617Smlaierpfctl_show_limits(int dev, int opts)
1140126353Smlaier{
1141126353Smlaier	struct pfioc_limit pl;
1142126353Smlaier	int i;
1143126353Smlaier
1144130617Smlaier	if (opts & PF_OPT_SHOWALL)
1145130617Smlaier		pfctl_print_title("LIMITS:");
1146126353Smlaier	memset(&pl, 0, sizeof(pl));
1147126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1148130617Smlaier		pl.index = pf_limits[i].index;
1149126353Smlaier		if (ioctl(dev, DIOCGETLIMIT, &pl))
1150126353Smlaier			err(1, "DIOCGETLIMIT");
1151171172Smlaier		printf("%-13s ", pf_limits[i].name);
1152126353Smlaier		if (pl.limit == UINT_MAX)
1153126353Smlaier			printf("unlimited\n");
1154126353Smlaier		else
1155171172Smlaier			printf("hard limit %8u\n", pl.limit);
1156126353Smlaier	}
1157126353Smlaier	return (0);
1158126353Smlaier}
1159126353Smlaier
1160126353Smlaier/* callbacks for rule/nat/rdr/addr */
1161126353Smlaierint
1162126353Smlaierpfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
1163126353Smlaier{
1164126353Smlaier	struct pf_pooladdr *pa;
1165126353Smlaier
1166126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1167126353Smlaier		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
1168126353Smlaier			err(1, "DIOCBEGINADDRS");
1169126353Smlaier	}
1170126353Smlaier
1171126353Smlaier	pf->paddr.af = af;
1172126353Smlaier	TAILQ_FOREACH(pa, &p->list, entries) {
1173126353Smlaier		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
1174126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1175126353Smlaier			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
1176126353Smlaier				err(1, "DIOCADDADDR");
1177126353Smlaier		}
1178126353Smlaier	}
1179126353Smlaier	return (0);
1180126353Smlaier}
1181126353Smlaier
1182126353Smlaierint
1183145840Smlaierpfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
1184126353Smlaier{
1185130617Smlaier	u_int8_t		rs_num;
1186171172Smlaier	struct pf_rule		*rule;
1187171172Smlaier	struct pf_ruleset	*rs;
1188171172Smlaier	char 			*p;
1189126353Smlaier
1190171172Smlaier	rs_num = pf_get_ruleset_number(r->action);
1191171172Smlaier	if (rs_num == PF_RULESET_MAX)
1192145840Smlaier		errx(1, "Invalid rule type %d", r->action);
1193126353Smlaier
1194171172Smlaier	rs = &pf->anchor->ruleset;
1195145840Smlaier
1196171172Smlaier	if (anchor_call[0] && r->anchor == NULL) {
1197171172Smlaier		/*
1198171172Smlaier		 * Don't make non-brace anchors part of the main anchor pool.
1199145840Smlaier		 */
1200171172Smlaier		if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1201171172Smlaier			err(1, "pfctl_add_rule: calloc");
1202171172Smlaier
1203171172Smlaier		pf_init_ruleset(&r->anchor->ruleset);
1204171172Smlaier		r->anchor->ruleset.anchor = r->anchor;
1205171172Smlaier		if (strlcpy(r->anchor->path, anchor_call,
1206171172Smlaier		    sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1207223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1208171172Smlaier		if ((p = strrchr(anchor_call, '/')) != NULL) {
1209171172Smlaier			if (!strlen(p))
1210171172Smlaier				err(1, "pfctl_add_rule: bad anchor name %s",
1211171172Smlaier				    anchor_call);
1212171172Smlaier		} else
1213171172Smlaier			p = (char *)anchor_call;
1214171172Smlaier		if (strlcpy(r->anchor->name, p,
1215171172Smlaier		    sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1216223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1217171172Smlaier	}
1218145840Smlaier
1219171172Smlaier	if ((rule = calloc(1, sizeof(*rule))) == NULL)
1220171172Smlaier		err(1, "calloc");
1221171172Smlaier	bcopy(r, rule, sizeof(*rule));
1222171172Smlaier	TAILQ_INIT(&rule->rpool.list);
1223171172Smlaier	pfctl_move_pool(&r->rpool, &rule->rpool);
1224145840Smlaier
1225171172Smlaier	TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1226171172Smlaier	return (0);
1227171172Smlaier}
1228171172Smlaier
1229171172Smlaierint
1230171172Smlaierpfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
1231171172Smlaier{
1232171172Smlaier	int osize = pf->trans->pfrb_size;
1233171172Smlaier
1234171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1235171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1236171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1237171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1238171172Smlaier			return (1);
1239171172Smlaier	}
1240171172Smlaier	if (a == pf->astack[0] && ((altqsupport &&
1241223637Sbz	    (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1242171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1243171172Smlaier			return (2);
1244171172Smlaier	}
1245171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1246171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1247171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1248171172Smlaier			return (3);
1249171172Smlaier	}
1250171172Smlaier	if (pf->loadopt & PFCTL_FLAG_TABLE)
1251171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1252171172Smlaier			return (4);
1253171172Smlaier	if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1254171172Smlaier		return (5);
1255171172Smlaier
1256171172Smlaier	return (0);
1257171172Smlaier}
1258171172Smlaier
1259171172Smlaierint
1260171172Smlaierpfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
1261171172Smlaier    int rs_num, int depth)
1262171172Smlaier{
1263171172Smlaier	struct pf_rule *r;
1264171172Smlaier	int		error, len = strlen(path);
1265171172Smlaier	int		brace = 0;
1266171172Smlaier
1267171172Smlaier	pf->anchor = rs->anchor;
1268171172Smlaier
1269171172Smlaier	if (path[0])
1270171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
1271171172Smlaier	else
1272171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
1273171172Smlaier
1274171172Smlaier	if (depth) {
1275171172Smlaier		if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
1276171172Smlaier			brace++;
1277171172Smlaier			if (pf->opts & PF_OPT_VERBOSE)
1278171172Smlaier				printf(" {\n");
1279171172Smlaier			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1280171172Smlaier			    (error = pfctl_ruleset_trans(pf,
1281171172Smlaier			    path, rs->anchor))) {
1282171172Smlaier				printf("pfctl_load_rulesets: "
1283171172Smlaier				    "pfctl_ruleset_trans %d\n", error);
1284171172Smlaier				goto error;
1285145840Smlaier			}
1286171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1287171172Smlaier			printf("\n");
1288145840Smlaier
1289145840Smlaier	}
1290145840Smlaier
1291171172Smlaier	if (pf->optimize && rs_num == PF_RULESET_FILTER)
1292171172Smlaier		pfctl_optimize_ruleset(pf, rs);
1293171172Smlaier
1294171172Smlaier	while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
1295171172Smlaier		TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
1296171172Smlaier		if ((error = pfctl_load_rule(pf, path, r, depth)))
1297171172Smlaier			goto error;
1298171172Smlaier		if (r->anchor) {
1299171172Smlaier			if ((error = pfctl_load_ruleset(pf, path,
1300171172Smlaier			    &r->anchor->ruleset, rs_num, depth + 1)))
1301171172Smlaier				goto error;
1302171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1303171172Smlaier			printf("\n");
1304171172Smlaier		free(r);
1305171172Smlaier	}
1306171172Smlaier	if (brace && pf->opts & PF_OPT_VERBOSE) {
1307171172Smlaier		INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
1308171172Smlaier		printf("}\n");
1309171172Smlaier	}
1310171172Smlaier	path[len] = '\0';
1311171172Smlaier	return (0);
1312171172Smlaier
1313171172Smlaier error:
1314171172Smlaier	path[len] = '\0';
1315171172Smlaier	return (error);
1316171172Smlaier
1317171172Smlaier}
1318171172Smlaier
1319171172Smlaierint
1320171172Smlaierpfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
1321171172Smlaier{
1322171172Smlaier	u_int8_t		rs_num = pf_get_ruleset_number(r->action);
1323171172Smlaier	char			*name;
1324171172Smlaier	struct pfioc_rule	pr;
1325171172Smlaier	int			len = strlen(path);
1326171172Smlaier
1327171172Smlaier	bzero(&pr, sizeof(pr));
1328171172Smlaier	/* set up anchor before adding to path for anchor_call */
1329171172Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1330171172Smlaier		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
1331171172Smlaier	if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
1332171172Smlaier		errx(1, "pfctl_load_rule: strlcpy");
1333171172Smlaier
1334171172Smlaier	if (r->anchor) {
1335171172Smlaier		if (r->anchor->match) {
1336171172Smlaier			if (path[0])
1337171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1338171172Smlaier				    "/%s", r->anchor->name);
1339171172Smlaier			else
1340171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1341171172Smlaier				    "%s", r->anchor->name);
1342171172Smlaier			name = path;
1343171172Smlaier		} else
1344171172Smlaier			name = r->anchor->path;
1345171172Smlaier	} else
1346171172Smlaier		name = "";
1347171172Smlaier
1348126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1349126353Smlaier		if (pfctl_add_pool(pf, &r->rpool, r->af))
1350126353Smlaier			return (1);
1351130617Smlaier		pr.pool_ticket = pf->paddr.ticket;
1352130617Smlaier		memcpy(&pr.rule, r, sizeof(pr.rule));
1353171172Smlaier		if (r->anchor && strlcpy(pr.anchor_call, name,
1354171172Smlaier		    sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
1355171172Smlaier			errx(1, "pfctl_load_rule: strlcpy");
1356130617Smlaier		if (ioctl(pf->dev, DIOCADDRULE, &pr))
1357126353Smlaier			err(1, "DIOCADDRULE");
1358126353Smlaier	}
1359171172Smlaier
1360171172Smlaier	if (pf->opts & PF_OPT_VERBOSE) {
1361171172Smlaier		INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
1362171172Smlaier		print_rule(r, r->anchor ? r->anchor->name : "",
1363223057Sbz		    pf->opts & PF_OPT_VERBOSE2,
1364223057Sbz		    pf->opts & PF_OPT_NUMERIC);
1365171172Smlaier	}
1366171172Smlaier	path[len] = '\0';
1367126353Smlaier	pfctl_clear_pool(&r->rpool);
1368126353Smlaier	return (0);
1369126353Smlaier}
1370126353Smlaier
1371126353Smlaierint
1372126353Smlaierpfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1373126353Smlaier{
1374126353Smlaier	if (altqsupport &&
1375126353Smlaier	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1376126353Smlaier		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1377126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1378126353Smlaier			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1379126353Smlaier				if (errno == ENXIO)
1380126353Smlaier					errx(1, "qtype not configured");
1381126353Smlaier				else if (errno == ENODEV)
1382126353Smlaier					errx(1, "%s: driver does not support "
1383126353Smlaier					    "altq", a->ifname);
1384126353Smlaier				else
1385126353Smlaier					err(1, "DIOCADDALTQ");
1386126353Smlaier			}
1387126353Smlaier		}
1388126353Smlaier		pfaltq_store(&pf->paltq->altq);
1389126353Smlaier	}
1390126353Smlaier	return (0);
1391126353Smlaier}
1392126353Smlaier
1393126353Smlaierint
1394223637Sbzpfctl_rules(int dev, char *filename, int opts, int optimize,
1395171172Smlaier    char *anchorname, struct pfr_buffer *trans)
1396126353Smlaier{
1397126353Smlaier#define ERR(x) do { warn(x); goto _error; } while(0)
1398126353Smlaier#define ERRX(x) do { warnx(x); goto _error; } while(0)
1399126353Smlaier
1400130617Smlaier	struct pfr_buffer	*t, buf;
1401130617Smlaier	struct pfioc_altq	 pa;
1402130617Smlaier	struct pfctl		 pf;
1403171172Smlaier	struct pf_ruleset	*rs;
1404130617Smlaier	struct pfr_table	 trs;
1405171172Smlaier	char			*path;
1406130617Smlaier	int			 osize;
1407126353Smlaier
1408171172Smlaier	RB_INIT(&pf_anchors);
1409171172Smlaier	memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
1410171172Smlaier	pf_init_ruleset(&pf_main_anchor.ruleset);
1411171172Smlaier	pf_main_anchor.ruleset.anchor = &pf_main_anchor;
1412130617Smlaier	if (trans == NULL) {
1413171172Smlaier		bzero(&buf, sizeof(buf));
1414171172Smlaier		buf.pfrb_type = PFRB_TRANS;
1415171172Smlaier		t = &buf;
1416171172Smlaier		osize = 0;
1417130617Smlaier	} else {
1418171172Smlaier		t = trans;
1419171172Smlaier		osize = t->pfrb_size;
1420130617Smlaier	}
1421130617Smlaier
1422126353Smlaier	memset(&pa, 0, sizeof(pa));
1423126353Smlaier	memset(&pf, 0, sizeof(pf));
1424126353Smlaier	memset(&trs, 0, sizeof(trs));
1425171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
1426171172Smlaier		ERRX("pfctl_rules: calloc");
1427126353Smlaier	if (strlcpy(trs.pfrt_anchor, anchorname,
1428145840Smlaier	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1429126353Smlaier		ERRX("pfctl_rules: strlcpy");
1430126353Smlaier	pf.dev = dev;
1431126353Smlaier	pf.opts = opts;
1432171172Smlaier	pf.optimize = optimize;
1433126353Smlaier	pf.loadopt = loadopt;
1434171172Smlaier
1435171172Smlaier	/* non-brace anchor, create without resolving the path */
1436171172Smlaier	if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
1437171172Smlaier		ERRX("pfctl_rules: calloc");
1438171172Smlaier	rs = &pf.anchor->ruleset;
1439171172Smlaier	pf_init_ruleset(rs);
1440171172Smlaier	rs->anchor = pf.anchor;
1441171172Smlaier	if (strlcpy(pf.anchor->path, anchorname,
1442171172Smlaier	    sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
1443171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1444171172Smlaier	if (strlcpy(pf.anchor->name, anchorname,
1445171172Smlaier	    sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
1446171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1447171172Smlaier
1448171172Smlaier
1449171172Smlaier	pf.astack[0] = pf.anchor;
1450171172Smlaier	pf.asd = 0;
1451130617Smlaier	if (anchorname[0])
1452130617Smlaier		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1453126353Smlaier	pf.paltq = &pa;
1454130617Smlaier	pf.trans = t;
1455145840Smlaier	pfctl_init_options(&pf);
1456130617Smlaier
1457130617Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
1458171172Smlaier		/*
1459171172Smlaier		 * XXX For the time being we need to open transactions for
1460171172Smlaier		 * the main ruleset before parsing, because tables are still
1461171172Smlaier		 * loaded at parse time.
1462171172Smlaier		 */
1463171172Smlaier		if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
1464171172Smlaier			ERRX("pfctl_rules");
1465130617Smlaier		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1466171172Smlaier			pa.ticket =
1467171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
1468130617Smlaier		if (pf.loadopt & PFCTL_FLAG_TABLE)
1469171172Smlaier			pf.astack[0]->ruleset.tticket =
1470171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
1471130617Smlaier	}
1472171172Smlaier
1473223637Sbz	if (parse_config(filename, &pf) < 0) {
1474126353Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1475126353Smlaier			ERRX("Syntax error in config file: "
1476126353Smlaier			    "pf rules not loaded");
1477126353Smlaier		else
1478126353Smlaier			goto _error;
1479126353Smlaier	}
1480171172Smlaier
1481171172Smlaier	if ((pf.loadopt & PFCTL_FLAG_FILTER &&
1482171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
1483171172Smlaier	    (pf.loadopt & PFCTL_FLAG_NAT &&
1484171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
1485171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
1486171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
1487171172Smlaier	    (pf.loadopt & PFCTL_FLAG_FILTER &&
1488171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
1489171172Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1490171172Smlaier			ERRX("Unable to load rules into kernel");
1491171172Smlaier		else
1492171172Smlaier			goto _error;
1493145840Smlaier	}
1494145840Smlaier
1495130617Smlaier	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1496126353Smlaier		if (check_commit_altq(dev, opts) != 0)
1497126353Smlaier			ERRX("errors in altq config");
1498145840Smlaier
1499126353Smlaier	/* process "load anchor" directives */
1500145840Smlaier	if (!anchorname[0])
1501171172Smlaier		if (pfctl_load_anchors(dev, &pf, t) == -1)
1502126353Smlaier			ERRX("load anchors");
1503126353Smlaier
1504145840Smlaier	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1505145840Smlaier		if (!anchorname[0])
1506145840Smlaier			if (pfctl_load_options(&pf))
1507145840Smlaier				goto _error;
1508171172Smlaier		if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
1509130617Smlaier			ERR("DIOCXCOMMIT");
1510145840Smlaier	}
1511126353Smlaier	return (0);
1512126353Smlaier
1513126353Smlaier_error:
1514130617Smlaier	if (trans == NULL) {	/* main ruleset */
1515130617Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1516171172Smlaier			if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
1517130617Smlaier				err(1, "DIOCXROLLBACK");
1518130617Smlaier		exit(1);
1519145840Smlaier	} else {		/* sub ruleset */
1520130617Smlaier		return (-1);
1521145840Smlaier	}
1522126353Smlaier
1523126353Smlaier#undef ERR
1524126353Smlaier#undef ERRX
1525126353Smlaier}
1526126353Smlaier
1527145840SmlaierFILE *
1528145840Smlaierpfctl_fopen(const char *name, const char *mode)
1529145840Smlaier{
1530145840Smlaier	struct stat	 st;
1531145840Smlaier	FILE		*fp;
1532145840Smlaier
1533145840Smlaier	fp = fopen(name, mode);
1534145840Smlaier	if (fp == NULL)
1535145840Smlaier		return (NULL);
1536145840Smlaier	if (fstat(fileno(fp), &st)) {
1537145840Smlaier		fclose(fp);
1538145840Smlaier		return (NULL);
1539145840Smlaier	}
1540145840Smlaier	if (S_ISDIR(st.st_mode)) {
1541145840Smlaier		fclose(fp);
1542145840Smlaier		errno = EISDIR;
1543145840Smlaier		return (NULL);
1544145840Smlaier	}
1545145840Smlaier	return (fp);
1546145840Smlaier}
1547145840Smlaier
1548145840Smlaiervoid
1549145840Smlaierpfctl_init_options(struct pfctl *pf)
1550145840Smlaier{
1551171172Smlaier
1552145840Smlaier	pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1553145840Smlaier	pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1554145840Smlaier	pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1555145840Smlaier	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1556145840Smlaier	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1557145840Smlaier	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1558145840Smlaier	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1559145840Smlaier	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1560145840Smlaier	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1561145840Smlaier	pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1562145840Smlaier	pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1563145840Smlaier	pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1564145840Smlaier	pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1565145840Smlaier	pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1566145840Smlaier	pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1567145840Smlaier	pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1568145840Smlaier	pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1569145840Smlaier	pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1570171172Smlaier	pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
1571171172Smlaier	pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
1572145840Smlaier
1573171172Smlaier	pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
1574171172Smlaier	pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
1575171172Smlaier	pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
1576171172Smlaier	pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
1577145840Smlaier
1578145840Smlaier	pf->debug = PF_DEBUG_URGENT;
1579145840Smlaier}
1580145840Smlaier
1581126353Smlaierint
1582145840Smlaierpfctl_load_options(struct pfctl *pf)
1583126353Smlaier{
1584145840Smlaier	int i, error = 0;
1585126353Smlaier
1586126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1587126353Smlaier		return (0);
1588126353Smlaier
1589145840Smlaier	/* load limits */
1590145840Smlaier	for (i = 0; i < PF_LIMIT_MAX; i++) {
1591145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1592145840Smlaier			continue;
1593145840Smlaier		if (pfctl_load_limit(pf, i, pf->limit[i]))
1594145840Smlaier			error = 1;
1595145840Smlaier	}
1596145840Smlaier
1597171172Smlaier	/*
1598223637Sbz	 * If we've set the limit, but haven't explicitly set adaptive
1599171172Smlaier	 * timeouts, do it now with a start of 60% and end of 120%.
1600171172Smlaier	 */
1601171172Smlaier	if (pf->limit_set[PF_LIMIT_STATES] &&
1602171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_START] &&
1603171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_END]) {
1604171172Smlaier		pf->timeout[PFTM_ADAPTIVE_START] =
1605171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 6;
1606171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
1607171172Smlaier		pf->timeout[PFTM_ADAPTIVE_END] =
1608171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 12;
1609171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
1610171172Smlaier	}
1611171172Smlaier
1612145840Smlaier	/* load timeouts */
1613145840Smlaier	for (i = 0; i < PFTM_MAX; i++) {
1614145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1615145840Smlaier			continue;
1616145840Smlaier		if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1617145840Smlaier			error = 1;
1618145840Smlaier	}
1619145840Smlaier
1620145840Smlaier	/* load debug */
1621145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1622145840Smlaier		if (pfctl_load_debug(pf, pf->debug))
1623145840Smlaier			error = 1;
1624145840Smlaier
1625145840Smlaier	/* load logif */
1626145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1627145840Smlaier		if (pfctl_load_logif(pf, pf->ifname))
1628145840Smlaier			error = 1;
1629145840Smlaier
1630145840Smlaier	/* load hostid */
1631145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1632145840Smlaier		if (pfctl_load_hostid(pf, pf->hostid))
1633145840Smlaier			error = 1;
1634145840Smlaier
1635145840Smlaier	return (error);
1636145840Smlaier}
1637145840Smlaier
1638145840Smlaierint
1639145840Smlaierpfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1640145840Smlaier{
1641145840Smlaier	int i;
1642145840Smlaier
1643145840Smlaier
1644126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1645126353Smlaier		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1646145840Smlaier			pf->limit[pf_limits[i].index] = limit;
1647145840Smlaier			pf->limit_set[pf_limits[i].index] = 1;
1648126353Smlaier			break;
1649126353Smlaier		}
1650126353Smlaier	}
1651126353Smlaier	if (pf_limits[i].name == NULL) {
1652126353Smlaier		warnx("Bad pool name.");
1653126353Smlaier		return (1);
1654126353Smlaier	}
1655126353Smlaier
1656126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1657126353Smlaier		printf("set limit %s %d\n", opt, limit);
1658126353Smlaier
1659126353Smlaier	return (0);
1660126353Smlaier}
1661126353Smlaier
1662126353Smlaierint
1663145840Smlaierpfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1664145840Smlaier{
1665145840Smlaier	struct pfioc_limit pl;
1666145840Smlaier
1667145840Smlaier	memset(&pl, 0, sizeof(pl));
1668145840Smlaier	pl.index = index;
1669145840Smlaier	pl.limit = limit;
1670145840Smlaier	if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1671145840Smlaier		if (errno == EBUSY)
1672145840Smlaier			warnx("Current pool size exceeds requested hard limit");
1673145840Smlaier		else
1674145840Smlaier			warnx("DIOCSETLIMIT");
1675145840Smlaier		return (1);
1676145840Smlaier	}
1677145840Smlaier	return (0);
1678145840Smlaier}
1679145840Smlaier
1680145840Smlaierint
1681126353Smlaierpfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1682126353Smlaier{
1683126353Smlaier	int i;
1684126353Smlaier
1685126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1686126353Smlaier		return (0);
1687126353Smlaier
1688126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1689126353Smlaier		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1690145840Smlaier			pf->timeout[pf_timeouts[i].timeout] = seconds;
1691145840Smlaier			pf->timeout_set[pf_timeouts[i].timeout] = 1;
1692126353Smlaier			break;
1693126353Smlaier		}
1694126353Smlaier	}
1695126353Smlaier
1696126353Smlaier	if (pf_timeouts[i].name == NULL) {
1697126353Smlaier		warnx("Bad timeout name.");
1698126353Smlaier		return (1);
1699126353Smlaier	}
1700126353Smlaier
1701126353Smlaier
1702126353Smlaier	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1703126353Smlaier		printf("set timeout %s %d\n", opt, seconds);
1704126353Smlaier
1705126353Smlaier	return (0);
1706126353Smlaier}
1707126353Smlaier
1708126353Smlaierint
1709145840Smlaierpfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1710145840Smlaier{
1711145840Smlaier	struct pfioc_tm pt;
1712145840Smlaier
1713145840Smlaier	memset(&pt, 0, sizeof(pt));
1714145840Smlaier	pt.timeout = timeout;
1715145840Smlaier	pt.seconds = seconds;
1716145840Smlaier	if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1717145840Smlaier		warnx("DIOCSETTIMEOUT");
1718145840Smlaier		return (1);
1719145840Smlaier	}
1720145840Smlaier	return (0);
1721145840Smlaier}
1722145840Smlaier
1723145840Smlaierint
1724126353Smlaierpfctl_set_optimization(struct pfctl *pf, const char *opt)
1725126353Smlaier{
1726126353Smlaier	const struct pf_hint *hint;
1727126353Smlaier	int i, r;
1728126353Smlaier
1729126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1730126353Smlaier		return (0);
1731126353Smlaier
1732126353Smlaier	for (i = 0; pf_hints[i].name; i++)
1733126353Smlaier		if (strcasecmp(opt, pf_hints[i].name) == 0)
1734126353Smlaier			break;
1735126353Smlaier
1736126353Smlaier	hint = pf_hints[i].hint;
1737126353Smlaier	if (hint == NULL) {
1738171172Smlaier		warnx("invalid state timeouts optimization");
1739126353Smlaier		return (1);
1740126353Smlaier	}
1741126353Smlaier
1742126353Smlaier	for (i = 0; hint[i].name; i++)
1743126353Smlaier		if ((r = pfctl_set_timeout(pf, hint[i].name,
1744126353Smlaier		    hint[i].timeout, 1)))
1745126353Smlaier			return (r);
1746126353Smlaier
1747126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1748126353Smlaier		printf("set optimization %s\n", opt);
1749126353Smlaier
1750126353Smlaier	return (0);
1751126353Smlaier}
1752126353Smlaier
1753126353Smlaierint
1754126353Smlaierpfctl_set_logif(struct pfctl *pf, char *ifname)
1755126353Smlaier{
1756126353Smlaier
1757126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1758126353Smlaier		return (0);
1759126353Smlaier
1760145840Smlaier	if (!strcmp(ifname, "none")) {
1761145840Smlaier		free(pf->ifname);
1762145840Smlaier		pf->ifname = NULL;
1763145840Smlaier	} else {
1764145840Smlaier		pf->ifname = strdup(ifname);
1765145840Smlaier		if (!pf->ifname)
1766145840Smlaier			errx(1, "pfctl_set_logif: strdup");
1767126353Smlaier	}
1768145840Smlaier	pf->ifname_set = 1;
1769126353Smlaier
1770126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1771126353Smlaier		printf("set loginterface %s\n", ifname);
1772126353Smlaier
1773126353Smlaier	return (0);
1774126353Smlaier}
1775126353Smlaier
1776126353Smlaierint
1777145840Smlaierpfctl_load_logif(struct pfctl *pf, char *ifname)
1778145840Smlaier{
1779145840Smlaier	struct pfioc_if pi;
1780145840Smlaier
1781145840Smlaier	memset(&pi, 0, sizeof(pi));
1782145840Smlaier	if (ifname && strlcpy(pi.ifname, ifname,
1783145840Smlaier	    sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1784171172Smlaier		warnx("pfctl_load_logif: strlcpy");
1785145840Smlaier		return (1);
1786145840Smlaier	}
1787145840Smlaier	if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1788145840Smlaier		warnx("DIOCSETSTATUSIF");
1789145840Smlaier		return (1);
1790145840Smlaier	}
1791145840Smlaier	return (0);
1792145840Smlaier}
1793145840Smlaier
1794145840Smlaierint
1795130617Smlaierpfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1796130617Smlaier{
1797130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1798130617Smlaier		return (0);
1799130617Smlaier
1800130617Smlaier	HTONL(hostid);
1801130617Smlaier
1802145840Smlaier	pf->hostid = hostid;
1803145840Smlaier	pf->hostid_set = 1;
1804130617Smlaier
1805130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1806130617Smlaier		printf("set hostid 0x%08x\n", ntohl(hostid));
1807130617Smlaier
1808130617Smlaier	return (0);
1809130617Smlaier}
1810130617Smlaier
1811130617Smlaierint
1812145840Smlaierpfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1813145840Smlaier{
1814145840Smlaier	if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1815145840Smlaier		warnx("DIOCSETHOSTID");
1816145840Smlaier		return (1);
1817145840Smlaier	}
1818145840Smlaier	return (0);
1819145840Smlaier}
1820145840Smlaier
1821145840Smlaierint
1822130617Smlaierpfctl_set_debug(struct pfctl *pf, char *d)
1823130617Smlaier{
1824130617Smlaier	u_int32_t	level;
1825130617Smlaier
1826130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1827130617Smlaier		return (0);
1828130617Smlaier
1829130617Smlaier	if (!strcmp(d, "none"))
1830145840Smlaier		pf->debug = PF_DEBUG_NONE;
1831130617Smlaier	else if (!strcmp(d, "urgent"))
1832145840Smlaier		pf->debug = PF_DEBUG_URGENT;
1833130617Smlaier	else if (!strcmp(d, "misc"))
1834145840Smlaier		pf->debug = PF_DEBUG_MISC;
1835130617Smlaier	else if (!strcmp(d, "loud"))
1836145840Smlaier		pf->debug = PF_DEBUG_NOISY;
1837130617Smlaier	else {
1838130617Smlaier		warnx("unknown debug level \"%s\"", d);
1839130617Smlaier		return (-1);
1840130617Smlaier	}
1841130617Smlaier
1842145840Smlaier	pf->debug_set = 1;
1843145840Smlaier
1844130617Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1845130617Smlaier		if (ioctl(dev, DIOCSETDEBUG, &level))
1846130617Smlaier			err(1, "DIOCSETDEBUG");
1847130617Smlaier
1848130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1849130617Smlaier		printf("set debug %s\n", d);
1850130617Smlaier
1851130617Smlaier	return (0);
1852130617Smlaier}
1853130617Smlaier
1854130617Smlaierint
1855145840Smlaierpfctl_load_debug(struct pfctl *pf, unsigned int level)
1856145840Smlaier{
1857145840Smlaier	if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1858145840Smlaier		warnx("DIOCSETDEBUG");
1859145840Smlaier		return (1);
1860145840Smlaier	}
1861145840Smlaier	return (0);
1862145840Smlaier}
1863145840Smlaier
1864145840Smlaierint
1865145840Smlaierpfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1866145840Smlaier{
1867145840Smlaier	struct pfioc_iface	pi;
1868145840Smlaier
1869145840Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1870145840Smlaier		return (0);
1871145840Smlaier
1872145840Smlaier	bzero(&pi, sizeof(pi));
1873145840Smlaier
1874145840Smlaier	pi.pfiio_flags = flags;
1875145840Smlaier
1876145840Smlaier	if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
1877145840Smlaier	    sizeof(pi.pfiio_name))
1878145840Smlaier		errx(1, "pfctl_set_interface_flags: strlcpy");
1879145840Smlaier
1880145840Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1881145840Smlaier		if (how == 0) {
1882145840Smlaier			if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
1883145840Smlaier				err(1, "DIOCCLRIFFLAG");
1884145840Smlaier		} else {
1885145840Smlaier			if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
1886145840Smlaier				err(1, "DIOCSETIFFLAG");
1887145840Smlaier		}
1888145840Smlaier	}
1889145840Smlaier	return (0);
1890145840Smlaier}
1891145840Smlaier
1892145840Smlaiervoid
1893126353Smlaierpfctl_debug(int dev, u_int32_t level, int opts)
1894126353Smlaier{
1895126353Smlaier	if (ioctl(dev, DIOCSETDEBUG, &level))
1896126353Smlaier		err(1, "DIOCSETDEBUG");
1897126353Smlaier	if ((opts & PF_OPT_QUIET) == 0) {
1898126353Smlaier		fprintf(stderr, "debug level set to '");
1899126353Smlaier		switch (level) {
1900126353Smlaier		case PF_DEBUG_NONE:
1901126353Smlaier			fprintf(stderr, "none");
1902126353Smlaier			break;
1903126353Smlaier		case PF_DEBUG_URGENT:
1904126353Smlaier			fprintf(stderr, "urgent");
1905126353Smlaier			break;
1906126353Smlaier		case PF_DEBUG_MISC:
1907126353Smlaier			fprintf(stderr, "misc");
1908126353Smlaier			break;
1909126353Smlaier		case PF_DEBUG_NOISY:
1910126353Smlaier			fprintf(stderr, "loud");
1911126353Smlaier			break;
1912126353Smlaier		default:
1913126353Smlaier			fprintf(stderr, "<invalid>");
1914126353Smlaier			break;
1915126353Smlaier		}
1916126353Smlaier		fprintf(stderr, "'\n");
1917126353Smlaier	}
1918126353Smlaier}
1919126353Smlaier
1920126353Smlaierint
1921126353Smlaierpfctl_test_altqsupport(int dev, int opts)
1922126353Smlaier{
1923126353Smlaier	struct pfioc_altq pa;
1924126353Smlaier
1925126353Smlaier	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1926126353Smlaier		if (errno == ENODEV) {
1927126353Smlaier			if (!(opts & PF_OPT_QUIET))
1928126353Smlaier				fprintf(stderr, "No ALTQ support in kernel\n"
1929126353Smlaier				    "ALTQ related functions disabled\n");
1930126353Smlaier			return (0);
1931126353Smlaier		} else
1932126353Smlaier			err(1, "DIOCGETALTQS");
1933126353Smlaier	}
1934126353Smlaier	return (1);
1935126353Smlaier}
1936126353Smlaier
1937126353Smlaierint
1938126353Smlaierpfctl_show_anchors(int dev, int opts, char *anchorname)
1939126353Smlaier{
1940145840Smlaier	struct pfioc_ruleset	 pr;
1941145840Smlaier	u_int32_t		 mnr, nr;
1942126353Smlaier
1943145840Smlaier	memset(&pr, 0, sizeof(pr));
1944145840Smlaier	memcpy(pr.path, anchorname, sizeof(pr.path));
1945145840Smlaier	if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1946145840Smlaier		if (errno == EINVAL)
1947145840Smlaier			fprintf(stderr, "Anchor '%s' not found.\n",
1948145840Smlaier			    anchorname);
1949145840Smlaier		else
1950145840Smlaier			err(1, "DIOCGETRULESETS");
1951145840Smlaier		return (-1);
1952145840Smlaier	}
1953145840Smlaier	mnr = pr.nr;
1954145840Smlaier	for (nr = 0; nr < mnr; ++nr) {
1955145840Smlaier		char sub[MAXPATHLEN];
1956126353Smlaier
1957145840Smlaier		pr.nr = nr;
1958145840Smlaier		if (ioctl(dev, DIOCGETRULESET, &pr))
1959145840Smlaier			err(1, "DIOCGETRULESET");
1960145840Smlaier		if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
1961145840Smlaier			continue;
1962145840Smlaier		sub[0] = 0;
1963145840Smlaier		if (pr.path[0]) {
1964145840Smlaier			strlcat(sub, pr.path, sizeof(sub));
1965145840Smlaier			strlcat(sub, "/", sizeof(sub));
1966126353Smlaier		}
1967145840Smlaier		strlcat(sub, pr.name, sizeof(sub));
1968171172Smlaier		if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
1969171172Smlaier			printf("  %s\n", sub);
1970171172Smlaier		if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
1971126353Smlaier			return (-1);
1972126353Smlaier	}
1973126353Smlaier	return (0);
1974126353Smlaier}
1975126353Smlaier
1976126353Smlaierconst char *
1977126353Smlaierpfctl_lookup_option(char *cmd, const char **list)
1978126353Smlaier{
1979126353Smlaier	if (cmd != NULL && *cmd)
1980126353Smlaier		for (; *list; list++)
1981126353Smlaier			if (!strncmp(cmd, *list, strlen(cmd)))
1982126353Smlaier				return (*list);
1983126353Smlaier	return (NULL);
1984126353Smlaier}
1985126353Smlaier
1986126353Smlaierint
1987126353Smlaiermain(int argc, char *argv[])
1988126353Smlaier{
1989171172Smlaier	int	 error = 0;
1990171172Smlaier	int	 ch;
1991171172Smlaier	int	 mode = O_RDONLY;
1992171172Smlaier	int	 opts = 0;
1993223637Sbz	int	 optimize = PF_OPTIMIZE_BASIC;
1994171172Smlaier	char	 anchorname[MAXPATHLEN];
1995171172Smlaier	char	*path;
1996126353Smlaier
1997126353Smlaier	if (argc < 2)
1998126353Smlaier		usage();
1999126353Smlaier
2000130617Smlaier	while ((ch = getopt(argc, argv,
2001223637Sbz	    "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
2002126353Smlaier		switch (ch) {
2003126353Smlaier		case 'a':
2004126353Smlaier			anchoropt = optarg;
2005126353Smlaier			break;
2006126353Smlaier		case 'd':
2007126353Smlaier			opts |= PF_OPT_DISABLE;
2008126353Smlaier			mode = O_RDWR;
2009126353Smlaier			break;
2010126353Smlaier		case 'D':
2011126353Smlaier			if (pfctl_cmdline_symset(optarg) < 0)
2012126353Smlaier				warnx("could not parse macro definition %s",
2013126353Smlaier				    optarg);
2014126353Smlaier			break;
2015126353Smlaier		case 'e':
2016126353Smlaier			opts |= PF_OPT_ENABLE;
2017126353Smlaier			mode = O_RDWR;
2018126353Smlaier			break;
2019126353Smlaier		case 'q':
2020126353Smlaier			opts |= PF_OPT_QUIET;
2021126353Smlaier			break;
2022126353Smlaier		case 'F':
2023126353Smlaier			clearopt = pfctl_lookup_option(optarg, clearopt_list);
2024126353Smlaier			if (clearopt == NULL) {
2025126353Smlaier				warnx("Unknown flush modifier '%s'", optarg);
2026126353Smlaier				usage();
2027126353Smlaier			}
2028126353Smlaier			mode = O_RDWR;
2029126353Smlaier			break;
2030130617Smlaier		case 'i':
2031130617Smlaier			ifaceopt = optarg;
2032130617Smlaier			break;
2033126353Smlaier		case 'k':
2034126353Smlaier			if (state_killers >= 2) {
2035126353Smlaier				warnx("can only specify -k twice");
2036126353Smlaier				usage();
2037126353Smlaier				/* NOTREACHED */
2038126353Smlaier			}
2039126353Smlaier			state_kill[state_killers++] = optarg;
2040126353Smlaier			mode = O_RDWR;
2041126353Smlaier			break;
2042171172Smlaier		case 'K':
2043171172Smlaier			if (src_node_killers >= 2) {
2044171172Smlaier				warnx("can only specify -K twice");
2045171172Smlaier				usage();
2046171172Smlaier				/* NOTREACHED */
2047171172Smlaier			}
2048171172Smlaier			src_node_kill[src_node_killers++] = optarg;
2049171172Smlaier			mode = O_RDWR;
2050171172Smlaier			break;
2051145840Smlaier		case 'm':
2052145840Smlaier			opts |= PF_OPT_MERGE;
2053145840Smlaier			break;
2054126353Smlaier		case 'n':
2055126353Smlaier			opts |= PF_OPT_NOACTION;
2056126353Smlaier			break;
2057126353Smlaier		case 'N':
2058126353Smlaier			loadopt |= PFCTL_FLAG_NAT;
2059126353Smlaier			break;
2060126353Smlaier		case 'r':
2061126353Smlaier			opts |= PF_OPT_USEDNS;
2062126353Smlaier			break;
2063126353Smlaier		case 'f':
2064126353Smlaier			rulesopt = optarg;
2065126353Smlaier			mode = O_RDWR;
2066126353Smlaier			break;
2067126353Smlaier		case 'g':
2068126353Smlaier			opts |= PF_OPT_DEBUG;
2069126353Smlaier			break;
2070126353Smlaier		case 'A':
2071126353Smlaier			loadopt |= PFCTL_FLAG_ALTQ;
2072126353Smlaier			break;
2073126353Smlaier		case 'R':
2074126353Smlaier			loadopt |= PFCTL_FLAG_FILTER;
2075126353Smlaier			break;
2076145840Smlaier		case 'o':
2077223637Sbz			optiopt = pfctl_lookup_option(optarg, optiopt_list);
2078223637Sbz			if (optiopt == NULL) {
2079223637Sbz				warnx("Unknown optimization '%s'", optarg);
2080223637Sbz				usage();
2081171172Smlaier			}
2082171172Smlaier			opts |= PF_OPT_OPTIMIZE;
2083145840Smlaier			break;
2084126353Smlaier		case 'O':
2085126353Smlaier			loadopt |= PFCTL_FLAG_OPTION;
2086126353Smlaier			break;
2087130617Smlaier		case 'p':
2088130617Smlaier			pf_device = optarg;
2089130617Smlaier			break;
2090223057Sbz		case 'P':
2091223057Sbz			opts |= PF_OPT_NUMERIC;
2092223057Sbz			break;
2093126353Smlaier		case 's':
2094126353Smlaier			showopt = pfctl_lookup_option(optarg, showopt_list);
2095126353Smlaier			if (showopt == NULL) {
2096126353Smlaier				warnx("Unknown show modifier '%s'", optarg);
2097126353Smlaier				usage();
2098126353Smlaier			}
2099126353Smlaier			break;
2100126353Smlaier		case 't':
2101126353Smlaier			tableopt = optarg;
2102126353Smlaier			break;
2103126353Smlaier		case 'T':
2104126353Smlaier			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
2105126353Smlaier			if (tblcmdopt == NULL) {
2106126353Smlaier				warnx("Unknown table command '%s'", optarg);
2107126353Smlaier				usage();
2108126353Smlaier			}
2109126353Smlaier			break;
2110126353Smlaier		case 'v':
2111126353Smlaier			if (opts & PF_OPT_VERBOSE)
2112126353Smlaier				opts |= PF_OPT_VERBOSE2;
2113126353Smlaier			opts |= PF_OPT_VERBOSE;
2114126353Smlaier			break;
2115126353Smlaier		case 'x':
2116126353Smlaier			debugopt = pfctl_lookup_option(optarg, debugopt_list);
2117126353Smlaier			if (debugopt == NULL) {
2118126353Smlaier				warnx("Unknown debug level '%s'", optarg);
2119126353Smlaier				usage();
2120126353Smlaier			}
2121126353Smlaier			mode = O_RDWR;
2122126353Smlaier			break;
2123126353Smlaier		case 'z':
2124126353Smlaier			opts |= PF_OPT_CLRRULECTRS;
2125126353Smlaier			mode = O_RDWR;
2126126353Smlaier			break;
2127126353Smlaier		case 'h':
2128126353Smlaier			/* FALLTHROUGH */
2129126353Smlaier		default:
2130126353Smlaier			usage();
2131126353Smlaier			/* NOTREACHED */
2132126353Smlaier		}
2133126353Smlaier	}
2134126353Smlaier
2135126353Smlaier	if (tblcmdopt != NULL) {
2136126353Smlaier		argc -= optind;
2137126353Smlaier		argv += optind;
2138126353Smlaier		ch = *tblcmdopt;
2139126353Smlaier		if (ch == 'l') {
2140126353Smlaier			loadopt |= PFCTL_FLAG_TABLE;
2141126353Smlaier			tblcmdopt = NULL;
2142130617Smlaier		} else
2143171172Smlaier			mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
2144126353Smlaier	} else if (argc != optind) {
2145126353Smlaier		warnx("unknown command line argument: %s ...", argv[optind]);
2146126353Smlaier		usage();
2147126353Smlaier		/* NOTREACHED */
2148126353Smlaier	}
2149126353Smlaier	if (loadopt == 0)
2150126353Smlaier		loadopt = ~0;
2151126353Smlaier
2152171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
2153171172Smlaier		errx(1, "pfctl: calloc");
2154126353Smlaier	memset(anchorname, 0, sizeof(anchorname));
2155126353Smlaier	if (anchoropt != NULL) {
2156171172Smlaier		int len = strlen(anchoropt);
2157171172Smlaier
2158171172Smlaier		if (anchoropt[len - 1] == '*') {
2159171172Smlaier			if (len >= 2 && anchoropt[len - 2] == '/')
2160171172Smlaier				anchoropt[len - 2] = '\0';
2161171172Smlaier			else
2162171172Smlaier				anchoropt[len - 1] = '\0';
2163171172Smlaier			opts |= PF_OPT_RECURSE;
2164171172Smlaier		}
2165145840Smlaier		if (strlcpy(anchorname, anchoropt,
2166145840Smlaier		    sizeof(anchorname)) >= sizeof(anchorname))
2167145840Smlaier			errx(1, "anchor name '%s' too long",
2168145840Smlaier			    anchoropt);
2169126353Smlaier		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
2170126353Smlaier	}
2171126353Smlaier
2172126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
2173130617Smlaier		dev = open(pf_device, mode);
2174126353Smlaier		if (dev == -1)
2175130617Smlaier			err(1, "%s", pf_device);
2176126353Smlaier		altqsupport = pfctl_test_altqsupport(dev, opts);
2177126353Smlaier	} else {
2178130617Smlaier		dev = open(pf_device, O_RDONLY);
2179130617Smlaier		if (dev >= 0)
2180130617Smlaier			opts |= PF_OPT_DUMMYACTION;
2181126353Smlaier		/* turn off options */
2182126353Smlaier		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
2183126353Smlaier		clearopt = showopt = debugopt = NULL;
2184258485Sglebius#if !defined(ENABLE_ALTQ)
2185126355Smlaier		altqsupport = 0;
2186126355Smlaier#else
2187126353Smlaier		altqsupport = 1;
2188126355Smlaier#endif
2189126353Smlaier	}
2190126353Smlaier
2191126353Smlaier	if (opts & PF_OPT_DISABLE)
2192126353Smlaier		if (pfctl_disable(dev, opts))
2193126353Smlaier			error = 1;
2194126353Smlaier
2195126353Smlaier	if (showopt != NULL) {
2196126353Smlaier		switch (*showopt) {
2197126353Smlaier		case 'A':
2198126353Smlaier			pfctl_show_anchors(dev, opts, anchorname);
2199126353Smlaier			break;
2200126353Smlaier		case 'r':
2201126353Smlaier			pfctl_load_fingerprints(dev, opts);
2202171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
2203171172Smlaier			    anchorname, 0);
2204126353Smlaier			break;
2205126353Smlaier		case 'l':
2206126353Smlaier			pfctl_load_fingerprints(dev, opts);
2207171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
2208171172Smlaier			    anchorname, 0);
2209126353Smlaier			break;
2210126353Smlaier		case 'n':
2211126353Smlaier			pfctl_load_fingerprints(dev, opts);
2212145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2213126353Smlaier			break;
2214126353Smlaier		case 'q':
2215130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts,
2216130617Smlaier			    opts & PF_OPT_VERBOSE2);
2217126353Smlaier			break;
2218126353Smlaier		case 's':
2219130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2220126353Smlaier			break;
2221130617Smlaier		case 'S':
2222130617Smlaier			pfctl_show_src_nodes(dev, opts);
2223130617Smlaier			break;
2224126353Smlaier		case 'i':
2225130617Smlaier			pfctl_show_status(dev, opts);
2226126353Smlaier			break;
2227126353Smlaier		case 't':
2228130617Smlaier			pfctl_show_timeouts(dev, opts);
2229126353Smlaier			break;
2230126353Smlaier		case 'm':
2231130617Smlaier			pfctl_show_limits(dev, opts);
2232126353Smlaier			break;
2233126353Smlaier		case 'a':
2234130617Smlaier			opts |= PF_OPT_SHOWALL;
2235126353Smlaier			pfctl_load_fingerprints(dev, opts);
2236126353Smlaier
2237145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2238171172Smlaier			pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
2239130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts, 0);
2240130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2241130617Smlaier			pfctl_show_src_nodes(dev, opts);
2242130617Smlaier			pfctl_show_status(dev, opts);
2243171172Smlaier			pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
2244130617Smlaier			pfctl_show_timeouts(dev, opts);
2245130617Smlaier			pfctl_show_limits(dev, opts);
2246145840Smlaier			pfctl_show_tables(anchorname, opts);
2247126353Smlaier			pfctl_show_fingerprints(opts);
2248126353Smlaier			break;
2249126353Smlaier		case 'T':
2250145840Smlaier			pfctl_show_tables(anchorname, opts);
2251126353Smlaier			break;
2252126353Smlaier		case 'o':
2253126353Smlaier			pfctl_load_fingerprints(dev, opts);
2254126353Smlaier			pfctl_show_fingerprints(opts);
2255126353Smlaier			break;
2256130617Smlaier		case 'I':
2257130617Smlaier			pfctl_show_ifaces(ifaceopt, opts);
2258130617Smlaier			break;
2259126353Smlaier		}
2260126353Smlaier	}
2261126353Smlaier
2262171172Smlaier	if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
2263171172Smlaier		pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
2264171172Smlaier		    anchorname, 0);
2265171172Smlaier
2266126353Smlaier	if (clearopt != NULL) {
2267171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2268171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2269171172Smlaier			    "be modified from the command line");
2270171172Smlaier
2271126353Smlaier		switch (*clearopt) {
2272126353Smlaier		case 'r':
2273145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2274126353Smlaier			break;
2275126353Smlaier		case 'n':
2276145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2277126353Smlaier			break;
2278126353Smlaier		case 'q':
2279126353Smlaier			pfctl_clear_altq(dev, opts);
2280126353Smlaier			break;
2281126353Smlaier		case 's':
2282130617Smlaier			pfctl_clear_states(dev, ifaceopt, opts);
2283126353Smlaier			break;
2284130617Smlaier		case 'S':
2285130617Smlaier			pfctl_clear_src_nodes(dev, opts);
2286130617Smlaier			break;
2287126353Smlaier		case 'i':
2288126353Smlaier			pfctl_clear_stats(dev, opts);
2289126353Smlaier			break;
2290126353Smlaier		case 'a':
2291145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2292145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2293145840Smlaier			pfctl_clear_tables(anchorname, opts);
2294145840Smlaier			if (!*anchorname) {
2295130617Smlaier				pfctl_clear_altq(dev, opts);
2296130617Smlaier				pfctl_clear_states(dev, ifaceopt, opts);
2297130617Smlaier				pfctl_clear_src_nodes(dev, opts);
2298130617Smlaier				pfctl_clear_stats(dev, opts);
2299130617Smlaier				pfctl_clear_fingerprints(dev, opts);
2300145840Smlaier				pfctl_clear_interface_flags(dev, opts);
2301130617Smlaier			}
2302126353Smlaier			break;
2303126353Smlaier		case 'o':
2304126353Smlaier			pfctl_clear_fingerprints(dev, opts);
2305126353Smlaier			break;
2306126353Smlaier		case 'T':
2307145840Smlaier			pfctl_clear_tables(anchorname, opts);
2308126353Smlaier			break;
2309126353Smlaier		}
2310126353Smlaier	}
2311223637Sbz	if (state_killers) {
2312223637Sbz		if (!strcmp(state_kill[0], "label"))
2313223637Sbz			pfctl_label_kill_states(dev, ifaceopt, opts);
2314223637Sbz		else if (!strcmp(state_kill[0], "id"))
2315223637Sbz			pfctl_id_kill_states(dev, ifaceopt, opts);
2316223637Sbz		else
2317223637Sbz			pfctl_net_kill_states(dev, ifaceopt, opts);
2318223637Sbz	}
2319126353Smlaier
2320171172Smlaier	if (src_node_killers)
2321171172Smlaier		pfctl_kill_src_nodes(dev, ifaceopt, opts);
2322171172Smlaier
2323126353Smlaier	if (tblcmdopt != NULL) {
2324126353Smlaier		error = pfctl_command_tables(argc, argv, tableopt,
2325145840Smlaier		    tblcmdopt, rulesopt, anchorname, opts);
2326126353Smlaier		rulesopt = NULL;
2327126353Smlaier	}
2328171172Smlaier	if (optiopt != NULL) {
2329171172Smlaier		switch (*optiopt) {
2330171172Smlaier		case 'n':
2331171172Smlaier			optimize = 0;
2332171172Smlaier			break;
2333171172Smlaier		case 'b':
2334171172Smlaier			optimize |= PF_OPTIMIZE_BASIC;
2335171172Smlaier			break;
2336171172Smlaier		case 'o':
2337171172Smlaier		case 'p':
2338171172Smlaier			optimize |= PF_OPTIMIZE_PROFILE;
2339171172Smlaier			break;
2340171172Smlaier		}
2341171172Smlaier	}
2342126353Smlaier
2343171172Smlaier	if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
2344171172Smlaier	    !anchorname[0])
2345145840Smlaier		if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
2346145840Smlaier			error = 1;
2347145840Smlaier
2348145840Smlaier	if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
2349145840Smlaier	    !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
2350126353Smlaier		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
2351126353Smlaier			error = 1;
2352126353Smlaier
2353126353Smlaier	if (rulesopt != NULL) {
2354171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2355171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2356171172Smlaier			    "be modified from the command line");
2357223637Sbz		if (pfctl_rules(dev, rulesopt, opts, optimize,
2358171172Smlaier		    anchorname, NULL))
2359126353Smlaier			error = 1;
2360126353Smlaier		else if (!(opts & PF_OPT_NOACTION) &&
2361126353Smlaier		    (loadopt & PFCTL_FLAG_TABLE))
2362126353Smlaier			warn_namespace_collision(NULL);
2363126353Smlaier	}
2364126353Smlaier
2365126353Smlaier	if (opts & PF_OPT_ENABLE)
2366126353Smlaier		if (pfctl_enable(dev, opts))
2367126353Smlaier			error = 1;
2368126353Smlaier
2369126353Smlaier	if (debugopt != NULL) {
2370126353Smlaier		switch (*debugopt) {
2371126353Smlaier		case 'n':
2372126353Smlaier			pfctl_debug(dev, PF_DEBUG_NONE, opts);
2373126353Smlaier			break;
2374126353Smlaier		case 'u':
2375126353Smlaier			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
2376126353Smlaier			break;
2377126353Smlaier		case 'm':
2378126353Smlaier			pfctl_debug(dev, PF_DEBUG_MISC, opts);
2379126353Smlaier			break;
2380126353Smlaier		case 'l':
2381126353Smlaier			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
2382126353Smlaier			break;
2383126353Smlaier		}
2384126353Smlaier	}
2385126353Smlaier
2386126353Smlaier	exit(error);
2387126353Smlaier}
2388