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: releng/10.3/sbin/pfctl/pfctl.c 296370 2016-03-03 23:25:31Z gnn $");
36127082Sobrien
37126353Smlaier#include <sys/types.h>
38126353Smlaier#include <sys/ioctl.h>
39126353Smlaier#include <sys/socket.h>
40145840Smlaier#include <sys/stat.h>
41126353Smlaier
42223637Sbz#ifdef __FreeBSD__
43223637Sbz#include <sys/endian.h>
44223637Sbz#endif
45223637Sbz
46126353Smlaier#include <net/if.h>
47126353Smlaier#include <netinet/in.h>
48126353Smlaier#include <net/pfvar.h>
49126353Smlaier#include <arpa/inet.h>
50126353Smlaier#include <altq/altq.h>
51171172Smlaier#include <sys/sysctl.h>
52126353Smlaier
53126353Smlaier#include <err.h>
54126353Smlaier#include <errno.h>
55126353Smlaier#include <fcntl.h>
56126353Smlaier#include <limits.h>
57126353Smlaier#include <netdb.h>
58263029Sglebius#include <stdint.h>
59126353Smlaier#include <stdio.h>
60126353Smlaier#include <stdlib.h>
61126353Smlaier#include <string.h>
62126353Smlaier#include <unistd.h>
63126353Smlaier
64126353Smlaier#include "pfctl_parser.h"
65126353Smlaier#include "pfctl.h"
66126353Smlaier
67126353Smlaiervoid	 usage(void);
68126353Smlaierint	 pfctl_enable(int, int);
69126353Smlaierint	 pfctl_disable(int, int);
70126353Smlaierint	 pfctl_clear_stats(int, int);
71145840Smlaierint	 pfctl_clear_interface_flags(int, int);
72145840Smlaierint	 pfctl_clear_rules(int, int, char *);
73145840Smlaierint	 pfctl_clear_nat(int, int, char *);
74126353Smlaierint	 pfctl_clear_altq(int, int);
75130617Smlaierint	 pfctl_clear_src_nodes(int, int);
76130617Smlaierint	 pfctl_clear_states(int, const char *, int);
77171172Smlaiervoid	 pfctl_addrprefix(char *, struct pf_addr *);
78171172Smlaierint	 pfctl_kill_src_nodes(int, const char *, int);
79223637Sbzint	 pfctl_net_kill_states(int, const char *, int);
80223637Sbzint	 pfctl_label_kill_states(int, const char *, int);
81223637Sbzint	 pfctl_id_kill_states(int, const char *, int);
82145840Smlaiervoid	 pfctl_init_options(struct pfctl *);
83145840Smlaierint	 pfctl_load_options(struct pfctl *);
84145840Smlaierint	 pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
85145840Smlaierint	 pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
86145840Smlaierint	 pfctl_load_debug(struct pfctl *, unsigned int);
87145840Smlaierint	 pfctl_load_logif(struct pfctl *, char *);
88145840Smlaierint	 pfctl_load_hostid(struct pfctl *, unsigned int);
89126353Smlaierint	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
90145840Smlaier	    char *);
91126353Smlaiervoid	 pfctl_print_rule_counters(struct pf_rule *, int);
92171172Smlaierint	 pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
93145840Smlaierint	 pfctl_show_nat(int, int, char *);
94130617Smlaierint	 pfctl_show_src_nodes(int, int);
95130617Smlaierint	 pfctl_show_states(int, const char *, int);
96130617Smlaierint	 pfctl_show_status(int, int);
97130617Smlaierint	 pfctl_show_timeouts(int, int);
98130617Smlaierint	 pfctl_show_limits(int, int);
99145840Smlaiervoid	 pfctl_debug(int, u_int32_t, int);
100126353Smlaierint	 pfctl_test_altqsupport(int, int);
101126353Smlaierint	 pfctl_show_anchors(int, int, char *);
102171172Smlaierint	 pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
103171172Smlaierint	 pfctl_load_ruleset(struct pfctl *, char *,
104171172Smlaier		struct pf_ruleset *, int, int);
105171172Smlaierint	 pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
106126353Smlaierconst char	*pfctl_lookup_option(char *, const char **);
107126353Smlaier
108171172Smlaierstruct pf_anchor_global	 pf_anchors;
109171172Smlaierstruct pf_anchor	 pf_main_anchor;
110171172Smlaier
111126353Smlaierconst char	*clearopt;
112126353Smlaierchar		*rulesopt;
113126353Smlaierconst char	*showopt;
114126353Smlaierconst char	*debugopt;
115126353Smlaierchar		*anchoropt;
116171172Smlaierconst char	*optiopt = NULL;
117130617Smlaierchar		*pf_device = "/dev/pf";
118130617Smlaierchar		*ifaceopt;
119126353Smlaierchar		*tableopt;
120126353Smlaierconst char	*tblcmdopt;
121171172Smlaierint		 src_node_killers;
122171172Smlaierchar		*src_node_kill[2];
123126353Smlaierint		 state_killers;
124126353Smlaierchar		*state_kill[2];
125126353Smlaierint		 loadopt;
126126353Smlaierint		 altqsupport;
127126353Smlaier
128126353Smlaierint		 dev = -1;
129130617Smlaierint		 first_title = 1;
130130617Smlaierint		 labels = 0;
131126353Smlaier
132171172Smlaier#define INDENT(d, o)	do {						\
133171172Smlaier				if (o) {				\
134171172Smlaier					int i;				\
135171172Smlaier					for (i=0; i < d; i++)		\
136171172Smlaier						printf("  ");		\
137171172Smlaier				}					\
138171172Smlaier			} while (0);					\
139171172Smlaier
140171172Smlaier
141126353Smlaierstatic const struct {
142126353Smlaier	const char	*name;
143126353Smlaier	int		index;
144126353Smlaier} pf_limits[] = {
145171172Smlaier	{ "states",		PF_LIMIT_STATES },
146171172Smlaier	{ "src-nodes",		PF_LIMIT_SRC_NODES },
147171172Smlaier	{ "frags",		PF_LIMIT_FRAGS },
148171172Smlaier	{ "table-entries",	PF_LIMIT_TABLE_ENTRIES },
149171172Smlaier	{ NULL,			0 }
150126353Smlaier};
151126353Smlaier
152126353Smlaierstruct pf_hint {
153126353Smlaier	const char	*name;
154126353Smlaier	int		timeout;
155126353Smlaier};
156126353Smlaierstatic const struct pf_hint pf_hint_normal[] = {
157126353Smlaier	{ "tcp.first",		2 * 60 },
158126353Smlaier	{ "tcp.opening",	30 },
159126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
160126353Smlaier	{ "tcp.closing",	15 * 60 },
161126353Smlaier	{ "tcp.finwait",	45 },
162126353Smlaier	{ "tcp.closed",		90 },
163145840Smlaier	{ "tcp.tsdiff",		30 },
164126353Smlaier	{ NULL,			0 }
165126353Smlaier};
166126353Smlaierstatic const struct pf_hint pf_hint_satellite[] = {
167126353Smlaier	{ "tcp.first",		3 * 60 },
168126353Smlaier	{ "tcp.opening",	30 + 5 },
169126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
170126353Smlaier	{ "tcp.closing",	15 * 60 + 5 },
171126353Smlaier	{ "tcp.finwait",	45 + 5 },
172126353Smlaier	{ "tcp.closed",		90 + 5 },
173145840Smlaier	{ "tcp.tsdiff",		60 },
174126353Smlaier	{ NULL,			0 }
175126353Smlaier};
176126353Smlaierstatic const struct pf_hint pf_hint_conservative[] = {
177126353Smlaier	{ "tcp.first",		60 * 60 },
178126353Smlaier	{ "tcp.opening",	15 * 60 },
179126353Smlaier	{ "tcp.established",	5 * 24 * 60 * 60 },
180126353Smlaier	{ "tcp.closing",	60 * 60 },
181126353Smlaier	{ "tcp.finwait",	10 * 60 },
182126353Smlaier	{ "tcp.closed",		3 * 60 },
183145840Smlaier	{ "tcp.tsdiff",		60 },
184126353Smlaier	{ NULL,			0 }
185126353Smlaier};
186126353Smlaierstatic const struct pf_hint pf_hint_aggressive[] = {
187126353Smlaier	{ "tcp.first",		30 },
188126353Smlaier	{ "tcp.opening",	5 },
189126353Smlaier	{ "tcp.established",	5 * 60 * 60 },
190126353Smlaier	{ "tcp.closing",	60 },
191126353Smlaier	{ "tcp.finwait",	30 },
192126353Smlaier	{ "tcp.closed",		30 },
193145840Smlaier	{ "tcp.tsdiff",		10 },
194126353Smlaier	{ NULL,			0 }
195126353Smlaier};
196126353Smlaier
197126353Smlaierstatic const struct {
198126353Smlaier	const char *name;
199126353Smlaier	const struct pf_hint *hint;
200126353Smlaier} pf_hints[] = {
201126353Smlaier	{ "normal",		pf_hint_normal },
202126353Smlaier	{ "satellite",		pf_hint_satellite },
203126353Smlaier	{ "high-latency",	pf_hint_satellite },
204126353Smlaier	{ "conservative",	pf_hint_conservative },
205126353Smlaier	{ "aggressive",		pf_hint_aggressive },
206126353Smlaier	{ NULL,			NULL }
207126353Smlaier};
208126353Smlaier
209126353Smlaierstatic const char *clearopt_list[] = {
210130617Smlaier	"nat", "queue", "rules", "Sources",
211223637Sbz	"states", "info", "Tables", "osfp", "all", NULL
212126353Smlaier};
213126353Smlaier
214126353Smlaierstatic const char *showopt_list[] = {
215223637Sbz	"nat", "queue", "rules", "Anchors", "Sources", "states", "info",
216130617Smlaier	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
217130617Smlaier	"all", NULL
218126353Smlaier};
219126353Smlaier
220126353Smlaierstatic const char *tblcmdopt_list[] = {
221126353Smlaier	"kill", "flush", "add", "delete", "load", "replace", "show",
222171172Smlaier	"test", "zero", "expire", NULL
223126353Smlaier};
224126353Smlaier
225126353Smlaierstatic const char *debugopt_list[] = {
226126353Smlaier	"none", "urgent", "misc", "loud", NULL
227126353Smlaier};
228126353Smlaier
229171172Smlaierstatic const char *optiopt_list[] = {
230223637Sbz	"none", "basic", "profile", NULL
231171172Smlaier};
232126353Smlaier
233126353Smlaiervoid
234126353Smlaierusage(void)
235126353Smlaier{
236126353Smlaier	extern char *__progname;
237126353Smlaier
238223057Sbz	fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] ", __progname);
239145840Smlaier	fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
240223637Sbz	fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n");
241223637Sbz	fprintf(stderr, "\t[-k host | network | label | id] ");
242223637Sbz	fprintf(stderr, "[-o level] [-p device]\n");
243223637Sbz	fprintf(stderr, "\t[-s modifier] ");
244223637Sbz	fprintf(stderr, "[-t table -T command [address ...]] [-x level]\n");
245126353Smlaier	exit(1);
246126353Smlaier}
247126353Smlaier
248126353Smlaierint
249126353Smlaierpfctl_enable(int dev, int opts)
250126353Smlaier{
251126353Smlaier	if (ioctl(dev, DIOCSTART)) {
252126353Smlaier		if (errno == EEXIST)
253126353Smlaier			errx(1, "pf already enabled");
254127024Smlaier#ifdef __FreeBSD__
255126355Smlaier		else if (errno == ESRCH)
256126355Smlaier			errx(1, "pfil registeration failed");
257126355Smlaier#endif
258126353Smlaier		else
259126353Smlaier			err(1, "DIOCSTART");
260126353Smlaier	}
261126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
262126353Smlaier		fprintf(stderr, "pf enabled\n");
263126353Smlaier
264126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
265126353Smlaier		if (errno != EEXIST)
266126353Smlaier			err(1, "DIOCSTARTALTQ");
267126353Smlaier
268126353Smlaier	return (0);
269126353Smlaier}
270126353Smlaier
271126353Smlaierint
272126353Smlaierpfctl_disable(int dev, int opts)
273126353Smlaier{
274126353Smlaier	if (ioctl(dev, DIOCSTOP)) {
275126353Smlaier		if (errno == ENOENT)
276126353Smlaier			errx(1, "pf not enabled");
277126353Smlaier		else
278126353Smlaier			err(1, "DIOCSTOP");
279126353Smlaier	}
280126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
281126353Smlaier		fprintf(stderr, "pf disabled\n");
282126353Smlaier
283126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
284126353Smlaier			if (errno != ENOENT)
285126353Smlaier				err(1, "DIOCSTOPALTQ");
286126353Smlaier
287126353Smlaier	return (0);
288126353Smlaier}
289126353Smlaier
290126353Smlaierint
291126353Smlaierpfctl_clear_stats(int dev, int opts)
292126353Smlaier{
293126353Smlaier	if (ioctl(dev, DIOCCLRSTATUS))
294126353Smlaier		err(1, "DIOCCLRSTATUS");
295126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
296126353Smlaier		fprintf(stderr, "pf: statistics cleared\n");
297126353Smlaier	return (0);
298126353Smlaier}
299126353Smlaier
300126353Smlaierint
301145840Smlaierpfctl_clear_interface_flags(int dev, int opts)
302126353Smlaier{
303145840Smlaier	struct pfioc_iface	pi;
304126353Smlaier
305145840Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
306145840Smlaier		bzero(&pi, sizeof(pi));
307171172Smlaier		pi.pfiio_flags = PFI_IFLAG_SKIP;
308126353Smlaier
309145840Smlaier		if (ioctl(dev, DIOCCLRIFFLAG, &pi))
310145840Smlaier			err(1, "DIOCCLRIFFLAG");
311126353Smlaier		if ((opts & PF_OPT_QUIET) == 0)
312145840Smlaier			fprintf(stderr, "pf: interface flags reset\n");
313126353Smlaier	}
314145840Smlaier	return (0);
315145840Smlaier}
316145840Smlaier
317145840Smlaierint
318145840Smlaierpfctl_clear_rules(int dev, int opts, char *anchorname)
319145840Smlaier{
320145840Smlaier	struct pfr_buffer t;
321145840Smlaier
322130617Smlaier	memset(&t, 0, sizeof(t));
323130617Smlaier	t.pfrb_type = PFRB_TRANS;
324145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
325145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
326130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
327130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
328130617Smlaier		err(1, "pfctl_clear_rules");
329126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
330126353Smlaier		fprintf(stderr, "rules cleared\n");
331126353Smlaier	return (0);
332126353Smlaier}
333126353Smlaier
334126353Smlaierint
335145840Smlaierpfctl_clear_nat(int dev, int opts, char *anchorname)
336126353Smlaier{
337130617Smlaier	struct pfr_buffer t;
338126353Smlaier
339130617Smlaier	memset(&t, 0, sizeof(t));
340130617Smlaier	t.pfrb_type = PFRB_TRANS;
341145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
342145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
343145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
344130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
345130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
346130617Smlaier		err(1, "pfctl_clear_nat");
347126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
348126353Smlaier		fprintf(stderr, "nat cleared\n");
349126353Smlaier	return (0);
350126353Smlaier}
351126353Smlaier
352126353Smlaierint
353126353Smlaierpfctl_clear_altq(int dev, int opts)
354126353Smlaier{
355130617Smlaier	struct pfr_buffer t;
356126353Smlaier
357126353Smlaier	if (!altqsupport)
358126353Smlaier		return (-1);
359130617Smlaier	memset(&t, 0, sizeof(t));
360130617Smlaier	t.pfrb_type = PFRB_TRANS;
361145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
362130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
363130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
364130617Smlaier		err(1, "pfctl_clear_altq");
365126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
366126353Smlaier		fprintf(stderr, "altq cleared\n");
367126353Smlaier	return (0);
368126353Smlaier}
369126353Smlaier
370126353Smlaierint
371130617Smlaierpfctl_clear_src_nodes(int dev, int opts)
372126353Smlaier{
373130617Smlaier	if (ioctl(dev, DIOCCLRSRCNODES))
374130617Smlaier		err(1, "DIOCCLRSRCNODES");
375130617Smlaier	if ((opts & PF_OPT_QUIET) == 0)
376130617Smlaier		fprintf(stderr, "source tracking entries cleared\n");
377130617Smlaier	return (0);
378130617Smlaier}
379130617Smlaier
380130617Smlaierint
381130617Smlaierpfctl_clear_states(int dev, const char *iface, int opts)
382130617Smlaier{
383130617Smlaier	struct pfioc_state_kill psk;
384130617Smlaier
385130617Smlaier	memset(&psk, 0, sizeof(psk));
386130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
387130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
388130617Smlaier		errx(1, "invalid interface: %s", iface);
389130617Smlaier
390130617Smlaier	if (ioctl(dev, DIOCCLRSTATES, &psk))
391126353Smlaier		err(1, "DIOCCLRSTATES");
392126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
393223637Sbz		fprintf(stderr, "%d states cleared\n", psk.psk_killed);
394126353Smlaier	return (0);
395126353Smlaier}
396126353Smlaier
397171172Smlaiervoid
398171172Smlaierpfctl_addrprefix(char *addr, struct pf_addr *mask)
399171172Smlaier{
400171172Smlaier	char *p;
401171172Smlaier	const char *errstr;
402171172Smlaier	int prefix, ret_ga, q, r;
403171172Smlaier	struct addrinfo hints, *res;
404171172Smlaier
405171172Smlaier	if ((p = strchr(addr, '/')) == NULL)
406171172Smlaier		return;
407171172Smlaier
408171172Smlaier	*p++ = '\0';
409171172Smlaier	prefix = strtonum(p, 0, 128, &errstr);
410171172Smlaier	if (errstr)
411171172Smlaier		errx(1, "prefix is %s: %s", errstr, p);
412171172Smlaier
413171172Smlaier	bzero(&hints, sizeof(hints));
414171172Smlaier	/* prefix only with numeric addresses */
415171172Smlaier	hints.ai_flags |= AI_NUMERICHOST;
416171172Smlaier
417171172Smlaier	if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
418171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
419171172Smlaier		/* NOTREACHED */
420171172Smlaier	}
421171172Smlaier
422171172Smlaier	if (res->ai_family == AF_INET && prefix > 32)
423171172Smlaier		errx(1, "prefix too long for AF_INET");
424171172Smlaier	else if (res->ai_family == AF_INET6 && prefix > 128)
425171172Smlaier		errx(1, "prefix too long for AF_INET6");
426171172Smlaier
427171172Smlaier	q = prefix >> 3;
428171172Smlaier	r = prefix & 7;
429171172Smlaier	switch (res->ai_family) {
430171172Smlaier	case AF_INET:
431171172Smlaier		bzero(&mask->v4, sizeof(mask->v4));
432171172Smlaier		mask->v4.s_addr = htonl((u_int32_t)
433171172Smlaier		    (0xffffffffffULL << (32 - prefix)));
434171172Smlaier		break;
435171172Smlaier	case AF_INET6:
436171172Smlaier		bzero(&mask->v6, sizeof(mask->v6));
437171172Smlaier		if (q > 0)
438171172Smlaier			memset((void *)&mask->v6, 0xff, q);
439171172Smlaier		if (r > 0)
440171172Smlaier			*((u_char *)&mask->v6 + q) =
441171172Smlaier			    (0xff00 >> r) & 0xff;
442171172Smlaier		break;
443171172Smlaier	}
444171172Smlaier	freeaddrinfo(res);
445171172Smlaier}
446171172Smlaier
447126353Smlaierint
448171172Smlaierpfctl_kill_src_nodes(int dev, const char *iface, int opts)
449171172Smlaier{
450171172Smlaier	struct pfioc_src_node_kill psnk;
451171172Smlaier	struct addrinfo *res[2], *resp[2];
452171172Smlaier	struct sockaddr last_src, last_dst;
453171172Smlaier	int killed, sources, dests;
454171172Smlaier	int ret_ga;
455171172Smlaier
456171172Smlaier	killed = sources = dests = 0;
457171172Smlaier
458171172Smlaier	memset(&psnk, 0, sizeof(psnk));
459171172Smlaier	memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
460171172Smlaier	    sizeof(psnk.psnk_src.addr.v.a.mask));
461171172Smlaier	memset(&last_src, 0xff, sizeof(last_src));
462171172Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
463171172Smlaier
464171172Smlaier	pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
465171172Smlaier
466171172Smlaier	if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
467171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
468171172Smlaier		/* NOTREACHED */
469171172Smlaier	}
470171172Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
471171172Smlaier		if (resp[0]->ai_addr == NULL)
472171172Smlaier			continue;
473171172Smlaier		/* We get lots of duplicates.  Catch the easy ones */
474171172Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
475171172Smlaier			continue;
476171172Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
477171172Smlaier
478171172Smlaier		psnk.psnk_af = resp[0]->ai_family;
479171172Smlaier		sources++;
480171172Smlaier
481171172Smlaier		if (psnk.psnk_af == AF_INET)
482171172Smlaier			psnk.psnk_src.addr.v.a.addr.v4 =
483171172Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
484171172Smlaier		else if (psnk.psnk_af == AF_INET6)
485171172Smlaier			psnk.psnk_src.addr.v.a.addr.v6 =
486171172Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
487171172Smlaier			    sin6_addr;
488171172Smlaier		else
489171172Smlaier			errx(1, "Unknown address family %d", psnk.psnk_af);
490171172Smlaier
491171172Smlaier		if (src_node_killers > 1) {
492171172Smlaier			dests = 0;
493171172Smlaier			memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
494171172Smlaier			    sizeof(psnk.psnk_dst.addr.v.a.mask));
495171172Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
496171172Smlaier			pfctl_addrprefix(src_node_kill[1],
497171172Smlaier			    &psnk.psnk_dst.addr.v.a.mask);
498171172Smlaier			if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
499171172Smlaier			    &res[1]))) {
500171172Smlaier				errx(1, "getaddrinfo: %s",
501171172Smlaier				    gai_strerror(ret_ga));
502171172Smlaier				/* NOTREACHED */
503171172Smlaier			}
504171172Smlaier			for (resp[1] = res[1]; resp[1];
505171172Smlaier			    resp[1] = resp[1]->ai_next) {
506171172Smlaier				if (resp[1]->ai_addr == NULL)
507171172Smlaier					continue;
508171172Smlaier				if (psnk.psnk_af != resp[1]->ai_family)
509171172Smlaier					continue;
510171172Smlaier
511171172Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
512171172Smlaier				    sizeof(last_dst)) == 0)
513171172Smlaier					continue;
514171172Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
515171172Smlaier
516171172Smlaier				dests++;
517171172Smlaier
518171172Smlaier				if (psnk.psnk_af == AF_INET)
519171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v4 =
520171172Smlaier					    ((struct sockaddr_in *)resp[1]->
521171172Smlaier					    ai_addr)->sin_addr;
522171172Smlaier				else if (psnk.psnk_af == AF_INET6)
523171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v6 =
524171172Smlaier					    ((struct sockaddr_in6 *)resp[1]->
525171172Smlaier					    ai_addr)->sin6_addr;
526171172Smlaier				else
527171172Smlaier					errx(1, "Unknown address family %d",
528171172Smlaier					    psnk.psnk_af);
529171172Smlaier
530171172Smlaier				if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
531171172Smlaier					err(1, "DIOCKILLSRCNODES");
532223637Sbz				killed += psnk.psnk_killed;
533171172Smlaier			}
534171172Smlaier			freeaddrinfo(res[1]);
535171172Smlaier		} else {
536171172Smlaier			if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
537171172Smlaier				err(1, "DIOCKILLSRCNODES");
538223637Sbz			killed += psnk.psnk_killed;
539171172Smlaier		}
540171172Smlaier	}
541171172Smlaier
542171172Smlaier	freeaddrinfo(res[0]);
543171172Smlaier
544171172Smlaier	if ((opts & PF_OPT_QUIET) == 0)
545171172Smlaier		fprintf(stderr, "killed %d src nodes from %d sources and %d "
546171172Smlaier		    "destinations\n", killed, sources, dests);
547171172Smlaier	return (0);
548171172Smlaier}
549171172Smlaier
550171172Smlaierint
551223637Sbzpfctl_net_kill_states(int dev, const char *iface, int opts)
552126353Smlaier{
553126353Smlaier	struct pfioc_state_kill psk;
554126353Smlaier	struct addrinfo *res[2], *resp[2];
555126353Smlaier	struct sockaddr last_src, last_dst;
556126353Smlaier	int killed, sources, dests;
557126353Smlaier	int ret_ga;
558126353Smlaier
559126353Smlaier	killed = sources = dests = 0;
560126353Smlaier
561126353Smlaier	memset(&psk, 0, sizeof(psk));
562126353Smlaier	memset(&psk.psk_src.addr.v.a.mask, 0xff,
563126353Smlaier	    sizeof(psk.psk_src.addr.v.a.mask));
564126353Smlaier	memset(&last_src, 0xff, sizeof(last_src));
565126353Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
566130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
567130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
568130617Smlaier		errx(1, "invalid interface: %s", iface);
569126353Smlaier
570171172Smlaier	pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
571171172Smlaier
572126353Smlaier	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
573126353Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
574126353Smlaier		/* NOTREACHED */
575126353Smlaier	}
576126353Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
577126353Smlaier		if (resp[0]->ai_addr == NULL)
578126353Smlaier			continue;
579126353Smlaier		/* We get lots of duplicates.  Catch the easy ones */
580126353Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
581126353Smlaier			continue;
582126353Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
583126353Smlaier
584126353Smlaier		psk.psk_af = resp[0]->ai_family;
585126353Smlaier		sources++;
586126353Smlaier
587126353Smlaier		if (psk.psk_af == AF_INET)
588126353Smlaier			psk.psk_src.addr.v.a.addr.v4 =
589126353Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
590126353Smlaier		else if (psk.psk_af == AF_INET6)
591126353Smlaier			psk.psk_src.addr.v.a.addr.v6 =
592126353Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
593126353Smlaier			    sin6_addr;
594126353Smlaier		else
595126353Smlaier			errx(1, "Unknown address family %d", psk.psk_af);
596126353Smlaier
597126353Smlaier		if (state_killers > 1) {
598126353Smlaier			dests = 0;
599126353Smlaier			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
600126353Smlaier			    sizeof(psk.psk_dst.addr.v.a.mask));
601126353Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
602171172Smlaier			pfctl_addrprefix(state_kill[1],
603171172Smlaier			    &psk.psk_dst.addr.v.a.mask);
604126353Smlaier			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
605126353Smlaier			    &res[1]))) {
606130617Smlaier				errx(1, "getaddrinfo: %s",
607130617Smlaier				    gai_strerror(ret_ga));
608126353Smlaier				/* NOTREACHED */
609126353Smlaier			}
610126353Smlaier			for (resp[1] = res[1]; resp[1];
611126353Smlaier			    resp[1] = resp[1]->ai_next) {
612126353Smlaier				if (resp[1]->ai_addr == NULL)
613126353Smlaier					continue;
614126353Smlaier				if (psk.psk_af != resp[1]->ai_family)
615126353Smlaier					continue;
616126353Smlaier
617126353Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
618126353Smlaier				    sizeof(last_dst)) == 0)
619126353Smlaier					continue;
620126353Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
621126353Smlaier
622126353Smlaier				dests++;
623126353Smlaier
624126353Smlaier				if (psk.psk_af == AF_INET)
625126353Smlaier					psk.psk_dst.addr.v.a.addr.v4 =
626126353Smlaier					    ((struct sockaddr_in *)resp[1]->
627126353Smlaier					    ai_addr)->sin_addr;
628126353Smlaier				else if (psk.psk_af == AF_INET6)
629126353Smlaier					psk.psk_dst.addr.v.a.addr.v6 =
630126353Smlaier					    ((struct sockaddr_in6 *)resp[1]->
631126353Smlaier					    ai_addr)->sin6_addr;
632126353Smlaier				else
633126353Smlaier					errx(1, "Unknown address family %d",
634126353Smlaier					    psk.psk_af);
635126353Smlaier
636126353Smlaier				if (ioctl(dev, DIOCKILLSTATES, &psk))
637126353Smlaier					err(1, "DIOCKILLSTATES");
638223637Sbz				killed += psk.psk_killed;
639126353Smlaier			}
640126353Smlaier			freeaddrinfo(res[1]);
641126353Smlaier		} else {
642126353Smlaier			if (ioctl(dev, DIOCKILLSTATES, &psk))
643126353Smlaier				err(1, "DIOCKILLSTATES");
644223637Sbz			killed += psk.psk_killed;
645126353Smlaier		}
646126353Smlaier	}
647126353Smlaier
648126353Smlaier	freeaddrinfo(res[0]);
649126353Smlaier
650126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
651126353Smlaier		fprintf(stderr, "killed %d states from %d sources and %d "
652126353Smlaier		    "destinations\n", killed, sources, dests);
653126353Smlaier	return (0);
654126353Smlaier}
655126353Smlaier
656126353Smlaierint
657223637Sbzpfctl_label_kill_states(int dev, const char *iface, int opts)
658223637Sbz{
659223637Sbz	struct pfioc_state_kill psk;
660223637Sbz
661223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
662223637Sbz		warnx("no label specified");
663223637Sbz		usage();
664223637Sbz	}
665223637Sbz	memset(&psk, 0, sizeof(psk));
666223637Sbz	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
667223637Sbz	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
668223637Sbz		errx(1, "invalid interface: %s", iface);
669223637Sbz
670223637Sbz	if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
671223637Sbz	    sizeof(psk.psk_label))
672223637Sbz		errx(1, "label too long: %s", state_kill[1]);
673223637Sbz
674223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
675223637Sbz		err(1, "DIOCKILLSTATES");
676223637Sbz
677223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
678223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
679223637Sbz
680223637Sbz	return (0);
681223637Sbz}
682223637Sbz
683223637Sbzint
684223637Sbzpfctl_id_kill_states(int dev, const char *iface, int opts)
685223637Sbz{
686223637Sbz	struct pfioc_state_kill psk;
687223637Sbz
688223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
689223637Sbz		warnx("no id specified");
690223637Sbz		usage();
691223637Sbz	}
692223637Sbz
693223637Sbz	memset(&psk, 0, sizeof(psk));
694223637Sbz	if ((sscanf(state_kill[1], "%jx/%x",
695223637Sbz	    &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
696223637Sbz		HTONL(psk.psk_pfcmp.creatorid);
697223637Sbz	else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
698223637Sbz		psk.psk_pfcmp.creatorid = 0;
699223637Sbz	} else {
700223637Sbz		warnx("wrong id format specified");
701223637Sbz		usage();
702223637Sbz	}
703223637Sbz	if (psk.psk_pfcmp.id == 0) {
704223637Sbz		warnx("cannot kill id 0");
705223637Sbz		usage();
706223637Sbz	}
707223637Sbz
708223637Sbz	psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
709223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
710223637Sbz		err(1, "DIOCKILLSTATES");
711223637Sbz
712223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
713223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
714223637Sbz
715223637Sbz	return (0);
716223637Sbz}
717223637Sbz
718223637Sbzint
719126353Smlaierpfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
720145840Smlaier    u_int32_t ticket, int r_action, char *anchorname)
721126353Smlaier{
722126353Smlaier	struct pfioc_pooladdr pp;
723126353Smlaier	struct pf_pooladdr *pa;
724126353Smlaier	u_int32_t pnr, mpnr;
725126353Smlaier
726126353Smlaier	memset(&pp, 0, sizeof(pp));
727126353Smlaier	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
728126353Smlaier	pp.r_action = r_action;
729126353Smlaier	pp.r_num = nr;
730126353Smlaier	pp.ticket = ticket;
731126353Smlaier	if (ioctl(dev, DIOCGETADDRS, &pp)) {
732126353Smlaier		warn("DIOCGETADDRS");
733126353Smlaier		return (-1);
734126353Smlaier	}
735126353Smlaier	mpnr = pp.nr;
736126353Smlaier	TAILQ_INIT(&pool->list);
737126353Smlaier	for (pnr = 0; pnr < mpnr; ++pnr) {
738126353Smlaier		pp.nr = pnr;
739126353Smlaier		if (ioctl(dev, DIOCGETADDR, &pp)) {
740126353Smlaier			warn("DIOCGETADDR");
741126353Smlaier			return (-1);
742126353Smlaier		}
743126353Smlaier		pa = calloc(1, sizeof(struct pf_pooladdr));
744126353Smlaier		if (pa == NULL)
745126353Smlaier			err(1, "calloc");
746126353Smlaier		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
747126353Smlaier		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
748126353Smlaier	}
749126353Smlaier
750126353Smlaier	return (0);
751126353Smlaier}
752126353Smlaier
753126353Smlaiervoid
754171172Smlaierpfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
755171172Smlaier{
756171172Smlaier	struct pf_pooladdr *pa;
757171172Smlaier
758171172Smlaier	while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
759171172Smlaier		TAILQ_REMOVE(&src->list, pa, entries);
760171172Smlaier		TAILQ_INSERT_TAIL(&dst->list, pa, entries);
761171172Smlaier	}
762171172Smlaier}
763171172Smlaier
764171172Smlaiervoid
765126353Smlaierpfctl_clear_pool(struct pf_pool *pool)
766126353Smlaier{
767126353Smlaier	struct pf_pooladdr *pa;
768126353Smlaier
769126353Smlaier	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
770126353Smlaier		TAILQ_REMOVE(&pool->list, pa, entries);
771126353Smlaier		free(pa);
772126353Smlaier	}
773126353Smlaier}
774126353Smlaier
775126353Smlaiervoid
776126353Smlaierpfctl_print_rule_counters(struct pf_rule *rule, int opts)
777126353Smlaier{
778126353Smlaier	if (opts & PF_OPT_DEBUG) {
779126353Smlaier		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
780126353Smlaier		    "p", "sa", "sp", "da", "dp" };
781126353Smlaier		int i;
782126353Smlaier
783126353Smlaier		printf("  [ Skip steps: ");
784126353Smlaier		for (i = 0; i < PF_SKIP_COUNT; ++i) {
785126353Smlaier			if (rule->skip[i].nr == rule->nr + 1)
786126353Smlaier				continue;
787126353Smlaier			printf("%s=", t[i]);
788126353Smlaier			if (rule->skip[i].nr == -1)
789126353Smlaier				printf("end ");
790126353Smlaier			else
791126353Smlaier				printf("%u ", rule->skip[i].nr);
792126353Smlaier		}
793126353Smlaier		printf("]\n");
794126353Smlaier
795126353Smlaier		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
796126353Smlaier		    rule->qname, rule->qid, rule->pqname, rule->pqid);
797126353Smlaier	}
798171172Smlaier	if (opts & PF_OPT_VERBOSE) {
799127024Smlaier		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
800263029Sglebius			    "Bytes: %-10llu  States: %-6ju]\n",
801127024Smlaier			    (unsigned long long)rule->evaluations,
802171172Smlaier			    (unsigned long long)(rule->packets[0] +
803171172Smlaier			    rule->packets[1]),
804171172Smlaier			    (unsigned long long)(rule->bytes[0] +
805263029Sglebius			    rule->bytes[1]), (uintmax_t)rule->u_states_cur);
806171172Smlaier		if (!(opts & PF_OPT_DEBUG))
807223637Sbz			printf("  [ Inserted: uid %u pid %u "
808263029Sglebius			    "State Creations: %-6ju]\n",
809223637Sbz			    (unsigned)rule->cuid, (unsigned)rule->cpid,
810263029Sglebius			    (uintmax_t)rule->u_states_tot);
811171172Smlaier	}
812126353Smlaier}
813126353Smlaier
814130617Smlaiervoid
815130617Smlaierpfctl_print_title(char *title)
816130617Smlaier{
817130617Smlaier	if (!first_title)
818130617Smlaier		printf("\n");
819130617Smlaier	first_title = 0;
820130617Smlaier	printf("%s\n", title);
821130617Smlaier}
822130617Smlaier
823126353Smlaierint
824171172Smlaierpfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
825171172Smlaier    char *anchorname, int depth)
826126353Smlaier{
827126353Smlaier	struct pfioc_rule pr;
828130617Smlaier	u_int32_t nr, mnr, header = 0;
829126353Smlaier	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
830223057Sbz	int numeric = opts & PF_OPT_NUMERIC;
831171172Smlaier	int len = strlen(path);
832171172Smlaier	int brace;
833171172Smlaier	char *p;
834126353Smlaier
835171172Smlaier	if (path[0])
836171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
837171172Smlaier	else
838171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
839171172Smlaier
840126353Smlaier	memset(&pr, 0, sizeof(pr));
841171172Smlaier	memcpy(pr.anchor, path, sizeof(pr.anchor));
842130617Smlaier	if (opts & PF_OPT_SHOWALL) {
843130617Smlaier		pr.rule.action = PF_PASS;
844130617Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
845130617Smlaier			warn("DIOCGETRULES");
846171172Smlaier			goto error;
847130617Smlaier		}
848130617Smlaier		header++;
849130617Smlaier	}
850126353Smlaier	pr.rule.action = PF_SCRUB;
851126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
852126353Smlaier		warn("DIOCGETRULES");
853171172Smlaier		goto error;
854126353Smlaier	}
855130617Smlaier	if (opts & PF_OPT_SHOWALL) {
856171172Smlaier		if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
857130617Smlaier			pfctl_print_title("FILTER RULES:");
858171172Smlaier		else if (format == PFCTL_SHOW_LABELS && labels)
859130617Smlaier			pfctl_print_title("LABEL COUNTERS:");
860130617Smlaier	}
861126353Smlaier	mnr = pr.nr;
862171172Smlaier	if (opts & PF_OPT_CLRRULECTRS)
863171172Smlaier		pr.action = PF_GET_CLR_CNTR;
864171172Smlaier
865126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
866126353Smlaier		pr.nr = nr;
867126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
868126353Smlaier			warn("DIOCGETRULE");
869171172Smlaier			goto error;
870126353Smlaier		}
871126353Smlaier
872126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
873171172Smlaier		    nr, pr.ticket, PF_SCRUB, path) != 0)
874171172Smlaier			goto error;
875126353Smlaier
876126353Smlaier		switch (format) {
877171172Smlaier		case PFCTL_SHOW_LABELS:
878126353Smlaier			break;
879171172Smlaier		case PFCTL_SHOW_RULES:
880130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
881130617Smlaier				labels = 1;
882223057Sbz			print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
883171172Smlaier			printf("\n");
884126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
885171172Smlaier			break;
886171172Smlaier		case PFCTL_SHOW_NOTHING:
887171172Smlaier			break;
888126353Smlaier		}
889126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
890126353Smlaier	}
891126353Smlaier	pr.rule.action = PF_PASS;
892126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
893126353Smlaier		warn("DIOCGETRULES");
894171172Smlaier		goto error;
895126353Smlaier	}
896126353Smlaier	mnr = pr.nr;
897126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
898126353Smlaier		pr.nr = nr;
899126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
900126353Smlaier			warn("DIOCGETRULE");
901171172Smlaier			goto error;
902126353Smlaier		}
903126353Smlaier
904126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
905171172Smlaier		    nr, pr.ticket, PF_PASS, path) != 0)
906171172Smlaier			goto error;
907126353Smlaier
908126353Smlaier		switch (format) {
909171172Smlaier		case PFCTL_SHOW_LABELS:
910126353Smlaier			if (pr.rule.label[0]) {
911223637Sbz				printf("%s %llu %llu %llu %llu"
912263029Sglebius				    " %llu %llu %llu %ju\n",
913223637Sbz				    pr.rule.label,
914127024Smlaier				    (unsigned long long)pr.rule.evaluations,
915171172Smlaier				    (unsigned long long)(pr.rule.packets[0] +
916171172Smlaier				    pr.rule.packets[1]),
917171172Smlaier				    (unsigned long long)(pr.rule.bytes[0] +
918171172Smlaier				    pr.rule.bytes[1]),
919171172Smlaier				    (unsigned long long)pr.rule.packets[0],
920171172Smlaier				    (unsigned long long)pr.rule.bytes[0],
921171172Smlaier				    (unsigned long long)pr.rule.packets[1],
922223637Sbz				    (unsigned long long)pr.rule.bytes[1],
923263029Sglebius				    (uintmax_t)pr.rule.u_states_tot);
924126353Smlaier			}
925126353Smlaier			break;
926171172Smlaier		case PFCTL_SHOW_RULES:
927171172Smlaier			brace = 0;
928130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
929130617Smlaier				labels = 1;
930171172Smlaier			INDENT(depth, !(opts & PF_OPT_VERBOSE));
931171172Smlaier			if (pr.anchor_call[0] &&
932171172Smlaier			   ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
933171172Smlaier			   ((void *)p == (void *)pr.anchor_call ||
934171172Smlaier			   *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
935171172Smlaier				brace++;
936171172Smlaier				if ((p = strrchr(pr.anchor_call, '/')) !=
937171172Smlaier				    NULL)
938171172Smlaier					p++;
939171172Smlaier				else
940171172Smlaier					p = &pr.anchor_call[0];
941171172Smlaier			} else
942171172Smlaier				p = &pr.anchor_call[0];
943171172Smlaier
944223057Sbz			print_rule(&pr.rule, p, rule_numbers, numeric);
945171172Smlaier			if (brace)
946171172Smlaier				printf(" {\n");
947171172Smlaier			else
948171172Smlaier				printf("\n");
949126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
950171172Smlaier			if (brace) {
951171172Smlaier				pfctl_show_rules(dev, path, opts, format,
952171172Smlaier				    p, depth + 1);
953171172Smlaier				INDENT(depth, !(opts & PF_OPT_VERBOSE));
954171172Smlaier				printf("}\n");
955171172Smlaier			}
956171172Smlaier			break;
957171172Smlaier		case PFCTL_SHOW_NOTHING:
958171172Smlaier			break;
959126353Smlaier		}
960126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
961126353Smlaier	}
962171172Smlaier	path[len] = '\0';
963126353Smlaier	return (0);
964171172Smlaier
965171172Smlaier error:
966171172Smlaier	path[len] = '\0';
967171172Smlaier	return (-1);
968126353Smlaier}
969126353Smlaier
970126353Smlaierint
971145840Smlaierpfctl_show_nat(int dev, int opts, char *anchorname)
972126353Smlaier{
973126353Smlaier	struct pfioc_rule pr;
974126353Smlaier	u_int32_t mnr, nr;
975126353Smlaier	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
976130617Smlaier	int i, dotitle = opts & PF_OPT_SHOWALL;
977126353Smlaier
978126353Smlaier	memset(&pr, 0, sizeof(pr));
979126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
980126353Smlaier	for (i = 0; i < 3; i++) {
981126353Smlaier		pr.rule.action = nattype[i];
982126353Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
983126353Smlaier			warn("DIOCGETRULES");
984126353Smlaier			return (-1);
985126353Smlaier		}
986126353Smlaier		mnr = pr.nr;
987126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
988126353Smlaier			pr.nr = nr;
989126353Smlaier			if (ioctl(dev, DIOCGETRULE, &pr)) {
990126353Smlaier				warn("DIOCGETRULE");
991126353Smlaier				return (-1);
992126353Smlaier			}
993126353Smlaier			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
994145840Smlaier			    pr.ticket, nattype[i], anchorname) != 0)
995126353Smlaier				return (-1);
996130617Smlaier			if (dotitle) {
997130617Smlaier				pfctl_print_title("TRANSLATION RULES:");
998130617Smlaier				dotitle = 0;
999130617Smlaier			}
1000145840Smlaier			print_rule(&pr.rule, pr.anchor_call,
1001223057Sbz			    opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
1002171172Smlaier			printf("\n");
1003126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
1004126353Smlaier			pfctl_clear_pool(&pr.rule.rpool);
1005126353Smlaier		}
1006126353Smlaier	}
1007126353Smlaier	return (0);
1008126353Smlaier}
1009126353Smlaier
1010126353Smlaierint
1011130617Smlaierpfctl_show_src_nodes(int dev, int opts)
1012126353Smlaier{
1013130617Smlaier	struct pfioc_src_nodes psn;
1014130617Smlaier	struct pf_src_node *p;
1015130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1016223637Sbz	unsigned int len = 0;
1017130617Smlaier	int i;
1018130617Smlaier
1019130617Smlaier	memset(&psn, 0, sizeof(psn));
1020130617Smlaier	for (;;) {
1021130617Smlaier		psn.psn_len = len;
1022130617Smlaier		if (len) {
1023130617Smlaier			newinbuf = realloc(inbuf, len);
1024130617Smlaier			if (newinbuf == NULL)
1025130617Smlaier				err(1, "realloc");
1026130617Smlaier			psn.psn_buf = inbuf = newinbuf;
1027130617Smlaier		}
1028130617Smlaier		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
1029130617Smlaier			warn("DIOCGETSRCNODES");
1030171172Smlaier			free(inbuf);
1031130617Smlaier			return (-1);
1032130617Smlaier		}
1033130617Smlaier		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
1034130617Smlaier			break;
1035130617Smlaier		if (len == 0 && psn.psn_len == 0)
1036171172Smlaier			goto done;
1037130617Smlaier		if (len == 0 && psn.psn_len != 0)
1038130617Smlaier			len = psn.psn_len;
1039130617Smlaier		if (psn.psn_len == 0)
1040171172Smlaier			goto done;	/* no src_nodes */
1041130617Smlaier		len *= 2;
1042130617Smlaier	}
1043130617Smlaier	p = psn.psn_src_nodes;
1044130617Smlaier	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
1045130617Smlaier		pfctl_print_title("SOURCE TRACKING NODES:");
1046130617Smlaier	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
1047130617Smlaier		print_src_node(p, opts);
1048130617Smlaier		p++;
1049130617Smlaier	}
1050171172Smlaierdone:
1051171172Smlaier	free(inbuf);
1052130617Smlaier	return (0);
1053130617Smlaier}
1054130617Smlaier
1055130617Smlaierint
1056130617Smlaierpfctl_show_states(int dev, const char *iface, int opts)
1057130617Smlaier{
1058126353Smlaier	struct pfioc_states ps;
1059223637Sbz	struct pfsync_state *p;
1060130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1061223637Sbz	unsigned int len = 0;
1062130617Smlaier	int i, dotitle = (opts & PF_OPT_SHOWALL);
1063126353Smlaier
1064126353Smlaier	memset(&ps, 0, sizeof(ps));
1065126353Smlaier	for (;;) {
1066126353Smlaier		ps.ps_len = len;
1067126353Smlaier		if (len) {
1068130617Smlaier			newinbuf = realloc(inbuf, len);
1069130617Smlaier			if (newinbuf == NULL)
1070126353Smlaier				err(1, "realloc");
1071130617Smlaier			ps.ps_buf = inbuf = newinbuf;
1072126353Smlaier		}
1073126353Smlaier		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
1074126353Smlaier			warn("DIOCGETSTATES");
1075171172Smlaier			free(inbuf);
1076126353Smlaier			return (-1);
1077126353Smlaier		}
1078126353Smlaier		if (ps.ps_len + sizeof(struct pfioc_states) < len)
1079126353Smlaier			break;
1080126353Smlaier		if (len == 0 && ps.ps_len == 0)
1081171172Smlaier			goto done;
1082126353Smlaier		if (len == 0 && ps.ps_len != 0)
1083126353Smlaier			len = ps.ps_len;
1084126353Smlaier		if (ps.ps_len == 0)
1085171172Smlaier			goto done;	/* no states */
1086126353Smlaier		len *= 2;
1087126353Smlaier	}
1088126353Smlaier	p = ps.ps_states;
1089130617Smlaier	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
1090223637Sbz		if (iface != NULL && strcmp(p->ifname, iface))
1091130617Smlaier			continue;
1092130617Smlaier		if (dotitle) {
1093130617Smlaier			pfctl_print_title("STATES:");
1094130617Smlaier			dotitle = 0;
1095130617Smlaier		}
1096130617Smlaier		print_state(p, opts);
1097126353Smlaier	}
1098171172Smlaierdone:
1099171172Smlaier	free(inbuf);
1100126353Smlaier	return (0);
1101126353Smlaier}
1102126353Smlaier
1103126353Smlaierint
1104130617Smlaierpfctl_show_status(int dev, int opts)
1105126353Smlaier{
1106126353Smlaier	struct pf_status status;
1107126353Smlaier
1108126353Smlaier	if (ioctl(dev, DIOCGETSTATUS, &status)) {
1109126353Smlaier		warn("DIOCGETSTATUS");
1110126353Smlaier		return (-1);
1111126353Smlaier	}
1112130617Smlaier	if (opts & PF_OPT_SHOWALL)
1113130617Smlaier		pfctl_print_title("INFO:");
1114130617Smlaier	print_status(&status, opts);
1115126353Smlaier	return (0);
1116126353Smlaier}
1117126353Smlaier
1118126353Smlaierint
1119130617Smlaierpfctl_show_timeouts(int dev, int opts)
1120126353Smlaier{
1121126353Smlaier	struct pfioc_tm pt;
1122126353Smlaier	int i;
1123126353Smlaier
1124130617Smlaier	if (opts & PF_OPT_SHOWALL)
1125130617Smlaier		pfctl_print_title("TIMEOUTS:");
1126126353Smlaier	memset(&pt, 0, sizeof(pt));
1127126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1128126353Smlaier		pt.timeout = pf_timeouts[i].timeout;
1129126353Smlaier		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
1130126353Smlaier			err(1, "DIOCGETTIMEOUT");
1131126353Smlaier		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
1132145840Smlaier		if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1133145840Smlaier		    pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1134126353Smlaier			printf(" states");
1135126353Smlaier		else
1136126353Smlaier			printf("s");
1137126353Smlaier		printf("\n");
1138126353Smlaier	}
1139126353Smlaier	return (0);
1140126353Smlaier
1141126353Smlaier}
1142126353Smlaier
1143126353Smlaierint
1144130617Smlaierpfctl_show_limits(int dev, int opts)
1145126353Smlaier{
1146126353Smlaier	struct pfioc_limit pl;
1147126353Smlaier	int i;
1148126353Smlaier
1149130617Smlaier	if (opts & PF_OPT_SHOWALL)
1150130617Smlaier		pfctl_print_title("LIMITS:");
1151126353Smlaier	memset(&pl, 0, sizeof(pl));
1152126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1153130617Smlaier		pl.index = pf_limits[i].index;
1154126353Smlaier		if (ioctl(dev, DIOCGETLIMIT, &pl))
1155126353Smlaier			err(1, "DIOCGETLIMIT");
1156171172Smlaier		printf("%-13s ", pf_limits[i].name);
1157126353Smlaier		if (pl.limit == UINT_MAX)
1158126353Smlaier			printf("unlimited\n");
1159126353Smlaier		else
1160171172Smlaier			printf("hard limit %8u\n", pl.limit);
1161126353Smlaier	}
1162126353Smlaier	return (0);
1163126353Smlaier}
1164126353Smlaier
1165126353Smlaier/* callbacks for rule/nat/rdr/addr */
1166126353Smlaierint
1167126353Smlaierpfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
1168126353Smlaier{
1169126353Smlaier	struct pf_pooladdr *pa;
1170126353Smlaier
1171126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1172126353Smlaier		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
1173126353Smlaier			err(1, "DIOCBEGINADDRS");
1174126353Smlaier	}
1175126353Smlaier
1176126353Smlaier	pf->paddr.af = af;
1177126353Smlaier	TAILQ_FOREACH(pa, &p->list, entries) {
1178126353Smlaier		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
1179126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1180126353Smlaier			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
1181126353Smlaier				err(1, "DIOCADDADDR");
1182126353Smlaier		}
1183126353Smlaier	}
1184126353Smlaier	return (0);
1185126353Smlaier}
1186126353Smlaier
1187126353Smlaierint
1188145840Smlaierpfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
1189126353Smlaier{
1190130617Smlaier	u_int8_t		rs_num;
1191171172Smlaier	struct pf_rule		*rule;
1192171172Smlaier	struct pf_ruleset	*rs;
1193171172Smlaier	char 			*p;
1194126353Smlaier
1195171172Smlaier	rs_num = pf_get_ruleset_number(r->action);
1196171172Smlaier	if (rs_num == PF_RULESET_MAX)
1197145840Smlaier		errx(1, "Invalid rule type %d", r->action);
1198126353Smlaier
1199171172Smlaier	rs = &pf->anchor->ruleset;
1200145840Smlaier
1201171172Smlaier	if (anchor_call[0] && r->anchor == NULL) {
1202171172Smlaier		/*
1203171172Smlaier		 * Don't make non-brace anchors part of the main anchor pool.
1204145840Smlaier		 */
1205171172Smlaier		if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1206171172Smlaier			err(1, "pfctl_add_rule: calloc");
1207171172Smlaier
1208171172Smlaier		pf_init_ruleset(&r->anchor->ruleset);
1209171172Smlaier		r->anchor->ruleset.anchor = r->anchor;
1210171172Smlaier		if (strlcpy(r->anchor->path, anchor_call,
1211171172Smlaier		    sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1212223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1213171172Smlaier		if ((p = strrchr(anchor_call, '/')) != NULL) {
1214171172Smlaier			if (!strlen(p))
1215171172Smlaier				err(1, "pfctl_add_rule: bad anchor name %s",
1216171172Smlaier				    anchor_call);
1217171172Smlaier		} else
1218171172Smlaier			p = (char *)anchor_call;
1219171172Smlaier		if (strlcpy(r->anchor->name, p,
1220171172Smlaier		    sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1221223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1222171172Smlaier	}
1223145840Smlaier
1224171172Smlaier	if ((rule = calloc(1, sizeof(*rule))) == NULL)
1225171172Smlaier		err(1, "calloc");
1226171172Smlaier	bcopy(r, rule, sizeof(*rule));
1227171172Smlaier	TAILQ_INIT(&rule->rpool.list);
1228171172Smlaier	pfctl_move_pool(&r->rpool, &rule->rpool);
1229145840Smlaier
1230171172Smlaier	TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1231171172Smlaier	return (0);
1232171172Smlaier}
1233171172Smlaier
1234171172Smlaierint
1235171172Smlaierpfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
1236171172Smlaier{
1237171172Smlaier	int osize = pf->trans->pfrb_size;
1238171172Smlaier
1239171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1240171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1241171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1242171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1243171172Smlaier			return (1);
1244171172Smlaier	}
1245171172Smlaier	if (a == pf->astack[0] && ((altqsupport &&
1246223637Sbz	    (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1247171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1248171172Smlaier			return (2);
1249171172Smlaier	}
1250171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1251171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1252171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1253171172Smlaier			return (3);
1254171172Smlaier	}
1255171172Smlaier	if (pf->loadopt & PFCTL_FLAG_TABLE)
1256171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1257171172Smlaier			return (4);
1258171172Smlaier	if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1259171172Smlaier		return (5);
1260171172Smlaier
1261171172Smlaier	return (0);
1262171172Smlaier}
1263171172Smlaier
1264171172Smlaierint
1265171172Smlaierpfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
1266171172Smlaier    int rs_num, int depth)
1267171172Smlaier{
1268171172Smlaier	struct pf_rule *r;
1269171172Smlaier	int		error, len = strlen(path);
1270171172Smlaier	int		brace = 0;
1271171172Smlaier
1272171172Smlaier	pf->anchor = rs->anchor;
1273171172Smlaier
1274171172Smlaier	if (path[0])
1275171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
1276171172Smlaier	else
1277171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
1278171172Smlaier
1279171172Smlaier	if (depth) {
1280171172Smlaier		if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
1281171172Smlaier			brace++;
1282171172Smlaier			if (pf->opts & PF_OPT_VERBOSE)
1283171172Smlaier				printf(" {\n");
1284171172Smlaier			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1285171172Smlaier			    (error = pfctl_ruleset_trans(pf,
1286171172Smlaier			    path, rs->anchor))) {
1287171172Smlaier				printf("pfctl_load_rulesets: "
1288171172Smlaier				    "pfctl_ruleset_trans %d\n", error);
1289171172Smlaier				goto error;
1290145840Smlaier			}
1291171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1292171172Smlaier			printf("\n");
1293145840Smlaier
1294145840Smlaier	}
1295145840Smlaier
1296171172Smlaier	if (pf->optimize && rs_num == PF_RULESET_FILTER)
1297171172Smlaier		pfctl_optimize_ruleset(pf, rs);
1298171172Smlaier
1299171172Smlaier	while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
1300171172Smlaier		TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
1301171172Smlaier		if ((error = pfctl_load_rule(pf, path, r, depth)))
1302171172Smlaier			goto error;
1303171172Smlaier		if (r->anchor) {
1304171172Smlaier			if ((error = pfctl_load_ruleset(pf, path,
1305171172Smlaier			    &r->anchor->ruleset, rs_num, depth + 1)))
1306171172Smlaier				goto error;
1307171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1308171172Smlaier			printf("\n");
1309171172Smlaier		free(r);
1310171172Smlaier	}
1311171172Smlaier	if (brace && pf->opts & PF_OPT_VERBOSE) {
1312171172Smlaier		INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
1313171172Smlaier		printf("}\n");
1314171172Smlaier	}
1315171172Smlaier	path[len] = '\0';
1316171172Smlaier	return (0);
1317171172Smlaier
1318171172Smlaier error:
1319171172Smlaier	path[len] = '\0';
1320171172Smlaier	return (error);
1321171172Smlaier
1322171172Smlaier}
1323171172Smlaier
1324171172Smlaierint
1325171172Smlaierpfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
1326171172Smlaier{
1327171172Smlaier	u_int8_t		rs_num = pf_get_ruleset_number(r->action);
1328171172Smlaier	char			*name;
1329171172Smlaier	struct pfioc_rule	pr;
1330171172Smlaier	int			len = strlen(path);
1331171172Smlaier
1332171172Smlaier	bzero(&pr, sizeof(pr));
1333171172Smlaier	/* set up anchor before adding to path for anchor_call */
1334171172Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1335171172Smlaier		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
1336171172Smlaier	if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
1337171172Smlaier		errx(1, "pfctl_load_rule: strlcpy");
1338171172Smlaier
1339171172Smlaier	if (r->anchor) {
1340171172Smlaier		if (r->anchor->match) {
1341171172Smlaier			if (path[0])
1342171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1343171172Smlaier				    "/%s", r->anchor->name);
1344171172Smlaier			else
1345171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1346171172Smlaier				    "%s", r->anchor->name);
1347171172Smlaier			name = path;
1348171172Smlaier		} else
1349171172Smlaier			name = r->anchor->path;
1350171172Smlaier	} else
1351171172Smlaier		name = "";
1352171172Smlaier
1353126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1354126353Smlaier		if (pfctl_add_pool(pf, &r->rpool, r->af))
1355126353Smlaier			return (1);
1356130617Smlaier		pr.pool_ticket = pf->paddr.ticket;
1357130617Smlaier		memcpy(&pr.rule, r, sizeof(pr.rule));
1358171172Smlaier		if (r->anchor && strlcpy(pr.anchor_call, name,
1359171172Smlaier		    sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
1360171172Smlaier			errx(1, "pfctl_load_rule: strlcpy");
1361130617Smlaier		if (ioctl(pf->dev, DIOCADDRULE, &pr))
1362126353Smlaier			err(1, "DIOCADDRULE");
1363126353Smlaier	}
1364171172Smlaier
1365171172Smlaier	if (pf->opts & PF_OPT_VERBOSE) {
1366171172Smlaier		INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
1367171172Smlaier		print_rule(r, r->anchor ? r->anchor->name : "",
1368223057Sbz		    pf->opts & PF_OPT_VERBOSE2,
1369223057Sbz		    pf->opts & PF_OPT_NUMERIC);
1370171172Smlaier	}
1371171172Smlaier	path[len] = '\0';
1372126353Smlaier	pfctl_clear_pool(&r->rpool);
1373126353Smlaier	return (0);
1374126353Smlaier}
1375126353Smlaier
1376126353Smlaierint
1377126353Smlaierpfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1378126353Smlaier{
1379126353Smlaier	if (altqsupport &&
1380126353Smlaier	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1381126353Smlaier		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1382126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1383126353Smlaier			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1384126353Smlaier				if (errno == ENXIO)
1385126353Smlaier					errx(1, "qtype not configured");
1386126353Smlaier				else if (errno == ENODEV)
1387126353Smlaier					errx(1, "%s: driver does not support "
1388126353Smlaier					    "altq", a->ifname);
1389126353Smlaier				else
1390126353Smlaier					err(1, "DIOCADDALTQ");
1391126353Smlaier			}
1392126353Smlaier		}
1393126353Smlaier		pfaltq_store(&pf->paltq->altq);
1394126353Smlaier	}
1395126353Smlaier	return (0);
1396126353Smlaier}
1397126353Smlaier
1398126353Smlaierint
1399223637Sbzpfctl_rules(int dev, char *filename, int opts, int optimize,
1400171172Smlaier    char *anchorname, struct pfr_buffer *trans)
1401126353Smlaier{
1402126353Smlaier#define ERR(x) do { warn(x); goto _error; } while(0)
1403126353Smlaier#define ERRX(x) do { warnx(x); goto _error; } while(0)
1404126353Smlaier
1405130617Smlaier	struct pfr_buffer	*t, buf;
1406130617Smlaier	struct pfioc_altq	 pa;
1407130617Smlaier	struct pfctl		 pf;
1408171172Smlaier	struct pf_ruleset	*rs;
1409130617Smlaier	struct pfr_table	 trs;
1410171172Smlaier	char			*path;
1411130617Smlaier	int			 osize;
1412126353Smlaier
1413171172Smlaier	RB_INIT(&pf_anchors);
1414171172Smlaier	memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
1415171172Smlaier	pf_init_ruleset(&pf_main_anchor.ruleset);
1416171172Smlaier	pf_main_anchor.ruleset.anchor = &pf_main_anchor;
1417130617Smlaier	if (trans == NULL) {
1418171172Smlaier		bzero(&buf, sizeof(buf));
1419171172Smlaier		buf.pfrb_type = PFRB_TRANS;
1420171172Smlaier		t = &buf;
1421171172Smlaier		osize = 0;
1422130617Smlaier	} else {
1423171172Smlaier		t = trans;
1424171172Smlaier		osize = t->pfrb_size;
1425130617Smlaier	}
1426130617Smlaier
1427126353Smlaier	memset(&pa, 0, sizeof(pa));
1428126353Smlaier	memset(&pf, 0, sizeof(pf));
1429126353Smlaier	memset(&trs, 0, sizeof(trs));
1430171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
1431171172Smlaier		ERRX("pfctl_rules: calloc");
1432126353Smlaier	if (strlcpy(trs.pfrt_anchor, anchorname,
1433145840Smlaier	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1434126353Smlaier		ERRX("pfctl_rules: strlcpy");
1435126353Smlaier	pf.dev = dev;
1436126353Smlaier	pf.opts = opts;
1437171172Smlaier	pf.optimize = optimize;
1438126353Smlaier	pf.loadopt = loadopt;
1439171172Smlaier
1440171172Smlaier	/* non-brace anchor, create without resolving the path */
1441171172Smlaier	if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
1442171172Smlaier		ERRX("pfctl_rules: calloc");
1443171172Smlaier	rs = &pf.anchor->ruleset;
1444171172Smlaier	pf_init_ruleset(rs);
1445171172Smlaier	rs->anchor = pf.anchor;
1446171172Smlaier	if (strlcpy(pf.anchor->path, anchorname,
1447171172Smlaier	    sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
1448171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1449171172Smlaier	if (strlcpy(pf.anchor->name, anchorname,
1450171172Smlaier	    sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
1451171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1452171172Smlaier
1453171172Smlaier
1454171172Smlaier	pf.astack[0] = pf.anchor;
1455171172Smlaier	pf.asd = 0;
1456130617Smlaier	if (anchorname[0])
1457130617Smlaier		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1458126353Smlaier	pf.paltq = &pa;
1459130617Smlaier	pf.trans = t;
1460145840Smlaier	pfctl_init_options(&pf);
1461130617Smlaier
1462130617Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
1463171172Smlaier		/*
1464171172Smlaier		 * XXX For the time being we need to open transactions for
1465171172Smlaier		 * the main ruleset before parsing, because tables are still
1466171172Smlaier		 * loaded at parse time.
1467171172Smlaier		 */
1468171172Smlaier		if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
1469171172Smlaier			ERRX("pfctl_rules");
1470130617Smlaier		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1471171172Smlaier			pa.ticket =
1472171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
1473130617Smlaier		if (pf.loadopt & PFCTL_FLAG_TABLE)
1474171172Smlaier			pf.astack[0]->ruleset.tticket =
1475171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
1476130617Smlaier	}
1477171172Smlaier
1478223637Sbz	if (parse_config(filename, &pf) < 0) {
1479126353Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1480126353Smlaier			ERRX("Syntax error in config file: "
1481126353Smlaier			    "pf rules not loaded");
1482126353Smlaier		else
1483126353Smlaier			goto _error;
1484126353Smlaier	}
1485171172Smlaier
1486171172Smlaier	if ((pf.loadopt & PFCTL_FLAG_FILTER &&
1487171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
1488171172Smlaier	    (pf.loadopt & PFCTL_FLAG_NAT &&
1489171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
1490171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
1491171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
1492171172Smlaier	    (pf.loadopt & PFCTL_FLAG_FILTER &&
1493171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
1494171172Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1495171172Smlaier			ERRX("Unable to load rules into kernel");
1496171172Smlaier		else
1497171172Smlaier			goto _error;
1498145840Smlaier	}
1499145840Smlaier
1500130617Smlaier	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1501126353Smlaier		if (check_commit_altq(dev, opts) != 0)
1502126353Smlaier			ERRX("errors in altq config");
1503145840Smlaier
1504126353Smlaier	/* process "load anchor" directives */
1505145840Smlaier	if (!anchorname[0])
1506171172Smlaier		if (pfctl_load_anchors(dev, &pf, t) == -1)
1507126353Smlaier			ERRX("load anchors");
1508126353Smlaier
1509145840Smlaier	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1510145840Smlaier		if (!anchorname[0])
1511145840Smlaier			if (pfctl_load_options(&pf))
1512145840Smlaier				goto _error;
1513171172Smlaier		if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
1514130617Smlaier			ERR("DIOCXCOMMIT");
1515145840Smlaier	}
1516126353Smlaier	return (0);
1517126353Smlaier
1518126353Smlaier_error:
1519130617Smlaier	if (trans == NULL) {	/* main ruleset */
1520130617Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1521171172Smlaier			if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
1522130617Smlaier				err(1, "DIOCXROLLBACK");
1523130617Smlaier		exit(1);
1524145840Smlaier	} else {		/* sub ruleset */
1525130617Smlaier		return (-1);
1526145840Smlaier	}
1527126353Smlaier
1528126353Smlaier#undef ERR
1529126353Smlaier#undef ERRX
1530126353Smlaier}
1531126353Smlaier
1532145840SmlaierFILE *
1533145840Smlaierpfctl_fopen(const char *name, const char *mode)
1534145840Smlaier{
1535145840Smlaier	struct stat	 st;
1536145840Smlaier	FILE		*fp;
1537145840Smlaier
1538145840Smlaier	fp = fopen(name, mode);
1539145840Smlaier	if (fp == NULL)
1540145840Smlaier		return (NULL);
1541145840Smlaier	if (fstat(fileno(fp), &st)) {
1542145840Smlaier		fclose(fp);
1543145840Smlaier		return (NULL);
1544145840Smlaier	}
1545145840Smlaier	if (S_ISDIR(st.st_mode)) {
1546145840Smlaier		fclose(fp);
1547145840Smlaier		errno = EISDIR;
1548145840Smlaier		return (NULL);
1549145840Smlaier	}
1550145840Smlaier	return (fp);
1551145840Smlaier}
1552145840Smlaier
1553145840Smlaiervoid
1554145840Smlaierpfctl_init_options(struct pfctl *pf)
1555145840Smlaier{
1556171172Smlaier
1557145840Smlaier	pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1558145840Smlaier	pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1559145840Smlaier	pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1560145840Smlaier	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1561145840Smlaier	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1562145840Smlaier	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1563145840Smlaier	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1564145840Smlaier	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1565145840Smlaier	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1566145840Smlaier	pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1567145840Smlaier	pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1568145840Smlaier	pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1569145840Smlaier	pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1570145840Smlaier	pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1571145840Smlaier	pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1572145840Smlaier	pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1573145840Smlaier	pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1574145840Smlaier	pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1575171172Smlaier	pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
1576171172Smlaier	pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
1577145840Smlaier
1578171172Smlaier	pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
1579171172Smlaier	pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
1580171172Smlaier	pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
1581171172Smlaier	pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
1582145840Smlaier
1583145840Smlaier	pf->debug = PF_DEBUG_URGENT;
1584145840Smlaier}
1585145840Smlaier
1586126353Smlaierint
1587145840Smlaierpfctl_load_options(struct pfctl *pf)
1588126353Smlaier{
1589145840Smlaier	int i, error = 0;
1590126353Smlaier
1591126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1592126353Smlaier		return (0);
1593126353Smlaier
1594145840Smlaier	/* load limits */
1595145840Smlaier	for (i = 0; i < PF_LIMIT_MAX; i++) {
1596145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1597145840Smlaier			continue;
1598145840Smlaier		if (pfctl_load_limit(pf, i, pf->limit[i]))
1599145840Smlaier			error = 1;
1600145840Smlaier	}
1601145840Smlaier
1602171172Smlaier	/*
1603223637Sbz	 * If we've set the limit, but haven't explicitly set adaptive
1604171172Smlaier	 * timeouts, do it now with a start of 60% and end of 120%.
1605171172Smlaier	 */
1606171172Smlaier	if (pf->limit_set[PF_LIMIT_STATES] &&
1607171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_START] &&
1608171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_END]) {
1609171172Smlaier		pf->timeout[PFTM_ADAPTIVE_START] =
1610171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 6;
1611171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
1612171172Smlaier		pf->timeout[PFTM_ADAPTIVE_END] =
1613171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 12;
1614171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
1615171172Smlaier	}
1616171172Smlaier
1617145840Smlaier	/* load timeouts */
1618145840Smlaier	for (i = 0; i < PFTM_MAX; i++) {
1619145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1620145840Smlaier			continue;
1621145840Smlaier		if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1622145840Smlaier			error = 1;
1623145840Smlaier	}
1624145840Smlaier
1625145840Smlaier	/* load debug */
1626145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1627145840Smlaier		if (pfctl_load_debug(pf, pf->debug))
1628145840Smlaier			error = 1;
1629145840Smlaier
1630145840Smlaier	/* load logif */
1631145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1632145840Smlaier		if (pfctl_load_logif(pf, pf->ifname))
1633145840Smlaier			error = 1;
1634145840Smlaier
1635145840Smlaier	/* load hostid */
1636145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1637145840Smlaier		if (pfctl_load_hostid(pf, pf->hostid))
1638145840Smlaier			error = 1;
1639145840Smlaier
1640145840Smlaier	return (error);
1641145840Smlaier}
1642145840Smlaier
1643145840Smlaierint
1644145840Smlaierpfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1645145840Smlaier{
1646145840Smlaier	int i;
1647145840Smlaier
1648145840Smlaier
1649126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1650126353Smlaier		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1651145840Smlaier			pf->limit[pf_limits[i].index] = limit;
1652145840Smlaier			pf->limit_set[pf_limits[i].index] = 1;
1653126353Smlaier			break;
1654126353Smlaier		}
1655126353Smlaier	}
1656126353Smlaier	if (pf_limits[i].name == NULL) {
1657126353Smlaier		warnx("Bad pool name.");
1658126353Smlaier		return (1);
1659126353Smlaier	}
1660126353Smlaier
1661126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1662126353Smlaier		printf("set limit %s %d\n", opt, limit);
1663126353Smlaier
1664126353Smlaier	return (0);
1665126353Smlaier}
1666126353Smlaier
1667126353Smlaierint
1668145840Smlaierpfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1669145840Smlaier{
1670145840Smlaier	struct pfioc_limit pl;
1671145840Smlaier
1672145840Smlaier	memset(&pl, 0, sizeof(pl));
1673145840Smlaier	pl.index = index;
1674145840Smlaier	pl.limit = limit;
1675145840Smlaier	if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1676145840Smlaier		if (errno == EBUSY)
1677145840Smlaier			warnx("Current pool size exceeds requested hard limit");
1678145840Smlaier		else
1679145840Smlaier			warnx("DIOCSETLIMIT");
1680145840Smlaier		return (1);
1681145840Smlaier	}
1682145840Smlaier	return (0);
1683145840Smlaier}
1684145840Smlaier
1685145840Smlaierint
1686126353Smlaierpfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1687126353Smlaier{
1688126353Smlaier	int i;
1689126353Smlaier
1690126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1691126353Smlaier		return (0);
1692126353Smlaier
1693126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1694126353Smlaier		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1695145840Smlaier			pf->timeout[pf_timeouts[i].timeout] = seconds;
1696145840Smlaier			pf->timeout_set[pf_timeouts[i].timeout] = 1;
1697126353Smlaier			break;
1698126353Smlaier		}
1699126353Smlaier	}
1700126353Smlaier
1701126353Smlaier	if (pf_timeouts[i].name == NULL) {
1702126353Smlaier		warnx("Bad timeout name.");
1703126353Smlaier		return (1);
1704126353Smlaier	}
1705126353Smlaier
1706126353Smlaier
1707126353Smlaier	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1708126353Smlaier		printf("set timeout %s %d\n", opt, seconds);
1709126353Smlaier
1710126353Smlaier	return (0);
1711126353Smlaier}
1712126353Smlaier
1713126353Smlaierint
1714145840Smlaierpfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1715145840Smlaier{
1716145840Smlaier	struct pfioc_tm pt;
1717145840Smlaier
1718145840Smlaier	memset(&pt, 0, sizeof(pt));
1719145840Smlaier	pt.timeout = timeout;
1720145840Smlaier	pt.seconds = seconds;
1721145840Smlaier	if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1722145840Smlaier		warnx("DIOCSETTIMEOUT");
1723145840Smlaier		return (1);
1724145840Smlaier	}
1725145840Smlaier	return (0);
1726145840Smlaier}
1727145840Smlaier
1728145840Smlaierint
1729126353Smlaierpfctl_set_optimization(struct pfctl *pf, const char *opt)
1730126353Smlaier{
1731126353Smlaier	const struct pf_hint *hint;
1732126353Smlaier	int i, r;
1733126353Smlaier
1734126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1735126353Smlaier		return (0);
1736126353Smlaier
1737126353Smlaier	for (i = 0; pf_hints[i].name; i++)
1738126353Smlaier		if (strcasecmp(opt, pf_hints[i].name) == 0)
1739126353Smlaier			break;
1740126353Smlaier
1741126353Smlaier	hint = pf_hints[i].hint;
1742126353Smlaier	if (hint == NULL) {
1743171172Smlaier		warnx("invalid state timeouts optimization");
1744126353Smlaier		return (1);
1745126353Smlaier	}
1746126353Smlaier
1747126353Smlaier	for (i = 0; hint[i].name; i++)
1748126353Smlaier		if ((r = pfctl_set_timeout(pf, hint[i].name,
1749126353Smlaier		    hint[i].timeout, 1)))
1750126353Smlaier			return (r);
1751126353Smlaier
1752126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1753126353Smlaier		printf("set optimization %s\n", opt);
1754126353Smlaier
1755126353Smlaier	return (0);
1756126353Smlaier}
1757126353Smlaier
1758126353Smlaierint
1759126353Smlaierpfctl_set_logif(struct pfctl *pf, char *ifname)
1760126353Smlaier{
1761126353Smlaier
1762126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1763126353Smlaier		return (0);
1764126353Smlaier
1765145840Smlaier	if (!strcmp(ifname, "none")) {
1766145840Smlaier		free(pf->ifname);
1767145840Smlaier		pf->ifname = NULL;
1768145840Smlaier	} else {
1769145840Smlaier		pf->ifname = strdup(ifname);
1770145840Smlaier		if (!pf->ifname)
1771145840Smlaier			errx(1, "pfctl_set_logif: strdup");
1772126353Smlaier	}
1773145840Smlaier	pf->ifname_set = 1;
1774126353Smlaier
1775126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1776126353Smlaier		printf("set loginterface %s\n", ifname);
1777126353Smlaier
1778126353Smlaier	return (0);
1779126353Smlaier}
1780126353Smlaier
1781126353Smlaierint
1782145840Smlaierpfctl_load_logif(struct pfctl *pf, char *ifname)
1783145840Smlaier{
1784145840Smlaier	struct pfioc_if pi;
1785145840Smlaier
1786145840Smlaier	memset(&pi, 0, sizeof(pi));
1787145840Smlaier	if (ifname && strlcpy(pi.ifname, ifname,
1788145840Smlaier	    sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1789171172Smlaier		warnx("pfctl_load_logif: strlcpy");
1790145840Smlaier		return (1);
1791145840Smlaier	}
1792145840Smlaier	if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1793145840Smlaier		warnx("DIOCSETSTATUSIF");
1794145840Smlaier		return (1);
1795145840Smlaier	}
1796145840Smlaier	return (0);
1797145840Smlaier}
1798145840Smlaier
1799145840Smlaierint
1800130617Smlaierpfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1801130617Smlaier{
1802130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1803130617Smlaier		return (0);
1804130617Smlaier
1805130617Smlaier	HTONL(hostid);
1806130617Smlaier
1807145840Smlaier	pf->hostid = hostid;
1808145840Smlaier	pf->hostid_set = 1;
1809130617Smlaier
1810130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1811130617Smlaier		printf("set hostid 0x%08x\n", ntohl(hostid));
1812130617Smlaier
1813130617Smlaier	return (0);
1814130617Smlaier}
1815130617Smlaier
1816130617Smlaierint
1817145840Smlaierpfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1818145840Smlaier{
1819145840Smlaier	if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1820145840Smlaier		warnx("DIOCSETHOSTID");
1821145840Smlaier		return (1);
1822145840Smlaier	}
1823145840Smlaier	return (0);
1824145840Smlaier}
1825145840Smlaier
1826145840Smlaierint
1827130617Smlaierpfctl_set_debug(struct pfctl *pf, char *d)
1828130617Smlaier{
1829130617Smlaier	u_int32_t	level;
1830130617Smlaier
1831130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1832130617Smlaier		return (0);
1833130617Smlaier
1834130617Smlaier	if (!strcmp(d, "none"))
1835145840Smlaier		pf->debug = PF_DEBUG_NONE;
1836130617Smlaier	else if (!strcmp(d, "urgent"))
1837145840Smlaier		pf->debug = PF_DEBUG_URGENT;
1838130617Smlaier	else if (!strcmp(d, "misc"))
1839145840Smlaier		pf->debug = PF_DEBUG_MISC;
1840130617Smlaier	else if (!strcmp(d, "loud"))
1841145840Smlaier		pf->debug = PF_DEBUG_NOISY;
1842130617Smlaier	else {
1843130617Smlaier		warnx("unknown debug level \"%s\"", d);
1844130617Smlaier		return (-1);
1845130617Smlaier	}
1846130617Smlaier
1847145840Smlaier	pf->debug_set = 1;
1848292288Skp	level = pf->debug;
1849145840Smlaier
1850130617Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1851130617Smlaier		if (ioctl(dev, DIOCSETDEBUG, &level))
1852130617Smlaier			err(1, "DIOCSETDEBUG");
1853130617Smlaier
1854130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1855130617Smlaier		printf("set debug %s\n", d);
1856130617Smlaier
1857130617Smlaier	return (0);
1858130617Smlaier}
1859130617Smlaier
1860130617Smlaierint
1861145840Smlaierpfctl_load_debug(struct pfctl *pf, unsigned int level)
1862145840Smlaier{
1863145840Smlaier	if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1864145840Smlaier		warnx("DIOCSETDEBUG");
1865145840Smlaier		return (1);
1866145840Smlaier	}
1867145840Smlaier	return (0);
1868145840Smlaier}
1869145840Smlaier
1870145840Smlaierint
1871145840Smlaierpfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1872145840Smlaier{
1873145840Smlaier	struct pfioc_iface	pi;
1874145840Smlaier
1875145840Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1876145840Smlaier		return (0);
1877145840Smlaier
1878145840Smlaier	bzero(&pi, sizeof(pi));
1879145840Smlaier
1880145840Smlaier	pi.pfiio_flags = flags;
1881145840Smlaier
1882145840Smlaier	if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
1883145840Smlaier	    sizeof(pi.pfiio_name))
1884145840Smlaier		errx(1, "pfctl_set_interface_flags: strlcpy");
1885145840Smlaier
1886145840Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1887145840Smlaier		if (how == 0) {
1888145840Smlaier			if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
1889145840Smlaier				err(1, "DIOCCLRIFFLAG");
1890145840Smlaier		} else {
1891145840Smlaier			if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
1892145840Smlaier				err(1, "DIOCSETIFFLAG");
1893145840Smlaier		}
1894145840Smlaier	}
1895145840Smlaier	return (0);
1896145840Smlaier}
1897145840Smlaier
1898145840Smlaiervoid
1899126353Smlaierpfctl_debug(int dev, u_int32_t level, int opts)
1900126353Smlaier{
1901126353Smlaier	if (ioctl(dev, DIOCSETDEBUG, &level))
1902126353Smlaier		err(1, "DIOCSETDEBUG");
1903126353Smlaier	if ((opts & PF_OPT_QUIET) == 0) {
1904126353Smlaier		fprintf(stderr, "debug level set to '");
1905126353Smlaier		switch (level) {
1906126353Smlaier		case PF_DEBUG_NONE:
1907126353Smlaier			fprintf(stderr, "none");
1908126353Smlaier			break;
1909126353Smlaier		case PF_DEBUG_URGENT:
1910126353Smlaier			fprintf(stderr, "urgent");
1911126353Smlaier			break;
1912126353Smlaier		case PF_DEBUG_MISC:
1913126353Smlaier			fprintf(stderr, "misc");
1914126353Smlaier			break;
1915126353Smlaier		case PF_DEBUG_NOISY:
1916126353Smlaier			fprintf(stderr, "loud");
1917126353Smlaier			break;
1918126353Smlaier		default:
1919126353Smlaier			fprintf(stderr, "<invalid>");
1920126353Smlaier			break;
1921126353Smlaier		}
1922126353Smlaier		fprintf(stderr, "'\n");
1923126353Smlaier	}
1924126353Smlaier}
1925126353Smlaier
1926126353Smlaierint
1927126353Smlaierpfctl_test_altqsupport(int dev, int opts)
1928126353Smlaier{
1929126353Smlaier	struct pfioc_altq pa;
1930126353Smlaier
1931126353Smlaier	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1932126353Smlaier		if (errno == ENODEV) {
1933296370Sgnn			if (opts & PF_OPT_VERBOSE)
1934126353Smlaier				fprintf(stderr, "No ALTQ support in kernel\n"
1935126353Smlaier				    "ALTQ related functions disabled\n");
1936126353Smlaier			return (0);
1937126353Smlaier		} else
1938126353Smlaier			err(1, "DIOCGETALTQS");
1939126353Smlaier	}
1940126353Smlaier	return (1);
1941126353Smlaier}
1942126353Smlaier
1943126353Smlaierint
1944126353Smlaierpfctl_show_anchors(int dev, int opts, char *anchorname)
1945126353Smlaier{
1946145840Smlaier	struct pfioc_ruleset	 pr;
1947145840Smlaier	u_int32_t		 mnr, nr;
1948126353Smlaier
1949145840Smlaier	memset(&pr, 0, sizeof(pr));
1950145840Smlaier	memcpy(pr.path, anchorname, sizeof(pr.path));
1951145840Smlaier	if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1952145840Smlaier		if (errno == EINVAL)
1953145840Smlaier			fprintf(stderr, "Anchor '%s' not found.\n",
1954145840Smlaier			    anchorname);
1955145840Smlaier		else
1956145840Smlaier			err(1, "DIOCGETRULESETS");
1957145840Smlaier		return (-1);
1958145840Smlaier	}
1959145840Smlaier	mnr = pr.nr;
1960145840Smlaier	for (nr = 0; nr < mnr; ++nr) {
1961145840Smlaier		char sub[MAXPATHLEN];
1962126353Smlaier
1963145840Smlaier		pr.nr = nr;
1964145840Smlaier		if (ioctl(dev, DIOCGETRULESET, &pr))
1965145840Smlaier			err(1, "DIOCGETRULESET");
1966145840Smlaier		if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
1967145840Smlaier			continue;
1968145840Smlaier		sub[0] = 0;
1969145840Smlaier		if (pr.path[0]) {
1970145840Smlaier			strlcat(sub, pr.path, sizeof(sub));
1971145840Smlaier			strlcat(sub, "/", sizeof(sub));
1972126353Smlaier		}
1973145840Smlaier		strlcat(sub, pr.name, sizeof(sub));
1974171172Smlaier		if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
1975171172Smlaier			printf("  %s\n", sub);
1976171172Smlaier		if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
1977126353Smlaier			return (-1);
1978126353Smlaier	}
1979126353Smlaier	return (0);
1980126353Smlaier}
1981126353Smlaier
1982126353Smlaierconst char *
1983126353Smlaierpfctl_lookup_option(char *cmd, const char **list)
1984126353Smlaier{
1985126353Smlaier	if (cmd != NULL && *cmd)
1986126353Smlaier		for (; *list; list++)
1987126353Smlaier			if (!strncmp(cmd, *list, strlen(cmd)))
1988126353Smlaier				return (*list);
1989126353Smlaier	return (NULL);
1990126353Smlaier}
1991126353Smlaier
1992126353Smlaierint
1993126353Smlaiermain(int argc, char *argv[])
1994126353Smlaier{
1995171172Smlaier	int	 error = 0;
1996171172Smlaier	int	 ch;
1997171172Smlaier	int	 mode = O_RDONLY;
1998171172Smlaier	int	 opts = 0;
1999223637Sbz	int	 optimize = PF_OPTIMIZE_BASIC;
2000171172Smlaier	char	 anchorname[MAXPATHLEN];
2001171172Smlaier	char	*path;
2002126353Smlaier
2003126353Smlaier	if (argc < 2)
2004126353Smlaier		usage();
2005126353Smlaier
2006130617Smlaier	while ((ch = getopt(argc, argv,
2007223637Sbz	    "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
2008126353Smlaier		switch (ch) {
2009126353Smlaier		case 'a':
2010126353Smlaier			anchoropt = optarg;
2011126353Smlaier			break;
2012126353Smlaier		case 'd':
2013126353Smlaier			opts |= PF_OPT_DISABLE;
2014126353Smlaier			mode = O_RDWR;
2015126353Smlaier			break;
2016126353Smlaier		case 'D':
2017126353Smlaier			if (pfctl_cmdline_symset(optarg) < 0)
2018126353Smlaier				warnx("could not parse macro definition %s",
2019126353Smlaier				    optarg);
2020126353Smlaier			break;
2021126353Smlaier		case 'e':
2022126353Smlaier			opts |= PF_OPT_ENABLE;
2023126353Smlaier			mode = O_RDWR;
2024126353Smlaier			break;
2025126353Smlaier		case 'q':
2026126353Smlaier			opts |= PF_OPT_QUIET;
2027126353Smlaier			break;
2028126353Smlaier		case 'F':
2029126353Smlaier			clearopt = pfctl_lookup_option(optarg, clearopt_list);
2030126353Smlaier			if (clearopt == NULL) {
2031126353Smlaier				warnx("Unknown flush modifier '%s'", optarg);
2032126353Smlaier				usage();
2033126353Smlaier			}
2034126353Smlaier			mode = O_RDWR;
2035126353Smlaier			break;
2036130617Smlaier		case 'i':
2037130617Smlaier			ifaceopt = optarg;
2038130617Smlaier			break;
2039126353Smlaier		case 'k':
2040126353Smlaier			if (state_killers >= 2) {
2041126353Smlaier				warnx("can only specify -k twice");
2042126353Smlaier				usage();
2043126353Smlaier				/* NOTREACHED */
2044126353Smlaier			}
2045126353Smlaier			state_kill[state_killers++] = optarg;
2046126353Smlaier			mode = O_RDWR;
2047126353Smlaier			break;
2048171172Smlaier		case 'K':
2049171172Smlaier			if (src_node_killers >= 2) {
2050171172Smlaier				warnx("can only specify -K twice");
2051171172Smlaier				usage();
2052171172Smlaier				/* NOTREACHED */
2053171172Smlaier			}
2054171172Smlaier			src_node_kill[src_node_killers++] = optarg;
2055171172Smlaier			mode = O_RDWR;
2056171172Smlaier			break;
2057145840Smlaier		case 'm':
2058145840Smlaier			opts |= PF_OPT_MERGE;
2059145840Smlaier			break;
2060126353Smlaier		case 'n':
2061126353Smlaier			opts |= PF_OPT_NOACTION;
2062126353Smlaier			break;
2063126353Smlaier		case 'N':
2064126353Smlaier			loadopt |= PFCTL_FLAG_NAT;
2065126353Smlaier			break;
2066126353Smlaier		case 'r':
2067126353Smlaier			opts |= PF_OPT_USEDNS;
2068126353Smlaier			break;
2069126353Smlaier		case 'f':
2070126353Smlaier			rulesopt = optarg;
2071126353Smlaier			mode = O_RDWR;
2072126353Smlaier			break;
2073126353Smlaier		case 'g':
2074126353Smlaier			opts |= PF_OPT_DEBUG;
2075126353Smlaier			break;
2076126353Smlaier		case 'A':
2077126353Smlaier			loadopt |= PFCTL_FLAG_ALTQ;
2078126353Smlaier			break;
2079126353Smlaier		case 'R':
2080126353Smlaier			loadopt |= PFCTL_FLAG_FILTER;
2081126353Smlaier			break;
2082145840Smlaier		case 'o':
2083223637Sbz			optiopt = pfctl_lookup_option(optarg, optiopt_list);
2084223637Sbz			if (optiopt == NULL) {
2085223637Sbz				warnx("Unknown optimization '%s'", optarg);
2086223637Sbz				usage();
2087171172Smlaier			}
2088171172Smlaier			opts |= PF_OPT_OPTIMIZE;
2089145840Smlaier			break;
2090126353Smlaier		case 'O':
2091126353Smlaier			loadopt |= PFCTL_FLAG_OPTION;
2092126353Smlaier			break;
2093130617Smlaier		case 'p':
2094130617Smlaier			pf_device = optarg;
2095130617Smlaier			break;
2096223057Sbz		case 'P':
2097223057Sbz			opts |= PF_OPT_NUMERIC;
2098223057Sbz			break;
2099126353Smlaier		case 's':
2100126353Smlaier			showopt = pfctl_lookup_option(optarg, showopt_list);
2101126353Smlaier			if (showopt == NULL) {
2102126353Smlaier				warnx("Unknown show modifier '%s'", optarg);
2103126353Smlaier				usage();
2104126353Smlaier			}
2105126353Smlaier			break;
2106126353Smlaier		case 't':
2107126353Smlaier			tableopt = optarg;
2108126353Smlaier			break;
2109126353Smlaier		case 'T':
2110126353Smlaier			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
2111126353Smlaier			if (tblcmdopt == NULL) {
2112126353Smlaier				warnx("Unknown table command '%s'", optarg);
2113126353Smlaier				usage();
2114126353Smlaier			}
2115126353Smlaier			break;
2116126353Smlaier		case 'v':
2117126353Smlaier			if (opts & PF_OPT_VERBOSE)
2118126353Smlaier				opts |= PF_OPT_VERBOSE2;
2119126353Smlaier			opts |= PF_OPT_VERBOSE;
2120126353Smlaier			break;
2121126353Smlaier		case 'x':
2122126353Smlaier			debugopt = pfctl_lookup_option(optarg, debugopt_list);
2123126353Smlaier			if (debugopt == NULL) {
2124126353Smlaier				warnx("Unknown debug level '%s'", optarg);
2125126353Smlaier				usage();
2126126353Smlaier			}
2127126353Smlaier			mode = O_RDWR;
2128126353Smlaier			break;
2129126353Smlaier		case 'z':
2130126353Smlaier			opts |= PF_OPT_CLRRULECTRS;
2131126353Smlaier			mode = O_RDWR;
2132126353Smlaier			break;
2133126353Smlaier		case 'h':
2134126353Smlaier			/* FALLTHROUGH */
2135126353Smlaier		default:
2136126353Smlaier			usage();
2137126353Smlaier			/* NOTREACHED */
2138126353Smlaier		}
2139126353Smlaier	}
2140126353Smlaier
2141126353Smlaier	if (tblcmdopt != NULL) {
2142126353Smlaier		argc -= optind;
2143126353Smlaier		argv += optind;
2144126353Smlaier		ch = *tblcmdopt;
2145126353Smlaier		if (ch == 'l') {
2146126353Smlaier			loadopt |= PFCTL_FLAG_TABLE;
2147126353Smlaier			tblcmdopt = NULL;
2148130617Smlaier		} else
2149171172Smlaier			mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
2150126353Smlaier	} else if (argc != optind) {
2151126353Smlaier		warnx("unknown command line argument: %s ...", argv[optind]);
2152126353Smlaier		usage();
2153126353Smlaier		/* NOTREACHED */
2154126353Smlaier	}
2155126353Smlaier	if (loadopt == 0)
2156126353Smlaier		loadopt = ~0;
2157126353Smlaier
2158171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
2159171172Smlaier		errx(1, "pfctl: calloc");
2160126353Smlaier	memset(anchorname, 0, sizeof(anchorname));
2161126353Smlaier	if (anchoropt != NULL) {
2162171172Smlaier		int len = strlen(anchoropt);
2163171172Smlaier
2164171172Smlaier		if (anchoropt[len - 1] == '*') {
2165171172Smlaier			if (len >= 2 && anchoropt[len - 2] == '/')
2166171172Smlaier				anchoropt[len - 2] = '\0';
2167171172Smlaier			else
2168171172Smlaier				anchoropt[len - 1] = '\0';
2169171172Smlaier			opts |= PF_OPT_RECURSE;
2170171172Smlaier		}
2171145840Smlaier		if (strlcpy(anchorname, anchoropt,
2172145840Smlaier		    sizeof(anchorname)) >= sizeof(anchorname))
2173145840Smlaier			errx(1, "anchor name '%s' too long",
2174145840Smlaier			    anchoropt);
2175126353Smlaier		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
2176126353Smlaier	}
2177126353Smlaier
2178126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
2179130617Smlaier		dev = open(pf_device, mode);
2180126353Smlaier		if (dev == -1)
2181130617Smlaier			err(1, "%s", pf_device);
2182126353Smlaier		altqsupport = pfctl_test_altqsupport(dev, opts);
2183126353Smlaier	} else {
2184130617Smlaier		dev = open(pf_device, O_RDONLY);
2185130617Smlaier		if (dev >= 0)
2186130617Smlaier			opts |= PF_OPT_DUMMYACTION;
2187126353Smlaier		/* turn off options */
2188126353Smlaier		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
2189126353Smlaier		clearopt = showopt = debugopt = NULL;
2190126355Smlaier#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
2191126355Smlaier		altqsupport = 0;
2192126355Smlaier#else
2193126353Smlaier		altqsupport = 1;
2194126355Smlaier#endif
2195126353Smlaier	}
2196126353Smlaier
2197126353Smlaier	if (opts & PF_OPT_DISABLE)
2198126353Smlaier		if (pfctl_disable(dev, opts))
2199126353Smlaier			error = 1;
2200126353Smlaier
2201126353Smlaier	if (showopt != NULL) {
2202126353Smlaier		switch (*showopt) {
2203126353Smlaier		case 'A':
2204126353Smlaier			pfctl_show_anchors(dev, opts, anchorname);
2205126353Smlaier			break;
2206126353Smlaier		case 'r':
2207126353Smlaier			pfctl_load_fingerprints(dev, opts);
2208171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
2209171172Smlaier			    anchorname, 0);
2210126353Smlaier			break;
2211126353Smlaier		case 'l':
2212126353Smlaier			pfctl_load_fingerprints(dev, opts);
2213171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
2214171172Smlaier			    anchorname, 0);
2215126353Smlaier			break;
2216126353Smlaier		case 'n':
2217126353Smlaier			pfctl_load_fingerprints(dev, opts);
2218145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2219126353Smlaier			break;
2220126353Smlaier		case 'q':
2221130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts,
2222130617Smlaier			    opts & PF_OPT_VERBOSE2);
2223126353Smlaier			break;
2224126353Smlaier		case 's':
2225130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2226126353Smlaier			break;
2227130617Smlaier		case 'S':
2228130617Smlaier			pfctl_show_src_nodes(dev, opts);
2229130617Smlaier			break;
2230126353Smlaier		case 'i':
2231130617Smlaier			pfctl_show_status(dev, opts);
2232126353Smlaier			break;
2233126353Smlaier		case 't':
2234130617Smlaier			pfctl_show_timeouts(dev, opts);
2235126353Smlaier			break;
2236126353Smlaier		case 'm':
2237130617Smlaier			pfctl_show_limits(dev, opts);
2238126353Smlaier			break;
2239126353Smlaier		case 'a':
2240130617Smlaier			opts |= PF_OPT_SHOWALL;
2241126353Smlaier			pfctl_load_fingerprints(dev, opts);
2242126353Smlaier
2243145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2244171172Smlaier			pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
2245130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts, 0);
2246130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2247130617Smlaier			pfctl_show_src_nodes(dev, opts);
2248130617Smlaier			pfctl_show_status(dev, opts);
2249171172Smlaier			pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
2250130617Smlaier			pfctl_show_timeouts(dev, opts);
2251130617Smlaier			pfctl_show_limits(dev, opts);
2252145840Smlaier			pfctl_show_tables(anchorname, opts);
2253126353Smlaier			pfctl_show_fingerprints(opts);
2254126353Smlaier			break;
2255126353Smlaier		case 'T':
2256145840Smlaier			pfctl_show_tables(anchorname, opts);
2257126353Smlaier			break;
2258126353Smlaier		case 'o':
2259126353Smlaier			pfctl_load_fingerprints(dev, opts);
2260126353Smlaier			pfctl_show_fingerprints(opts);
2261126353Smlaier			break;
2262130617Smlaier		case 'I':
2263130617Smlaier			pfctl_show_ifaces(ifaceopt, opts);
2264130617Smlaier			break;
2265126353Smlaier		}
2266126353Smlaier	}
2267126353Smlaier
2268171172Smlaier	if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
2269171172Smlaier		pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
2270171172Smlaier		    anchorname, 0);
2271171172Smlaier
2272126353Smlaier	if (clearopt != NULL) {
2273171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2274171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2275171172Smlaier			    "be modified from the command line");
2276171172Smlaier
2277126353Smlaier		switch (*clearopt) {
2278126353Smlaier		case 'r':
2279145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2280126353Smlaier			break;
2281126353Smlaier		case 'n':
2282145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2283126353Smlaier			break;
2284126353Smlaier		case 'q':
2285126353Smlaier			pfctl_clear_altq(dev, opts);
2286126353Smlaier			break;
2287126353Smlaier		case 's':
2288130617Smlaier			pfctl_clear_states(dev, ifaceopt, opts);
2289126353Smlaier			break;
2290130617Smlaier		case 'S':
2291130617Smlaier			pfctl_clear_src_nodes(dev, opts);
2292130617Smlaier			break;
2293126353Smlaier		case 'i':
2294126353Smlaier			pfctl_clear_stats(dev, opts);
2295126353Smlaier			break;
2296126353Smlaier		case 'a':
2297145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2298145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2299145840Smlaier			pfctl_clear_tables(anchorname, opts);
2300145840Smlaier			if (!*anchorname) {
2301130617Smlaier				pfctl_clear_altq(dev, opts);
2302130617Smlaier				pfctl_clear_states(dev, ifaceopt, opts);
2303130617Smlaier				pfctl_clear_src_nodes(dev, opts);
2304130617Smlaier				pfctl_clear_stats(dev, opts);
2305130617Smlaier				pfctl_clear_fingerprints(dev, opts);
2306145840Smlaier				pfctl_clear_interface_flags(dev, opts);
2307130617Smlaier			}
2308126353Smlaier			break;
2309126353Smlaier		case 'o':
2310126353Smlaier			pfctl_clear_fingerprints(dev, opts);
2311126353Smlaier			break;
2312126353Smlaier		case 'T':
2313145840Smlaier			pfctl_clear_tables(anchorname, opts);
2314126353Smlaier			break;
2315126353Smlaier		}
2316126353Smlaier	}
2317223637Sbz	if (state_killers) {
2318223637Sbz		if (!strcmp(state_kill[0], "label"))
2319223637Sbz			pfctl_label_kill_states(dev, ifaceopt, opts);
2320223637Sbz		else if (!strcmp(state_kill[0], "id"))
2321223637Sbz			pfctl_id_kill_states(dev, ifaceopt, opts);
2322223637Sbz		else
2323223637Sbz			pfctl_net_kill_states(dev, ifaceopt, opts);
2324223637Sbz	}
2325126353Smlaier
2326171172Smlaier	if (src_node_killers)
2327171172Smlaier		pfctl_kill_src_nodes(dev, ifaceopt, opts);
2328171172Smlaier
2329126353Smlaier	if (tblcmdopt != NULL) {
2330126353Smlaier		error = pfctl_command_tables(argc, argv, tableopt,
2331145840Smlaier		    tblcmdopt, rulesopt, anchorname, opts);
2332126353Smlaier		rulesopt = NULL;
2333126353Smlaier	}
2334171172Smlaier	if (optiopt != NULL) {
2335171172Smlaier		switch (*optiopt) {
2336171172Smlaier		case 'n':
2337171172Smlaier			optimize = 0;
2338171172Smlaier			break;
2339171172Smlaier		case 'b':
2340171172Smlaier			optimize |= PF_OPTIMIZE_BASIC;
2341171172Smlaier			break;
2342171172Smlaier		case 'o':
2343171172Smlaier		case 'p':
2344171172Smlaier			optimize |= PF_OPTIMIZE_PROFILE;
2345171172Smlaier			break;
2346171172Smlaier		}
2347171172Smlaier	}
2348126353Smlaier
2349171172Smlaier	if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
2350171172Smlaier	    !anchorname[0])
2351145840Smlaier		if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
2352145840Smlaier			error = 1;
2353145840Smlaier
2354145840Smlaier	if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
2355145840Smlaier	    !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
2356126353Smlaier		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
2357126353Smlaier			error = 1;
2358126353Smlaier
2359126353Smlaier	if (rulesopt != NULL) {
2360171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2361171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2362171172Smlaier			    "be modified from the command line");
2363223637Sbz		if (pfctl_rules(dev, rulesopt, opts, optimize,
2364171172Smlaier		    anchorname, NULL))
2365126353Smlaier			error = 1;
2366126353Smlaier		else if (!(opts & PF_OPT_NOACTION) &&
2367126353Smlaier		    (loadopt & PFCTL_FLAG_TABLE))
2368126353Smlaier			warn_namespace_collision(NULL);
2369126353Smlaier	}
2370126353Smlaier
2371126353Smlaier	if (opts & PF_OPT_ENABLE)
2372126353Smlaier		if (pfctl_enable(dev, opts))
2373126353Smlaier			error = 1;
2374126353Smlaier
2375126353Smlaier	if (debugopt != NULL) {
2376126353Smlaier		switch (*debugopt) {
2377126353Smlaier		case 'n':
2378126353Smlaier			pfctl_debug(dev, PF_DEBUG_NONE, opts);
2379126353Smlaier			break;
2380126353Smlaier		case 'u':
2381126353Smlaier			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
2382126353Smlaier			break;
2383126353Smlaier		case 'm':
2384126353Smlaier			pfctl_debug(dev, PF_DEBUG_MISC, opts);
2385126353Smlaier			break;
2386126353Smlaier		case 'l':
2387126353Smlaier			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
2388126353Smlaier			break;
2389126353Smlaier		}
2390126353Smlaier	}
2391126353Smlaier
2392126353Smlaier	exit(error);
2393126353Smlaier}
2394