pfctl.c revision 171172
1171172Smlaier/*	$OpenBSD: pfctl.c,v 1.262 2007/03/01 17:20:53 deraadt Exp $ */
2126353Smlaier
3126353Smlaier/*
4126353Smlaier * Copyright (c) 2001 Daniel Hartmeier
5130617Smlaier * Copyright (c) 2002,2003 Henning Brauer
6126353Smlaier * All rights reserved.
7126353Smlaier *
8126353Smlaier * Redistribution and use in source and binary forms, with or without
9126353Smlaier * modification, are permitted provided that the following conditions
10126353Smlaier * are met:
11126353Smlaier *
12126353Smlaier *    - Redistributions of source code must retain the above copyright
13126353Smlaier *      notice, this list of conditions and the following disclaimer.
14126353Smlaier *    - Redistributions in binary form must reproduce the above
15126353Smlaier *      copyright notice, this list of conditions and the following
16126353Smlaier *      disclaimer in the documentation and/or other materials provided
17126353Smlaier *      with the distribution.
18126353Smlaier *
19126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20126353Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21126353Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22126353Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23126353Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24126353Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25126353Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26126353Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27126353Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29126353Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30126353Smlaier * POSSIBILITY OF SUCH DAMAGE.
31126353Smlaier *
32126353Smlaier */
33126353Smlaier
34127082Sobrien#include <sys/cdefs.h>
35127082Sobrien__FBSDID("$FreeBSD: head/contrib/pf/pfctl/pfctl.c 171172 2007-07-03 12:30:03Z mlaier $");
36127082Sobrien
37126353Smlaier#include <sys/types.h>
38126353Smlaier#include <sys/ioctl.h>
39126353Smlaier#include <sys/socket.h>
40145840Smlaier#include <sys/stat.h>
41126353Smlaier
42126353Smlaier#include <net/if.h>
43126353Smlaier#include <netinet/in.h>
44126353Smlaier#include <net/pfvar.h>
45126353Smlaier#include <arpa/inet.h>
46126353Smlaier#include <altq/altq.h>
47171172Smlaier#include <sys/sysctl.h>
48126353Smlaier
49126353Smlaier#include <err.h>
50126353Smlaier#include <errno.h>
51126353Smlaier#include <fcntl.h>
52126353Smlaier#include <limits.h>
53126353Smlaier#include <netdb.h>
54126353Smlaier#include <stdio.h>
55126353Smlaier#include <stdlib.h>
56126353Smlaier#include <string.h>
57126353Smlaier#include <unistd.h>
58126353Smlaier
59126353Smlaier#include "pfctl_parser.h"
60126353Smlaier#include "pfctl.h"
61126353Smlaier
62130617Smlaier#ifdef __FreeBSD__
63130617Smlaier#define HTONL(x)	(x) = htonl((__uint32_t)(x))
64130617Smlaier#endif
65130617Smlaier
66126353Smlaiervoid	 usage(void);
67126353Smlaierint	 pfctl_enable(int, int);
68126353Smlaierint	 pfctl_disable(int, int);
69126353Smlaierint	 pfctl_clear_stats(int, int);
70145840Smlaierint	 pfctl_clear_interface_flags(int, int);
71145840Smlaierint	 pfctl_clear_rules(int, int, char *);
72145840Smlaierint	 pfctl_clear_nat(int, int, char *);
73126353Smlaierint	 pfctl_clear_altq(int, int);
74130617Smlaierint	 pfctl_clear_src_nodes(int, int);
75130617Smlaierint	 pfctl_clear_states(int, const char *, int);
76171172Smlaiervoid	 pfctl_addrprefix(char *, struct pf_addr *);
77171172Smlaierint	 pfctl_kill_src_nodes(int, const char *, int);
78130617Smlaierint	 pfctl_kill_states(int, const char *, int);
79145840Smlaiervoid	 pfctl_init_options(struct pfctl *);
80145840Smlaierint	 pfctl_load_options(struct pfctl *);
81145840Smlaierint	 pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
82145840Smlaierint	 pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
83145840Smlaierint	 pfctl_load_debug(struct pfctl *, unsigned int);
84145840Smlaierint	 pfctl_load_logif(struct pfctl *, char *);
85145840Smlaierint	 pfctl_load_hostid(struct pfctl *, unsigned int);
86126353Smlaierint	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
87145840Smlaier	    char *);
88126353Smlaiervoid	 pfctl_print_rule_counters(struct pf_rule *, int);
89171172Smlaierint	 pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
90145840Smlaierint	 pfctl_show_nat(int, int, char *);
91130617Smlaierint	 pfctl_show_src_nodes(int, int);
92130617Smlaierint	 pfctl_show_states(int, const char *, int);
93130617Smlaierint	 pfctl_show_status(int, int);
94130617Smlaierint	 pfctl_show_timeouts(int, int);
95130617Smlaierint	 pfctl_show_limits(int, int);
96145840Smlaiervoid	 pfctl_debug(int, u_int32_t, int);
97126353Smlaierint	 pfctl_test_altqsupport(int, int);
98126353Smlaierint	 pfctl_show_anchors(int, int, char *);
99171172Smlaierint	 pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
100171172Smlaierint	 pfctl_load_ruleset(struct pfctl *, char *,
101171172Smlaier		struct pf_ruleset *, int, int);
102171172Smlaierint	 pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
103126353Smlaierconst char	*pfctl_lookup_option(char *, const char **);
104126353Smlaier
105171172Smlaierstruct pf_anchor_global	 pf_anchors;
106171172Smlaierstruct pf_anchor	 pf_main_anchor;
107171172Smlaier
108126353Smlaierconst char	*clearopt;
109126353Smlaierchar		*rulesopt;
110126353Smlaierconst char	*showopt;
111126353Smlaierconst char	*debugopt;
112126353Smlaierchar		*anchoropt;
113171172Smlaierconst char	*optiopt = NULL;
114130617Smlaierchar		*pf_device = "/dev/pf";
115130617Smlaierchar		*ifaceopt;
116126353Smlaierchar		*tableopt;
117126353Smlaierconst char	*tblcmdopt;
118171172Smlaierint		 src_node_killers;
119171172Smlaierchar		*src_node_kill[2];
120126353Smlaierint		 state_killers;
121126353Smlaierchar		*state_kill[2];
122126353Smlaierint		 loadopt;
123126353Smlaierint		 altqsupport;
124126353Smlaier
125126353Smlaierint		 dev = -1;
126130617Smlaierint		 first_title = 1;
127130617Smlaierint		 labels = 0;
128126353Smlaier
129126353Smlaierconst char	*infile;
130126353Smlaier
131171172Smlaier#define INDENT(d, o)	do {						\
132171172Smlaier				if (o) {				\
133171172Smlaier					int i;				\
134171172Smlaier					for (i=0; i < d; i++)		\
135171172Smlaier						printf("  ");		\
136171172Smlaier				}					\
137171172Smlaier			} while (0);					\
138171172Smlaier
139171172Smlaier
140126353Smlaierstatic const struct {
141126353Smlaier	const char	*name;
142126353Smlaier	int		index;
143126353Smlaier} pf_limits[] = {
144171172Smlaier	{ "states",		PF_LIMIT_STATES },
145171172Smlaier	{ "src-nodes",		PF_LIMIT_SRC_NODES },
146171172Smlaier	{ "frags",		PF_LIMIT_FRAGS },
147171172Smlaier	{ "tables",		PF_LIMIT_TABLES },
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",
211130617Smlaier	"state", "info", "Tables", "osfp", "all", NULL
212126353Smlaier};
213126353Smlaier
214126353Smlaierstatic const char *showopt_list[] = {
215130617Smlaier	"nat", "queue", "rules", "Anchors", "Sources", "state", "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[] = {
230171172Smlaier	"o", "none", "basic", "profile", NULL
231171172Smlaier};
232126353Smlaier
233126353Smlaiervoid
234126353Smlaierusage(void)
235126353Smlaier{
236126353Smlaier	extern char *__progname;
237126353Smlaier
238171172Smlaier	fprintf(stderr, "usage: %s [-AdeghmNnOqRrvz] ", __progname);
239145840Smlaier	fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
240171172Smlaier	fprintf(stderr, "\t[-f file] [-i interface] [-K host | network] ");
241171172Smlaier	fprintf(stderr, "[-k host | network ]\n");
242171172Smlaier	fprintf(stderr, "\t[-o [level]] [-p device] [-s modifier ]\n");
243171172Smlaier	fprintf(stderr, "\t[-t table -T command [address ...]] [-x level]\n");
244126353Smlaier	exit(1);
245126353Smlaier}
246126353Smlaier
247126353Smlaierint
248126353Smlaierpfctl_enable(int dev, int opts)
249126353Smlaier{
250126353Smlaier	if (ioctl(dev, DIOCSTART)) {
251126353Smlaier		if (errno == EEXIST)
252126353Smlaier			errx(1, "pf already enabled");
253127024Smlaier#ifdef __FreeBSD__
254126355Smlaier		else if (errno == ESRCH)
255126355Smlaier			errx(1, "pfil registeration failed");
256126355Smlaier#endif
257126353Smlaier		else
258126353Smlaier			err(1, "DIOCSTART");
259126353Smlaier	}
260126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
261126353Smlaier		fprintf(stderr, "pf enabled\n");
262126353Smlaier
263126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
264126353Smlaier		if (errno != EEXIST)
265126353Smlaier			err(1, "DIOCSTARTALTQ");
266126353Smlaier
267126353Smlaier	return (0);
268126353Smlaier}
269126353Smlaier
270126353Smlaierint
271126353Smlaierpfctl_disable(int dev, int opts)
272126353Smlaier{
273126353Smlaier	if (ioctl(dev, DIOCSTOP)) {
274126353Smlaier		if (errno == ENOENT)
275126353Smlaier			errx(1, "pf not enabled");
276126353Smlaier		else
277126353Smlaier			err(1, "DIOCSTOP");
278126353Smlaier	}
279126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
280126353Smlaier		fprintf(stderr, "pf disabled\n");
281126353Smlaier
282126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
283126353Smlaier			if (errno != ENOENT)
284126353Smlaier				err(1, "DIOCSTOPALTQ");
285126353Smlaier
286126353Smlaier	return (0);
287126353Smlaier}
288126353Smlaier
289126353Smlaierint
290126353Smlaierpfctl_clear_stats(int dev, int opts)
291126353Smlaier{
292126353Smlaier	if (ioctl(dev, DIOCCLRSTATUS))
293126353Smlaier		err(1, "DIOCCLRSTATUS");
294126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
295126353Smlaier		fprintf(stderr, "pf: statistics cleared\n");
296126353Smlaier	return (0);
297126353Smlaier}
298126353Smlaier
299126353Smlaierint
300145840Smlaierpfctl_clear_interface_flags(int dev, int opts)
301126353Smlaier{
302145840Smlaier	struct pfioc_iface	pi;
303126353Smlaier
304145840Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
305145840Smlaier		bzero(&pi, sizeof(pi));
306171172Smlaier		pi.pfiio_flags = PFI_IFLAG_SKIP;
307126353Smlaier
308145840Smlaier		if (ioctl(dev, DIOCCLRIFFLAG, &pi))
309145840Smlaier			err(1, "DIOCCLRIFFLAG");
310126353Smlaier		if ((opts & PF_OPT_QUIET) == 0)
311145840Smlaier			fprintf(stderr, "pf: interface flags reset\n");
312126353Smlaier	}
313145840Smlaier	return (0);
314145840Smlaier}
315145840Smlaier
316145840Smlaierint
317145840Smlaierpfctl_clear_rules(int dev, int opts, char *anchorname)
318145840Smlaier{
319145840Smlaier	struct pfr_buffer t;
320145840Smlaier
321130617Smlaier	memset(&t, 0, sizeof(t));
322130617Smlaier	t.pfrb_type = PFRB_TRANS;
323145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
324145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
325130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
326130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
327130617Smlaier		err(1, "pfctl_clear_rules");
328126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
329126353Smlaier		fprintf(stderr, "rules cleared\n");
330126353Smlaier	return (0);
331126353Smlaier}
332126353Smlaier
333126353Smlaierint
334145840Smlaierpfctl_clear_nat(int dev, int opts, char *anchorname)
335126353Smlaier{
336130617Smlaier	struct pfr_buffer t;
337126353Smlaier
338130617Smlaier	memset(&t, 0, sizeof(t));
339130617Smlaier	t.pfrb_type = PFRB_TRANS;
340145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
341145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
342145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
343130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
344130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
345130617Smlaier		err(1, "pfctl_clear_nat");
346126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
347126353Smlaier		fprintf(stderr, "nat cleared\n");
348126353Smlaier	return (0);
349126353Smlaier}
350126353Smlaier
351126353Smlaierint
352126353Smlaierpfctl_clear_altq(int dev, int opts)
353126353Smlaier{
354130617Smlaier	struct pfr_buffer t;
355126353Smlaier
356126353Smlaier	if (!altqsupport)
357126353Smlaier		return (-1);
358130617Smlaier	memset(&t, 0, sizeof(t));
359130617Smlaier	t.pfrb_type = PFRB_TRANS;
360145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
361130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
362130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
363130617Smlaier		err(1, "pfctl_clear_altq");
364126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
365126353Smlaier		fprintf(stderr, "altq cleared\n");
366126353Smlaier	return (0);
367126353Smlaier}
368126353Smlaier
369126353Smlaierint
370130617Smlaierpfctl_clear_src_nodes(int dev, int opts)
371126353Smlaier{
372130617Smlaier	if (ioctl(dev, DIOCCLRSRCNODES))
373130617Smlaier		err(1, "DIOCCLRSRCNODES");
374130617Smlaier	if ((opts & PF_OPT_QUIET) == 0)
375130617Smlaier		fprintf(stderr, "source tracking entries cleared\n");
376130617Smlaier	return (0);
377130617Smlaier}
378130617Smlaier
379130617Smlaierint
380130617Smlaierpfctl_clear_states(int dev, const char *iface, int opts)
381130617Smlaier{
382130617Smlaier	struct pfioc_state_kill psk;
383130617Smlaier
384130617Smlaier	memset(&psk, 0, sizeof(psk));
385130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
386130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
387130617Smlaier		errx(1, "invalid interface: %s", iface);
388130617Smlaier
389130617Smlaier	if (ioctl(dev, DIOCCLRSTATES, &psk))
390126353Smlaier		err(1, "DIOCCLRSTATES");
391126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
392130617Smlaier		fprintf(stderr, "%d states cleared\n", psk.psk_af);
393126353Smlaier	return (0);
394126353Smlaier}
395126353Smlaier
396171172Smlaiervoid
397171172Smlaierpfctl_addrprefix(char *addr, struct pf_addr *mask)
398171172Smlaier{
399171172Smlaier	char *p;
400171172Smlaier	const char *errstr;
401171172Smlaier	int prefix, ret_ga, q, r;
402171172Smlaier	struct addrinfo hints, *res;
403171172Smlaier
404171172Smlaier	if ((p = strchr(addr, '/')) == NULL)
405171172Smlaier		return;
406171172Smlaier
407171172Smlaier	*p++ = '\0';
408171172Smlaier	prefix = strtonum(p, 0, 128, &errstr);
409171172Smlaier	if (errstr)
410171172Smlaier		errx(1, "prefix is %s: %s", errstr, p);
411171172Smlaier
412171172Smlaier	bzero(&hints, sizeof(hints));
413171172Smlaier	/* prefix only with numeric addresses */
414171172Smlaier	hints.ai_flags |= AI_NUMERICHOST;
415171172Smlaier
416171172Smlaier	if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
417171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
418171172Smlaier		/* NOTREACHED */
419171172Smlaier	}
420171172Smlaier
421171172Smlaier	if (res->ai_family == AF_INET && prefix > 32)
422171172Smlaier		errx(1, "prefix too long for AF_INET");
423171172Smlaier	else if (res->ai_family == AF_INET6 && prefix > 128)
424171172Smlaier		errx(1, "prefix too long for AF_INET6");
425171172Smlaier
426171172Smlaier	q = prefix >> 3;
427171172Smlaier	r = prefix & 7;
428171172Smlaier	switch (res->ai_family) {
429171172Smlaier	case AF_INET:
430171172Smlaier		bzero(&mask->v4, sizeof(mask->v4));
431171172Smlaier		mask->v4.s_addr = htonl((u_int32_t)
432171172Smlaier		    (0xffffffffffULL << (32 - prefix)));
433171172Smlaier		break;
434171172Smlaier	case AF_INET6:
435171172Smlaier		bzero(&mask->v6, sizeof(mask->v6));
436171172Smlaier		if (q > 0)
437171172Smlaier			memset((void *)&mask->v6, 0xff, q);
438171172Smlaier		if (r > 0)
439171172Smlaier			*((u_char *)&mask->v6 + q) =
440171172Smlaier			    (0xff00 >> r) & 0xff;
441171172Smlaier		break;
442171172Smlaier	}
443171172Smlaier	freeaddrinfo(res);
444171172Smlaier}
445171172Smlaier
446126353Smlaierint
447171172Smlaierpfctl_kill_src_nodes(int dev, const char *iface, int opts)
448171172Smlaier{
449171172Smlaier	struct pfioc_src_node_kill psnk;
450171172Smlaier	struct addrinfo *res[2], *resp[2];
451171172Smlaier	struct sockaddr last_src, last_dst;
452171172Smlaier	int killed, sources, dests;
453171172Smlaier	int ret_ga;
454171172Smlaier
455171172Smlaier	killed = sources = dests = 0;
456171172Smlaier
457171172Smlaier	memset(&psnk, 0, sizeof(psnk));
458171172Smlaier	memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
459171172Smlaier	    sizeof(psnk.psnk_src.addr.v.a.mask));
460171172Smlaier	memset(&last_src, 0xff, sizeof(last_src));
461171172Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
462171172Smlaier
463171172Smlaier	pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
464171172Smlaier
465171172Smlaier	if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
466171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
467171172Smlaier		/* NOTREACHED */
468171172Smlaier	}
469171172Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
470171172Smlaier		if (resp[0]->ai_addr == NULL)
471171172Smlaier			continue;
472171172Smlaier		/* We get lots of duplicates.  Catch the easy ones */
473171172Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
474171172Smlaier			continue;
475171172Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
476171172Smlaier
477171172Smlaier		psnk.psnk_af = resp[0]->ai_family;
478171172Smlaier		sources++;
479171172Smlaier
480171172Smlaier		if (psnk.psnk_af == AF_INET)
481171172Smlaier			psnk.psnk_src.addr.v.a.addr.v4 =
482171172Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
483171172Smlaier		else if (psnk.psnk_af == AF_INET6)
484171172Smlaier			psnk.psnk_src.addr.v.a.addr.v6 =
485171172Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
486171172Smlaier			    sin6_addr;
487171172Smlaier		else
488171172Smlaier			errx(1, "Unknown address family %d", psnk.psnk_af);
489171172Smlaier
490171172Smlaier		if (src_node_killers > 1) {
491171172Smlaier			dests = 0;
492171172Smlaier			memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
493171172Smlaier			    sizeof(psnk.psnk_dst.addr.v.a.mask));
494171172Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
495171172Smlaier			pfctl_addrprefix(src_node_kill[1],
496171172Smlaier			    &psnk.psnk_dst.addr.v.a.mask);
497171172Smlaier			if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
498171172Smlaier			    &res[1]))) {
499171172Smlaier				errx(1, "getaddrinfo: %s",
500171172Smlaier				    gai_strerror(ret_ga));
501171172Smlaier				/* NOTREACHED */
502171172Smlaier			}
503171172Smlaier			for (resp[1] = res[1]; resp[1];
504171172Smlaier			    resp[1] = resp[1]->ai_next) {
505171172Smlaier				if (resp[1]->ai_addr == NULL)
506171172Smlaier					continue;
507171172Smlaier				if (psnk.psnk_af != resp[1]->ai_family)
508171172Smlaier					continue;
509171172Smlaier
510171172Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
511171172Smlaier				    sizeof(last_dst)) == 0)
512171172Smlaier					continue;
513171172Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
514171172Smlaier
515171172Smlaier				dests++;
516171172Smlaier
517171172Smlaier				if (psnk.psnk_af == AF_INET)
518171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v4 =
519171172Smlaier					    ((struct sockaddr_in *)resp[1]->
520171172Smlaier					    ai_addr)->sin_addr;
521171172Smlaier				else if (psnk.psnk_af == AF_INET6)
522171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v6 =
523171172Smlaier					    ((struct sockaddr_in6 *)resp[1]->
524171172Smlaier					    ai_addr)->sin6_addr;
525171172Smlaier				else
526171172Smlaier					errx(1, "Unknown address family %d",
527171172Smlaier					    psnk.psnk_af);
528171172Smlaier
529171172Smlaier				if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
530171172Smlaier					err(1, "DIOCKILLSRCNODES");
531171172Smlaier				killed += psnk.psnk_af;
532171172Smlaier				/* fixup psnk.psnk_af */
533171172Smlaier				psnk.psnk_af = resp[1]->ai_family;
534171172Smlaier			}
535171172Smlaier			freeaddrinfo(res[1]);
536171172Smlaier		} else {
537171172Smlaier			if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
538171172Smlaier				err(1, "DIOCKILLSRCNODES");
539171172Smlaier			killed += psnk.psnk_af;
540171172Smlaier			/* fixup psnk.psnk_af */
541171172Smlaier			psnk.psnk_af = res[0]->ai_family;
542171172Smlaier		}
543171172Smlaier	}
544171172Smlaier
545171172Smlaier	freeaddrinfo(res[0]);
546171172Smlaier
547171172Smlaier	if ((opts & PF_OPT_QUIET) == 0)
548171172Smlaier		fprintf(stderr, "killed %d src nodes from %d sources and %d "
549171172Smlaier		    "destinations\n", killed, sources, dests);
550171172Smlaier	return (0);
551171172Smlaier}
552171172Smlaier
553171172Smlaierint
554130617Smlaierpfctl_kill_states(int dev, const char *iface, int opts)
555126353Smlaier{
556126353Smlaier	struct pfioc_state_kill psk;
557126353Smlaier	struct addrinfo *res[2], *resp[2];
558126353Smlaier	struct sockaddr last_src, last_dst;
559126353Smlaier	int killed, sources, dests;
560126353Smlaier	int ret_ga;
561126353Smlaier
562126353Smlaier	killed = sources = dests = 0;
563126353Smlaier
564126353Smlaier	memset(&psk, 0, sizeof(psk));
565126353Smlaier	memset(&psk.psk_src.addr.v.a.mask, 0xff,
566126353Smlaier	    sizeof(psk.psk_src.addr.v.a.mask));
567126353Smlaier	memset(&last_src, 0xff, sizeof(last_src));
568126353Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
569130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
570130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
571130617Smlaier		errx(1, "invalid interface: %s", iface);
572126353Smlaier
573171172Smlaier	pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
574171172Smlaier
575126353Smlaier	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
576126353Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
577126353Smlaier		/* NOTREACHED */
578126353Smlaier	}
579126353Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
580126353Smlaier		if (resp[0]->ai_addr == NULL)
581126353Smlaier			continue;
582126353Smlaier		/* We get lots of duplicates.  Catch the easy ones */
583126353Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
584126353Smlaier			continue;
585126353Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
586126353Smlaier
587126353Smlaier		psk.psk_af = resp[0]->ai_family;
588126353Smlaier		sources++;
589126353Smlaier
590126353Smlaier		if (psk.psk_af == AF_INET)
591126353Smlaier			psk.psk_src.addr.v.a.addr.v4 =
592126353Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
593126353Smlaier		else if (psk.psk_af == AF_INET6)
594126353Smlaier			psk.psk_src.addr.v.a.addr.v6 =
595126353Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
596126353Smlaier			    sin6_addr;
597126353Smlaier		else
598126353Smlaier			errx(1, "Unknown address family %d", psk.psk_af);
599126353Smlaier
600126353Smlaier		if (state_killers > 1) {
601126353Smlaier			dests = 0;
602126353Smlaier			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
603126353Smlaier			    sizeof(psk.psk_dst.addr.v.a.mask));
604126353Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
605171172Smlaier			pfctl_addrprefix(state_kill[1],
606171172Smlaier			    &psk.psk_dst.addr.v.a.mask);
607126353Smlaier			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
608126353Smlaier			    &res[1]))) {
609130617Smlaier				errx(1, "getaddrinfo: %s",
610130617Smlaier				    gai_strerror(ret_ga));
611126353Smlaier				/* NOTREACHED */
612126353Smlaier			}
613126353Smlaier			for (resp[1] = res[1]; resp[1];
614126353Smlaier			    resp[1] = resp[1]->ai_next) {
615126353Smlaier				if (resp[1]->ai_addr == NULL)
616126353Smlaier					continue;
617126353Smlaier				if (psk.psk_af != resp[1]->ai_family)
618126353Smlaier					continue;
619126353Smlaier
620126353Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
621126353Smlaier				    sizeof(last_dst)) == 0)
622126353Smlaier					continue;
623126353Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
624126353Smlaier
625126353Smlaier				dests++;
626126353Smlaier
627126353Smlaier				if (psk.psk_af == AF_INET)
628126353Smlaier					psk.psk_dst.addr.v.a.addr.v4 =
629126353Smlaier					    ((struct sockaddr_in *)resp[1]->
630126353Smlaier					    ai_addr)->sin_addr;
631126353Smlaier				else if (psk.psk_af == AF_INET6)
632126353Smlaier					psk.psk_dst.addr.v.a.addr.v6 =
633126353Smlaier					    ((struct sockaddr_in6 *)resp[1]->
634126353Smlaier					    ai_addr)->sin6_addr;
635126353Smlaier				else
636126353Smlaier					errx(1, "Unknown address family %d",
637126353Smlaier					    psk.psk_af);
638126353Smlaier
639126353Smlaier				if (ioctl(dev, DIOCKILLSTATES, &psk))
640126353Smlaier					err(1, "DIOCKILLSTATES");
641126353Smlaier				killed += psk.psk_af;
642126353Smlaier				/* fixup psk.psk_af */
643126353Smlaier				psk.psk_af = resp[1]->ai_family;
644126353Smlaier			}
645126353Smlaier			freeaddrinfo(res[1]);
646126353Smlaier		} else {
647126353Smlaier			if (ioctl(dev, DIOCKILLSTATES, &psk))
648126353Smlaier				err(1, "DIOCKILLSTATES");
649126353Smlaier			killed += psk.psk_af;
650126353Smlaier			/* fixup psk.psk_af */
651126353Smlaier			psk.psk_af = res[0]->ai_family;
652126353Smlaier		}
653126353Smlaier	}
654126353Smlaier
655126353Smlaier	freeaddrinfo(res[0]);
656126353Smlaier
657126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
658126353Smlaier		fprintf(stderr, "killed %d states from %d sources and %d "
659126353Smlaier		    "destinations\n", killed, sources, dests);
660126353Smlaier	return (0);
661126353Smlaier}
662126353Smlaier
663126353Smlaierint
664126353Smlaierpfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
665145840Smlaier    u_int32_t ticket, int r_action, char *anchorname)
666126353Smlaier{
667126353Smlaier	struct pfioc_pooladdr pp;
668126353Smlaier	struct pf_pooladdr *pa;
669126353Smlaier	u_int32_t pnr, mpnr;
670126353Smlaier
671126353Smlaier	memset(&pp, 0, sizeof(pp));
672126353Smlaier	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
673126353Smlaier	pp.r_action = r_action;
674126353Smlaier	pp.r_num = nr;
675126353Smlaier	pp.ticket = ticket;
676126353Smlaier	if (ioctl(dev, DIOCGETADDRS, &pp)) {
677126353Smlaier		warn("DIOCGETADDRS");
678126353Smlaier		return (-1);
679126353Smlaier	}
680126353Smlaier	mpnr = pp.nr;
681126353Smlaier	TAILQ_INIT(&pool->list);
682126353Smlaier	for (pnr = 0; pnr < mpnr; ++pnr) {
683126353Smlaier		pp.nr = pnr;
684126353Smlaier		if (ioctl(dev, DIOCGETADDR, &pp)) {
685126353Smlaier			warn("DIOCGETADDR");
686126353Smlaier			return (-1);
687126353Smlaier		}
688126353Smlaier		pa = calloc(1, sizeof(struct pf_pooladdr));
689126353Smlaier		if (pa == NULL)
690126353Smlaier			err(1, "calloc");
691126353Smlaier		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
692126353Smlaier		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
693126353Smlaier	}
694126353Smlaier
695126353Smlaier	return (0);
696126353Smlaier}
697126353Smlaier
698126353Smlaiervoid
699171172Smlaierpfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
700171172Smlaier{
701171172Smlaier	struct pf_pooladdr *pa;
702171172Smlaier
703171172Smlaier	while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
704171172Smlaier		TAILQ_REMOVE(&src->list, pa, entries);
705171172Smlaier		TAILQ_INSERT_TAIL(&dst->list, pa, entries);
706171172Smlaier	}
707171172Smlaier}
708171172Smlaier
709171172Smlaiervoid
710126353Smlaierpfctl_clear_pool(struct pf_pool *pool)
711126353Smlaier{
712126353Smlaier	struct pf_pooladdr *pa;
713126353Smlaier
714126353Smlaier	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
715126353Smlaier		TAILQ_REMOVE(&pool->list, pa, entries);
716126353Smlaier		free(pa);
717126353Smlaier	}
718126353Smlaier}
719126353Smlaier
720126353Smlaiervoid
721126353Smlaierpfctl_print_rule_counters(struct pf_rule *rule, int opts)
722126353Smlaier{
723126353Smlaier	if (opts & PF_OPT_DEBUG) {
724126353Smlaier		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
725126353Smlaier		    "p", "sa", "sp", "da", "dp" };
726126353Smlaier		int i;
727126353Smlaier
728126353Smlaier		printf("  [ Skip steps: ");
729126353Smlaier		for (i = 0; i < PF_SKIP_COUNT; ++i) {
730126353Smlaier			if (rule->skip[i].nr == rule->nr + 1)
731126353Smlaier				continue;
732126353Smlaier			printf("%s=", t[i]);
733126353Smlaier			if (rule->skip[i].nr == -1)
734126353Smlaier				printf("end ");
735126353Smlaier			else
736126353Smlaier				printf("%u ", rule->skip[i].nr);
737126353Smlaier		}
738126353Smlaier		printf("]\n");
739126353Smlaier
740126353Smlaier		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
741126353Smlaier		    rule->qname, rule->qid, rule->pqname, rule->pqid);
742126353Smlaier	}
743171172Smlaier	if (opts & PF_OPT_VERBOSE) {
744127024Smlaier		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
745127024Smlaier			    "Bytes: %-10llu  States: %-6u]\n",
746127024Smlaier			    (unsigned long long)rule->evaluations,
747171172Smlaier			    (unsigned long long)(rule->packets[0] +
748171172Smlaier			    rule->packets[1]),
749171172Smlaier			    (unsigned long long)(rule->bytes[0] +
750171172Smlaier			    rule->bytes[1]), rule->states);
751171172Smlaier		if (!(opts & PF_OPT_DEBUG))
752171172Smlaier			printf("  [ Inserted: uid %u pid %u ]\n",
753171172Smlaier			    (unsigned)rule->cuid, (unsigned)rule->cpid);
754171172Smlaier	}
755126353Smlaier}
756126353Smlaier
757130617Smlaiervoid
758130617Smlaierpfctl_print_title(char *title)
759130617Smlaier{
760130617Smlaier	if (!first_title)
761130617Smlaier		printf("\n");
762130617Smlaier	first_title = 0;
763130617Smlaier	printf("%s\n", title);
764130617Smlaier}
765130617Smlaier
766126353Smlaierint
767171172Smlaierpfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
768171172Smlaier    char *anchorname, int depth)
769126353Smlaier{
770126353Smlaier	struct pfioc_rule pr;
771130617Smlaier	u_int32_t nr, mnr, header = 0;
772126353Smlaier	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
773171172Smlaier	int len = strlen(path);
774171172Smlaier	int brace;
775171172Smlaier	char *p;
776126353Smlaier
777171172Smlaier	if (path[0])
778171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
779171172Smlaier	else
780171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
781171172Smlaier
782126353Smlaier	memset(&pr, 0, sizeof(pr));
783171172Smlaier	memcpy(pr.anchor, path, sizeof(pr.anchor));
784130617Smlaier	if (opts & PF_OPT_SHOWALL) {
785130617Smlaier		pr.rule.action = PF_PASS;
786130617Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
787130617Smlaier			warn("DIOCGETRULES");
788171172Smlaier			goto error;
789130617Smlaier		}
790130617Smlaier		header++;
791130617Smlaier	}
792126353Smlaier	pr.rule.action = PF_SCRUB;
793126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
794126353Smlaier		warn("DIOCGETRULES");
795171172Smlaier		goto error;
796126353Smlaier	}
797130617Smlaier	if (opts & PF_OPT_SHOWALL) {
798171172Smlaier		if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
799130617Smlaier			pfctl_print_title("FILTER RULES:");
800171172Smlaier		else if (format == PFCTL_SHOW_LABELS && labels)
801130617Smlaier			pfctl_print_title("LABEL COUNTERS:");
802130617Smlaier	}
803126353Smlaier	mnr = pr.nr;
804171172Smlaier	if (opts & PF_OPT_CLRRULECTRS)
805171172Smlaier		pr.action = PF_GET_CLR_CNTR;
806171172Smlaier
807126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
808126353Smlaier		pr.nr = nr;
809126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
810126353Smlaier			warn("DIOCGETRULE");
811171172Smlaier			goto error;
812126353Smlaier		}
813126353Smlaier
814126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
815171172Smlaier		    nr, pr.ticket, PF_SCRUB, path) != 0)
816171172Smlaier			goto error;
817126353Smlaier
818126353Smlaier		switch (format) {
819171172Smlaier		case PFCTL_SHOW_LABELS:
820126353Smlaier			if (pr.rule.label[0]) {
821126353Smlaier				printf("%s ", pr.rule.label);
822171172Smlaier				printf("%llu %llu %llu %llu %llu %llu %llu\n",
823127024Smlaier				    (unsigned long long)pr.rule.evaluations,
824171172Smlaier				    (unsigned long long)(pr.rule.packets[0] +
825171172Smlaier				    pr.rule.packets[1]),
826171172Smlaier				    (unsigned long long)(pr.rule.bytes[0] +
827171172Smlaier				    pr.rule.bytes[1]),
828171172Smlaier				    (unsigned long long)pr.rule.packets[0],
829171172Smlaier				    (unsigned long long)pr.rule.bytes[0],
830171172Smlaier				    (unsigned long long)pr.rule.packets[1],
831171172Smlaier				    (unsigned long long)pr.rule.bytes[1]);
832126353Smlaier			}
833126353Smlaier			break;
834171172Smlaier		case PFCTL_SHOW_RULES:
835130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
836130617Smlaier				labels = 1;
837145840Smlaier			print_rule(&pr.rule, pr.anchor_call, rule_numbers);
838171172Smlaier			printf("\n");
839126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
840171172Smlaier			break;
841171172Smlaier		case PFCTL_SHOW_NOTHING:
842171172Smlaier			break;
843126353Smlaier		}
844126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
845126353Smlaier	}
846126353Smlaier	pr.rule.action = PF_PASS;
847126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
848126353Smlaier		warn("DIOCGETRULES");
849171172Smlaier		goto error;
850126353Smlaier	}
851126353Smlaier	mnr = pr.nr;
852126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
853126353Smlaier		pr.nr = nr;
854126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
855126353Smlaier			warn("DIOCGETRULE");
856171172Smlaier			goto error;
857126353Smlaier		}
858126353Smlaier
859126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
860171172Smlaier		    nr, pr.ticket, PF_PASS, path) != 0)
861171172Smlaier			goto error;
862126353Smlaier
863126353Smlaier		switch (format) {
864171172Smlaier		case PFCTL_SHOW_LABELS:
865126353Smlaier			if (pr.rule.label[0]) {
866126353Smlaier				printf("%s ", pr.rule.label);
867171172Smlaier				printf("%llu %llu %llu %llu %llu %llu %llu\n",
868127024Smlaier				    (unsigned long long)pr.rule.evaluations,
869171172Smlaier				    (unsigned long long)(pr.rule.packets[0] +
870171172Smlaier				    pr.rule.packets[1]),
871171172Smlaier				    (unsigned long long)(pr.rule.bytes[0] +
872171172Smlaier				    pr.rule.bytes[1]),
873171172Smlaier				    (unsigned long long)pr.rule.packets[0],
874171172Smlaier				    (unsigned long long)pr.rule.bytes[0],
875171172Smlaier				    (unsigned long long)pr.rule.packets[1],
876171172Smlaier				    (unsigned long long)pr.rule.bytes[1]);
877126353Smlaier			}
878126353Smlaier			break;
879171172Smlaier		case PFCTL_SHOW_RULES:
880171172Smlaier			brace = 0;
881130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
882130617Smlaier				labels = 1;
883171172Smlaier			INDENT(depth, !(opts & PF_OPT_VERBOSE));
884171172Smlaier			if (pr.anchor_call[0] &&
885171172Smlaier			   ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
886171172Smlaier			   ((void *)p == (void *)pr.anchor_call ||
887171172Smlaier			   *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
888171172Smlaier				brace++;
889171172Smlaier				if ((p = strrchr(pr.anchor_call, '/')) !=
890171172Smlaier				    NULL)
891171172Smlaier					p++;
892171172Smlaier				else
893171172Smlaier					p = &pr.anchor_call[0];
894171172Smlaier			} else
895171172Smlaier				p = &pr.anchor_call[0];
896171172Smlaier
897171172Smlaier			print_rule(&pr.rule, p, rule_numbers);
898171172Smlaier			if (brace)
899171172Smlaier				printf(" {\n");
900171172Smlaier			else
901171172Smlaier				printf("\n");
902126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
903171172Smlaier			if (brace) {
904171172Smlaier				pfctl_show_rules(dev, path, opts, format,
905171172Smlaier				    p, depth + 1);
906171172Smlaier				INDENT(depth, !(opts & PF_OPT_VERBOSE));
907171172Smlaier				printf("}\n");
908171172Smlaier			}
909171172Smlaier			break;
910171172Smlaier		case PFCTL_SHOW_NOTHING:
911171172Smlaier			break;
912126353Smlaier		}
913126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
914126353Smlaier	}
915171172Smlaier	path[len] = '\0';
916126353Smlaier	return (0);
917171172Smlaier
918171172Smlaier error:
919171172Smlaier	path[len] = '\0';
920171172Smlaier	return (-1);
921126353Smlaier}
922126353Smlaier
923126353Smlaierint
924145840Smlaierpfctl_show_nat(int dev, int opts, char *anchorname)
925126353Smlaier{
926126353Smlaier	struct pfioc_rule pr;
927126353Smlaier	u_int32_t mnr, nr;
928126353Smlaier	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
929130617Smlaier	int i, dotitle = opts & PF_OPT_SHOWALL;
930126353Smlaier
931126353Smlaier	memset(&pr, 0, sizeof(pr));
932126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
933126353Smlaier	for (i = 0; i < 3; i++) {
934126353Smlaier		pr.rule.action = nattype[i];
935126353Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
936126353Smlaier			warn("DIOCGETRULES");
937126353Smlaier			return (-1);
938126353Smlaier		}
939126353Smlaier		mnr = pr.nr;
940126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
941126353Smlaier			pr.nr = nr;
942126353Smlaier			if (ioctl(dev, DIOCGETRULE, &pr)) {
943126353Smlaier				warn("DIOCGETRULE");
944126353Smlaier				return (-1);
945126353Smlaier			}
946126353Smlaier			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
947145840Smlaier			    pr.ticket, nattype[i], anchorname) != 0)
948126353Smlaier				return (-1);
949130617Smlaier			if (dotitle) {
950130617Smlaier				pfctl_print_title("TRANSLATION RULES:");
951130617Smlaier				dotitle = 0;
952130617Smlaier			}
953145840Smlaier			print_rule(&pr.rule, pr.anchor_call,
954145840Smlaier			    opts & PF_OPT_VERBOSE2);
955171172Smlaier			printf("\n");
956126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
957126353Smlaier			pfctl_clear_pool(&pr.rule.rpool);
958126353Smlaier		}
959126353Smlaier	}
960126353Smlaier	return (0);
961126353Smlaier}
962126353Smlaier
963126353Smlaierint
964130617Smlaierpfctl_show_src_nodes(int dev, int opts)
965126353Smlaier{
966130617Smlaier	struct pfioc_src_nodes psn;
967130617Smlaier	struct pf_src_node *p;
968130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
969130617Smlaier	unsigned len = 0;
970130617Smlaier	int i;
971130617Smlaier
972130617Smlaier	memset(&psn, 0, sizeof(psn));
973130617Smlaier	for (;;) {
974130617Smlaier		psn.psn_len = len;
975130617Smlaier		if (len) {
976130617Smlaier			newinbuf = realloc(inbuf, len);
977130617Smlaier			if (newinbuf == NULL)
978130617Smlaier				err(1, "realloc");
979130617Smlaier			psn.psn_buf = inbuf = newinbuf;
980130617Smlaier		}
981130617Smlaier		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
982130617Smlaier			warn("DIOCGETSRCNODES");
983171172Smlaier			free(inbuf);
984130617Smlaier			return (-1);
985130617Smlaier		}
986130617Smlaier		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
987130617Smlaier			break;
988130617Smlaier		if (len == 0 && psn.psn_len == 0)
989171172Smlaier			goto done;
990130617Smlaier		if (len == 0 && psn.psn_len != 0)
991130617Smlaier			len = psn.psn_len;
992130617Smlaier		if (psn.psn_len == 0)
993171172Smlaier			goto done;	/* no src_nodes */
994130617Smlaier		len *= 2;
995130617Smlaier	}
996130617Smlaier	p = psn.psn_src_nodes;
997130617Smlaier	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
998130617Smlaier		pfctl_print_title("SOURCE TRACKING NODES:");
999130617Smlaier	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
1000130617Smlaier		print_src_node(p, opts);
1001130617Smlaier		p++;
1002130617Smlaier	}
1003171172Smlaierdone:
1004171172Smlaier	free(inbuf);
1005130617Smlaier	return (0);
1006130617Smlaier}
1007130617Smlaier
1008130617Smlaierint
1009130617Smlaierpfctl_show_states(int dev, const char *iface, int opts)
1010130617Smlaier{
1011126353Smlaier	struct pfioc_states ps;
1012126353Smlaier	struct pf_state *p;
1013130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1014126353Smlaier	unsigned len = 0;
1015130617Smlaier	int i, dotitle = (opts & PF_OPT_SHOWALL);
1016126353Smlaier
1017126353Smlaier	memset(&ps, 0, sizeof(ps));
1018126353Smlaier	for (;;) {
1019126353Smlaier		ps.ps_len = len;
1020126353Smlaier		if (len) {
1021130617Smlaier			newinbuf = realloc(inbuf, len);
1022130617Smlaier			if (newinbuf == NULL)
1023126353Smlaier				err(1, "realloc");
1024130617Smlaier			ps.ps_buf = inbuf = newinbuf;
1025126353Smlaier		}
1026126353Smlaier		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
1027126353Smlaier			warn("DIOCGETSTATES");
1028171172Smlaier			free(inbuf);
1029126353Smlaier			return (-1);
1030126353Smlaier		}
1031126353Smlaier		if (ps.ps_len + sizeof(struct pfioc_states) < len)
1032126353Smlaier			break;
1033126353Smlaier		if (len == 0 && ps.ps_len == 0)
1034171172Smlaier			goto done;
1035126353Smlaier		if (len == 0 && ps.ps_len != 0)
1036126353Smlaier			len = ps.ps_len;
1037126353Smlaier		if (ps.ps_len == 0)
1038171172Smlaier			goto done;	/* no states */
1039126353Smlaier		len *= 2;
1040126353Smlaier	}
1041126353Smlaier	p = ps.ps_states;
1042130617Smlaier	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
1043130617Smlaier		if (iface != NULL && strcmp(p->u.ifname, iface))
1044130617Smlaier			continue;
1045130617Smlaier		if (dotitle) {
1046130617Smlaier			pfctl_print_title("STATES:");
1047130617Smlaier			dotitle = 0;
1048130617Smlaier		}
1049130617Smlaier		print_state(p, opts);
1050126353Smlaier	}
1051171172Smlaierdone:
1052171172Smlaier	free(inbuf);
1053126353Smlaier	return (0);
1054126353Smlaier}
1055126353Smlaier
1056126353Smlaierint
1057130617Smlaierpfctl_show_status(int dev, int opts)
1058126353Smlaier{
1059126353Smlaier	struct pf_status status;
1060126353Smlaier
1061126353Smlaier	if (ioctl(dev, DIOCGETSTATUS, &status)) {
1062126353Smlaier		warn("DIOCGETSTATUS");
1063126353Smlaier		return (-1);
1064126353Smlaier	}
1065130617Smlaier	if (opts & PF_OPT_SHOWALL)
1066130617Smlaier		pfctl_print_title("INFO:");
1067130617Smlaier	print_status(&status, opts);
1068126353Smlaier	return (0);
1069126353Smlaier}
1070126353Smlaier
1071126353Smlaierint
1072130617Smlaierpfctl_show_timeouts(int dev, int opts)
1073126353Smlaier{
1074126353Smlaier	struct pfioc_tm pt;
1075126353Smlaier	int i;
1076126353Smlaier
1077130617Smlaier	if (opts & PF_OPT_SHOWALL)
1078130617Smlaier		pfctl_print_title("TIMEOUTS:");
1079126353Smlaier	memset(&pt, 0, sizeof(pt));
1080126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1081126353Smlaier		pt.timeout = pf_timeouts[i].timeout;
1082126353Smlaier		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
1083126353Smlaier			err(1, "DIOCGETTIMEOUT");
1084126353Smlaier		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
1085145840Smlaier		if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1086145840Smlaier		    pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1087126353Smlaier			printf(" states");
1088126353Smlaier		else
1089126353Smlaier			printf("s");
1090126353Smlaier		printf("\n");
1091126353Smlaier	}
1092126353Smlaier	return (0);
1093126353Smlaier
1094126353Smlaier}
1095126353Smlaier
1096126353Smlaierint
1097130617Smlaierpfctl_show_limits(int dev, int opts)
1098126353Smlaier{
1099126353Smlaier	struct pfioc_limit pl;
1100126353Smlaier	int i;
1101126353Smlaier
1102130617Smlaier	if (opts & PF_OPT_SHOWALL)
1103130617Smlaier		pfctl_print_title("LIMITS:");
1104126353Smlaier	memset(&pl, 0, sizeof(pl));
1105126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1106130617Smlaier		pl.index = pf_limits[i].index;
1107126353Smlaier		if (ioctl(dev, DIOCGETLIMIT, &pl))
1108126353Smlaier			err(1, "DIOCGETLIMIT");
1109171172Smlaier		printf("%-13s ", pf_limits[i].name);
1110126353Smlaier		if (pl.limit == UINT_MAX)
1111126353Smlaier			printf("unlimited\n");
1112126353Smlaier		else
1113171172Smlaier			printf("hard limit %8u\n", pl.limit);
1114126353Smlaier	}
1115126353Smlaier	return (0);
1116126353Smlaier}
1117126353Smlaier
1118126353Smlaier/* callbacks for rule/nat/rdr/addr */
1119126353Smlaierint
1120126353Smlaierpfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
1121126353Smlaier{
1122126353Smlaier	struct pf_pooladdr *pa;
1123126353Smlaier
1124126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1125126353Smlaier		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
1126126353Smlaier			err(1, "DIOCBEGINADDRS");
1127126353Smlaier	}
1128126353Smlaier
1129126353Smlaier	pf->paddr.af = af;
1130126353Smlaier	TAILQ_FOREACH(pa, &p->list, entries) {
1131126353Smlaier		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
1132126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1133126353Smlaier			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
1134126353Smlaier				err(1, "DIOCADDADDR");
1135126353Smlaier		}
1136126353Smlaier	}
1137126353Smlaier	return (0);
1138126353Smlaier}
1139126353Smlaier
1140126353Smlaierint
1141145840Smlaierpfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
1142126353Smlaier{
1143130617Smlaier	u_int8_t		rs_num;
1144171172Smlaier	struct pf_rule		*rule;
1145171172Smlaier	struct pf_ruleset	*rs;
1146171172Smlaier	char 			*p;
1147126353Smlaier
1148171172Smlaier	rs_num = pf_get_ruleset_number(r->action);
1149171172Smlaier	if (rs_num == PF_RULESET_MAX)
1150145840Smlaier		errx(1, "Invalid rule type %d", r->action);
1151126353Smlaier
1152171172Smlaier	rs = &pf->anchor->ruleset;
1153145840Smlaier
1154171172Smlaier	if (anchor_call[0] && r->anchor == NULL) {
1155171172Smlaier		/*
1156171172Smlaier		 * Don't make non-brace anchors part of the main anchor pool.
1157145840Smlaier		 */
1158171172Smlaier		if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1159171172Smlaier			err(1, "pfctl_add_rule: calloc");
1160171172Smlaier
1161171172Smlaier		pf_init_ruleset(&r->anchor->ruleset);
1162171172Smlaier		r->anchor->ruleset.anchor = r->anchor;
1163171172Smlaier		if (strlcpy(r->anchor->path, anchor_call,
1164171172Smlaier		    sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1165171172Smlaier                        errx(1, "pfctl_add_rule: strlcpy");
1166171172Smlaier		if ((p = strrchr(anchor_call, '/')) != NULL) {
1167171172Smlaier			if (!strlen(p))
1168171172Smlaier				err(1, "pfctl_add_rule: bad anchor name %s",
1169171172Smlaier				    anchor_call);
1170171172Smlaier		} else
1171171172Smlaier			p = (char *)anchor_call;
1172171172Smlaier		if (strlcpy(r->anchor->name, p,
1173171172Smlaier		    sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1174171172Smlaier                        errx(1, "pfctl_add_rule: strlcpy");
1175171172Smlaier	}
1176145840Smlaier
1177171172Smlaier	if ((rule = calloc(1, sizeof(*rule))) == NULL)
1178171172Smlaier		err(1, "calloc");
1179171172Smlaier	bcopy(r, rule, sizeof(*rule));
1180171172Smlaier	TAILQ_INIT(&rule->rpool.list);
1181171172Smlaier	pfctl_move_pool(&r->rpool, &rule->rpool);
1182145840Smlaier
1183171172Smlaier	TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1184171172Smlaier	return (0);
1185171172Smlaier}
1186171172Smlaier
1187171172Smlaierint
1188171172Smlaierpfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
1189171172Smlaier{
1190171172Smlaier	int osize = pf->trans->pfrb_size;
1191171172Smlaier
1192171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1193171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1194171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1195171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1196171172Smlaier			return (1);
1197171172Smlaier	}
1198171172Smlaier	if (a == pf->astack[0] && ((altqsupport &&
1199171172Smlaier	     (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1200171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1201171172Smlaier			return (2);
1202171172Smlaier	}
1203171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1204171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1205171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1206171172Smlaier			return (3);
1207171172Smlaier	}
1208171172Smlaier	if (pf->loadopt & PFCTL_FLAG_TABLE)
1209171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1210171172Smlaier			return (4);
1211171172Smlaier	if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1212171172Smlaier		return (5);
1213171172Smlaier
1214171172Smlaier	return (0);
1215171172Smlaier}
1216171172Smlaier
1217171172Smlaierint
1218171172Smlaierpfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
1219171172Smlaier    int rs_num, int depth)
1220171172Smlaier{
1221171172Smlaier	struct pf_rule *r;
1222171172Smlaier	int		error, len = strlen(path);
1223171172Smlaier	int		brace = 0;
1224171172Smlaier
1225171172Smlaier	pf->anchor = rs->anchor;
1226171172Smlaier
1227171172Smlaier	if (path[0])
1228171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
1229171172Smlaier	else
1230171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
1231171172Smlaier
1232171172Smlaier	if (depth) {
1233171172Smlaier		if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
1234171172Smlaier			brace++;
1235171172Smlaier			if (pf->opts & PF_OPT_VERBOSE)
1236171172Smlaier				printf(" {\n");
1237171172Smlaier			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1238171172Smlaier			    (error = pfctl_ruleset_trans(pf,
1239171172Smlaier			    path, rs->anchor))) {
1240171172Smlaier				printf("pfctl_load_rulesets: "
1241171172Smlaier				    "pfctl_ruleset_trans %d\n", error);
1242171172Smlaier				goto error;
1243145840Smlaier			}
1244171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1245171172Smlaier			printf("\n");
1246145840Smlaier
1247145840Smlaier	}
1248145840Smlaier
1249171172Smlaier	if (pf->optimize && rs_num == PF_RULESET_FILTER)
1250171172Smlaier		pfctl_optimize_ruleset(pf, rs);
1251171172Smlaier
1252171172Smlaier	while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
1253171172Smlaier		TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
1254171172Smlaier		if ((error = pfctl_load_rule(pf, path, r, depth)))
1255171172Smlaier			goto error;
1256171172Smlaier		if (r->anchor) {
1257171172Smlaier			if ((error = pfctl_load_ruleset(pf, path,
1258171172Smlaier			    &r->anchor->ruleset, rs_num, depth + 1)))
1259171172Smlaier				goto error;
1260171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1261171172Smlaier			printf("\n");
1262171172Smlaier		free(r);
1263171172Smlaier	}
1264171172Smlaier	if (brace && pf->opts & PF_OPT_VERBOSE) {
1265171172Smlaier		INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
1266171172Smlaier		printf("}\n");
1267171172Smlaier	}
1268171172Smlaier	path[len] = '\0';
1269171172Smlaier	return (0);
1270171172Smlaier
1271171172Smlaier error:
1272171172Smlaier	path[len] = '\0';
1273171172Smlaier	return (error);
1274171172Smlaier
1275171172Smlaier}
1276171172Smlaier
1277171172Smlaierint
1278171172Smlaierpfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
1279171172Smlaier{
1280171172Smlaier	u_int8_t		rs_num = pf_get_ruleset_number(r->action);
1281171172Smlaier	char			*name;
1282171172Smlaier	struct pfioc_rule	pr;
1283171172Smlaier	int			len = strlen(path);
1284171172Smlaier
1285171172Smlaier	bzero(&pr, sizeof(pr));
1286171172Smlaier	/* set up anchor before adding to path for anchor_call */
1287171172Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1288171172Smlaier		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
1289171172Smlaier	if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
1290171172Smlaier		errx(1, "pfctl_load_rule: strlcpy");
1291171172Smlaier
1292171172Smlaier	if (r->anchor) {
1293171172Smlaier		if (r->anchor->match) {
1294171172Smlaier			if (path[0])
1295171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1296171172Smlaier				    "/%s", r->anchor->name);
1297171172Smlaier			else
1298171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1299171172Smlaier				    "%s", r->anchor->name);
1300171172Smlaier			name = path;
1301171172Smlaier		} else
1302171172Smlaier			name = r->anchor->path;
1303171172Smlaier	} else
1304171172Smlaier		name = "";
1305171172Smlaier
1306126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1307126353Smlaier		if (pfctl_add_pool(pf, &r->rpool, r->af))
1308126353Smlaier			return (1);
1309130617Smlaier		pr.pool_ticket = pf->paddr.ticket;
1310130617Smlaier		memcpy(&pr.rule, r, sizeof(pr.rule));
1311171172Smlaier		if (r->anchor && strlcpy(pr.anchor_call, name,
1312171172Smlaier		    sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
1313171172Smlaier			errx(1, "pfctl_load_rule: strlcpy");
1314130617Smlaier		if (ioctl(pf->dev, DIOCADDRULE, &pr))
1315126353Smlaier			err(1, "DIOCADDRULE");
1316126353Smlaier	}
1317171172Smlaier
1318171172Smlaier	if (pf->opts & PF_OPT_VERBOSE) {
1319171172Smlaier		INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
1320171172Smlaier		print_rule(r, r->anchor ? r->anchor->name : "",
1321171172Smlaier		    pf->opts & PF_OPT_VERBOSE2);
1322171172Smlaier	}
1323171172Smlaier	path[len] = '\0';
1324126353Smlaier	pfctl_clear_pool(&r->rpool);
1325126353Smlaier	return (0);
1326126353Smlaier}
1327126353Smlaier
1328126353Smlaierint
1329126353Smlaierpfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1330126353Smlaier{
1331126353Smlaier	if (altqsupport &&
1332126353Smlaier	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1333126353Smlaier		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1334126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1335126353Smlaier			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1336126353Smlaier				if (errno == ENXIO)
1337126353Smlaier					errx(1, "qtype not configured");
1338126353Smlaier				else if (errno == ENODEV)
1339126353Smlaier					errx(1, "%s: driver does not support "
1340126353Smlaier					    "altq", a->ifname);
1341126353Smlaier				else
1342126353Smlaier					err(1, "DIOCADDALTQ");
1343126353Smlaier			}
1344126353Smlaier		}
1345126353Smlaier		pfaltq_store(&pf->paltq->altq);
1346126353Smlaier	}
1347126353Smlaier	return (0);
1348126353Smlaier}
1349126353Smlaier
1350126353Smlaierint
1351171172Smlaierpfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize,
1352171172Smlaier    char *anchorname, struct pfr_buffer *trans)
1353126353Smlaier{
1354126353Smlaier#define ERR(x) do { warn(x); goto _error; } while(0)
1355126353Smlaier#define ERRX(x) do { warnx(x); goto _error; } while(0)
1356126353Smlaier
1357130617Smlaier	struct pfr_buffer	*t, buf;
1358130617Smlaier	struct pfioc_altq	 pa;
1359130617Smlaier	struct pfctl		 pf;
1360171172Smlaier	struct pf_ruleset	*rs;
1361130617Smlaier	struct pfr_table	 trs;
1362171172Smlaier	char			*path;
1363130617Smlaier	int			 osize;
1364126353Smlaier
1365171172Smlaier	RB_INIT(&pf_anchors);
1366171172Smlaier	memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
1367171172Smlaier	pf_init_ruleset(&pf_main_anchor.ruleset);
1368171172Smlaier	pf_main_anchor.ruleset.anchor = &pf_main_anchor;
1369130617Smlaier	if (trans == NULL) {
1370171172Smlaier		bzero(&buf, sizeof(buf));
1371171172Smlaier		buf.pfrb_type = PFRB_TRANS;
1372171172Smlaier		t = &buf;
1373171172Smlaier		osize = 0;
1374130617Smlaier	} else {
1375171172Smlaier		t = trans;
1376171172Smlaier		osize = t->pfrb_size;
1377130617Smlaier	}
1378130617Smlaier
1379126353Smlaier	memset(&pa, 0, sizeof(pa));
1380126353Smlaier	memset(&pf, 0, sizeof(pf));
1381126353Smlaier	memset(&trs, 0, sizeof(trs));
1382171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
1383171172Smlaier		ERRX("pfctl_rules: calloc");
1384126353Smlaier	if (strlcpy(trs.pfrt_anchor, anchorname,
1385145840Smlaier	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1386126353Smlaier		ERRX("pfctl_rules: strlcpy");
1387171172Smlaier	infile = filename;
1388126353Smlaier	pf.dev = dev;
1389126353Smlaier	pf.opts = opts;
1390171172Smlaier	pf.optimize = optimize;
1391126353Smlaier	pf.loadopt = loadopt;
1392171172Smlaier
1393171172Smlaier	/* non-brace anchor, create without resolving the path */
1394171172Smlaier	if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
1395171172Smlaier		ERRX("pfctl_rules: calloc");
1396171172Smlaier	rs = &pf.anchor->ruleset;
1397171172Smlaier	pf_init_ruleset(rs);
1398171172Smlaier	rs->anchor = pf.anchor;
1399171172Smlaier	if (strlcpy(pf.anchor->path, anchorname,
1400171172Smlaier	    sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
1401171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1402171172Smlaier	if (strlcpy(pf.anchor->name, anchorname,
1403171172Smlaier	    sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
1404171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1405171172Smlaier
1406171172Smlaier
1407171172Smlaier	pf.astack[0] = pf.anchor;
1408171172Smlaier	pf.asd = 0;
1409130617Smlaier	if (anchorname[0])
1410130617Smlaier		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1411126353Smlaier	pf.paltq = &pa;
1412130617Smlaier	pf.trans = t;
1413145840Smlaier	pfctl_init_options(&pf);
1414130617Smlaier
1415130617Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
1416171172Smlaier		/*
1417171172Smlaier		 * XXX For the time being we need to open transactions for
1418171172Smlaier		 * the main ruleset before parsing, because tables are still
1419171172Smlaier		 * loaded at parse time.
1420171172Smlaier		 */
1421171172Smlaier		if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
1422171172Smlaier			ERRX("pfctl_rules");
1423130617Smlaier		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1424171172Smlaier			pa.ticket =
1425171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
1426130617Smlaier		if (pf.loadopt & PFCTL_FLAG_TABLE)
1427171172Smlaier			pf.astack[0]->ruleset.tticket =
1428171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
1429130617Smlaier	}
1430171172Smlaier
1431126353Smlaier	if (parse_rules(fin, &pf) < 0) {
1432126353Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1433126353Smlaier			ERRX("Syntax error in config file: "
1434126353Smlaier			    "pf rules not loaded");
1435126353Smlaier		else
1436126353Smlaier			goto _error;
1437126353Smlaier	}
1438171172Smlaier
1439171172Smlaier	if ((pf.loadopt & PFCTL_FLAG_FILTER &&
1440171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
1441171172Smlaier	    (pf.loadopt & PFCTL_FLAG_NAT &&
1442171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
1443171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
1444171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
1445171172Smlaier	    (pf.loadopt & PFCTL_FLAG_FILTER &&
1446171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
1447171172Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1448171172Smlaier			ERRX("Unable to load rules into kernel");
1449171172Smlaier		else
1450171172Smlaier			goto _error;
1451145840Smlaier	}
1452145840Smlaier
1453130617Smlaier	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1454126353Smlaier		if (check_commit_altq(dev, opts) != 0)
1455126353Smlaier			ERRX("errors in altq config");
1456145840Smlaier
1457145840Smlaier	if (fin != stdin) {
1458126353Smlaier		fclose(fin);
1459145840Smlaier		fin = NULL;
1460145840Smlaier	}
1461126353Smlaier
1462126353Smlaier	/* process "load anchor" directives */
1463145840Smlaier	if (!anchorname[0])
1464171172Smlaier		if (pfctl_load_anchors(dev, &pf, t) == -1)
1465126353Smlaier			ERRX("load anchors");
1466126353Smlaier
1467145840Smlaier	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1468145840Smlaier		if (!anchorname[0])
1469145840Smlaier			if (pfctl_load_options(&pf))
1470145840Smlaier				goto _error;
1471171172Smlaier		if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
1472130617Smlaier			ERR("DIOCXCOMMIT");
1473145840Smlaier	}
1474126353Smlaier	return (0);
1475126353Smlaier
1476126353Smlaier_error:
1477130617Smlaier	if (trans == NULL) {	/* main ruleset */
1478130617Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1479171172Smlaier			if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
1480130617Smlaier				err(1, "DIOCXROLLBACK");
1481130617Smlaier		exit(1);
1482145840Smlaier	} else {		/* sub ruleset */
1483145840Smlaier		if (fin != NULL && fin != stdin)
1484145840Smlaier			fclose(fin);
1485130617Smlaier		return (-1);
1486145840Smlaier	}
1487126353Smlaier
1488126353Smlaier#undef ERR
1489126353Smlaier#undef ERRX
1490126353Smlaier}
1491126353Smlaier
1492145840SmlaierFILE *
1493145840Smlaierpfctl_fopen(const char *name, const char *mode)
1494145840Smlaier{
1495145840Smlaier	struct stat	 st;
1496145840Smlaier	FILE		*fp;
1497145840Smlaier
1498145840Smlaier	fp = fopen(name, mode);
1499145840Smlaier	if (fp == NULL)
1500145840Smlaier		return (NULL);
1501145840Smlaier	if (fstat(fileno(fp), &st)) {
1502145840Smlaier		fclose(fp);
1503145840Smlaier		return (NULL);
1504145840Smlaier	}
1505145840Smlaier	if (S_ISDIR(st.st_mode)) {
1506145840Smlaier		fclose(fp);
1507145840Smlaier		errno = EISDIR;
1508145840Smlaier		return (NULL);
1509145840Smlaier	}
1510145840Smlaier	return (fp);
1511145840Smlaier}
1512145840Smlaier
1513145840Smlaiervoid
1514145840Smlaierpfctl_init_options(struct pfctl *pf)
1515145840Smlaier{
1516171172Smlaier	int mib[2], mem;
1517171172Smlaier	size_t size;
1518171172Smlaier
1519145840Smlaier	pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1520145840Smlaier	pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1521145840Smlaier	pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1522145840Smlaier	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1523145840Smlaier	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1524145840Smlaier	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1525145840Smlaier	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1526145840Smlaier	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1527145840Smlaier	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1528145840Smlaier	pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1529145840Smlaier	pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1530145840Smlaier	pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1531145840Smlaier	pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1532145840Smlaier	pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1533145840Smlaier	pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1534145840Smlaier	pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1535145840Smlaier	pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1536145840Smlaier	pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1537171172Smlaier	pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
1538171172Smlaier	pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
1539145840Smlaier
1540171172Smlaier	pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
1541171172Smlaier	pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
1542171172Smlaier	pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
1543171172Smlaier	pf->limit[PF_LIMIT_TABLES] = PFR_KTABLE_HIWAT;
1544171172Smlaier	pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
1545145840Smlaier
1546171172Smlaier	mib[0] = CTL_HW;
1547171172Smlaier	mib[1] = HW_PHYSMEM;
1548171172Smlaier	size = sizeof(mem);
1549171172Smlaier	(void) sysctl(mib, 2, &mem, &size, NULL, 0);
1550171172Smlaier	if (mem <= 100*1024*1024)
1551171172Smlaier		pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL;
1552171172Smlaier
1553145840Smlaier	pf->debug = PF_DEBUG_URGENT;
1554145840Smlaier}
1555145840Smlaier
1556126353Smlaierint
1557145840Smlaierpfctl_load_options(struct pfctl *pf)
1558126353Smlaier{
1559145840Smlaier	int i, error = 0;
1560126353Smlaier
1561126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1562126353Smlaier		return (0);
1563126353Smlaier
1564145840Smlaier	/* load limits */
1565145840Smlaier	for (i = 0; i < PF_LIMIT_MAX; i++) {
1566145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1567145840Smlaier			continue;
1568145840Smlaier		if (pfctl_load_limit(pf, i, pf->limit[i]))
1569145840Smlaier			error = 1;
1570145840Smlaier	}
1571145840Smlaier
1572171172Smlaier	/*
1573171172Smlaier	 * If we've set the limit, but havn't explicitly set adaptive
1574171172Smlaier	 * timeouts, do it now with a start of 60% and end of 120%.
1575171172Smlaier	 */
1576171172Smlaier	if (pf->limit_set[PF_LIMIT_STATES] &&
1577171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_START] &&
1578171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_END]) {
1579171172Smlaier		pf->timeout[PFTM_ADAPTIVE_START] =
1580171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 6;
1581171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
1582171172Smlaier		pf->timeout[PFTM_ADAPTIVE_END] =
1583171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 12;
1584171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
1585171172Smlaier	}
1586171172Smlaier
1587145840Smlaier	/* load timeouts */
1588145840Smlaier	for (i = 0; i < PFTM_MAX; i++) {
1589145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1590145840Smlaier			continue;
1591145840Smlaier		if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1592145840Smlaier			error = 1;
1593145840Smlaier	}
1594145840Smlaier
1595145840Smlaier	/* load debug */
1596145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1597145840Smlaier		if (pfctl_load_debug(pf, pf->debug))
1598145840Smlaier			error = 1;
1599145840Smlaier
1600145840Smlaier	/* load logif */
1601145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1602145840Smlaier		if (pfctl_load_logif(pf, pf->ifname))
1603145840Smlaier			error = 1;
1604145840Smlaier
1605145840Smlaier	/* load hostid */
1606145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1607145840Smlaier		if (pfctl_load_hostid(pf, pf->hostid))
1608145840Smlaier			error = 1;
1609145840Smlaier
1610145840Smlaier	return (error);
1611145840Smlaier}
1612145840Smlaier
1613145840Smlaierint
1614145840Smlaierpfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1615145840Smlaier{
1616145840Smlaier	int i;
1617145840Smlaier
1618145840Smlaier
1619126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1620126353Smlaier		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1621145840Smlaier			pf->limit[pf_limits[i].index] = limit;
1622145840Smlaier			pf->limit_set[pf_limits[i].index] = 1;
1623126353Smlaier			break;
1624126353Smlaier		}
1625126353Smlaier	}
1626126353Smlaier	if (pf_limits[i].name == NULL) {
1627126353Smlaier		warnx("Bad pool name.");
1628126353Smlaier		return (1);
1629126353Smlaier	}
1630126353Smlaier
1631126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1632126353Smlaier		printf("set limit %s %d\n", opt, limit);
1633126353Smlaier
1634126353Smlaier	return (0);
1635126353Smlaier}
1636126353Smlaier
1637126353Smlaierint
1638145840Smlaierpfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1639145840Smlaier{
1640145840Smlaier	struct pfioc_limit pl;
1641145840Smlaier
1642145840Smlaier	memset(&pl, 0, sizeof(pl));
1643145840Smlaier	pl.index = index;
1644145840Smlaier	pl.limit = limit;
1645145840Smlaier	if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1646145840Smlaier		if (errno == EBUSY)
1647145840Smlaier			warnx("Current pool size exceeds requested hard limit");
1648145840Smlaier		else
1649145840Smlaier			warnx("DIOCSETLIMIT");
1650145840Smlaier		return (1);
1651145840Smlaier	}
1652145840Smlaier	return (0);
1653145840Smlaier}
1654145840Smlaier
1655145840Smlaierint
1656126353Smlaierpfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1657126353Smlaier{
1658126353Smlaier	int i;
1659126353Smlaier
1660126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1661126353Smlaier		return (0);
1662126353Smlaier
1663126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1664126353Smlaier		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1665145840Smlaier			pf->timeout[pf_timeouts[i].timeout] = seconds;
1666145840Smlaier			pf->timeout_set[pf_timeouts[i].timeout] = 1;
1667126353Smlaier			break;
1668126353Smlaier		}
1669126353Smlaier	}
1670126353Smlaier
1671126353Smlaier	if (pf_timeouts[i].name == NULL) {
1672126353Smlaier		warnx("Bad timeout name.");
1673126353Smlaier		return (1);
1674126353Smlaier	}
1675126353Smlaier
1676126353Smlaier
1677126353Smlaier	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1678126353Smlaier		printf("set timeout %s %d\n", opt, seconds);
1679126353Smlaier
1680126353Smlaier	return (0);
1681126353Smlaier}
1682126353Smlaier
1683126353Smlaierint
1684145840Smlaierpfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1685145840Smlaier{
1686145840Smlaier	struct pfioc_tm pt;
1687145840Smlaier
1688145840Smlaier	memset(&pt, 0, sizeof(pt));
1689145840Smlaier	pt.timeout = timeout;
1690145840Smlaier	pt.seconds = seconds;
1691145840Smlaier	if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1692145840Smlaier		warnx("DIOCSETTIMEOUT");
1693145840Smlaier		return (1);
1694145840Smlaier	}
1695145840Smlaier	return (0);
1696145840Smlaier}
1697145840Smlaier
1698145840Smlaierint
1699126353Smlaierpfctl_set_optimization(struct pfctl *pf, const char *opt)
1700126353Smlaier{
1701126353Smlaier	const struct pf_hint *hint;
1702126353Smlaier	int i, r;
1703126353Smlaier
1704126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1705126353Smlaier		return (0);
1706126353Smlaier
1707126353Smlaier	for (i = 0; pf_hints[i].name; i++)
1708126353Smlaier		if (strcasecmp(opt, pf_hints[i].name) == 0)
1709126353Smlaier			break;
1710126353Smlaier
1711126353Smlaier	hint = pf_hints[i].hint;
1712126353Smlaier	if (hint == NULL) {
1713171172Smlaier		warnx("invalid state timeouts optimization");
1714126353Smlaier		return (1);
1715126353Smlaier	}
1716126353Smlaier
1717126353Smlaier	for (i = 0; hint[i].name; i++)
1718126353Smlaier		if ((r = pfctl_set_timeout(pf, hint[i].name,
1719126353Smlaier		    hint[i].timeout, 1)))
1720126353Smlaier			return (r);
1721126353Smlaier
1722126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1723126353Smlaier		printf("set optimization %s\n", opt);
1724126353Smlaier
1725126353Smlaier	return (0);
1726126353Smlaier}
1727126353Smlaier
1728126353Smlaierint
1729126353Smlaierpfctl_set_logif(struct pfctl *pf, char *ifname)
1730126353Smlaier{
1731126353Smlaier
1732126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1733126353Smlaier		return (0);
1734126353Smlaier
1735145840Smlaier	if (!strcmp(ifname, "none")) {
1736145840Smlaier		free(pf->ifname);
1737145840Smlaier		pf->ifname = NULL;
1738145840Smlaier	} else {
1739145840Smlaier		pf->ifname = strdup(ifname);
1740145840Smlaier		if (!pf->ifname)
1741145840Smlaier			errx(1, "pfctl_set_logif: strdup");
1742126353Smlaier	}
1743145840Smlaier	pf->ifname_set = 1;
1744126353Smlaier
1745126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1746126353Smlaier		printf("set loginterface %s\n", ifname);
1747126353Smlaier
1748126353Smlaier	return (0);
1749126353Smlaier}
1750126353Smlaier
1751126353Smlaierint
1752145840Smlaierpfctl_load_logif(struct pfctl *pf, char *ifname)
1753145840Smlaier{
1754145840Smlaier	struct pfioc_if pi;
1755145840Smlaier
1756145840Smlaier	memset(&pi, 0, sizeof(pi));
1757145840Smlaier	if (ifname && strlcpy(pi.ifname, ifname,
1758145840Smlaier	    sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1759171172Smlaier		warnx("pfctl_load_logif: strlcpy");
1760145840Smlaier		return (1);
1761145840Smlaier	}
1762145840Smlaier	if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1763145840Smlaier		warnx("DIOCSETSTATUSIF");
1764145840Smlaier		return (1);
1765145840Smlaier	}
1766145840Smlaier	return (0);
1767145840Smlaier}
1768145840Smlaier
1769145840Smlaierint
1770130617Smlaierpfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1771130617Smlaier{
1772130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1773130617Smlaier		return (0);
1774130617Smlaier
1775130617Smlaier	HTONL(hostid);
1776130617Smlaier
1777145840Smlaier	pf->hostid = hostid;
1778145840Smlaier	pf->hostid_set = 1;
1779130617Smlaier
1780130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1781130617Smlaier		printf("set hostid 0x%08x\n", ntohl(hostid));
1782130617Smlaier
1783130617Smlaier	return (0);
1784130617Smlaier}
1785130617Smlaier
1786130617Smlaierint
1787145840Smlaierpfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1788145840Smlaier{
1789145840Smlaier	if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1790145840Smlaier		warnx("DIOCSETHOSTID");
1791145840Smlaier		return (1);
1792145840Smlaier	}
1793145840Smlaier	return (0);
1794145840Smlaier}
1795145840Smlaier
1796145840Smlaierint
1797130617Smlaierpfctl_set_debug(struct pfctl *pf, char *d)
1798130617Smlaier{
1799130617Smlaier	u_int32_t	level;
1800130617Smlaier
1801130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1802130617Smlaier		return (0);
1803130617Smlaier
1804130617Smlaier	if (!strcmp(d, "none"))
1805145840Smlaier		pf->debug = PF_DEBUG_NONE;
1806130617Smlaier	else if (!strcmp(d, "urgent"))
1807145840Smlaier		pf->debug = PF_DEBUG_URGENT;
1808130617Smlaier	else if (!strcmp(d, "misc"))
1809145840Smlaier		pf->debug = PF_DEBUG_MISC;
1810130617Smlaier	else if (!strcmp(d, "loud"))
1811145840Smlaier		pf->debug = PF_DEBUG_NOISY;
1812130617Smlaier	else {
1813130617Smlaier		warnx("unknown debug level \"%s\"", d);
1814130617Smlaier		return (-1);
1815130617Smlaier	}
1816130617Smlaier
1817145840Smlaier	pf->debug_set = 1;
1818145840Smlaier
1819130617Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1820130617Smlaier		if (ioctl(dev, DIOCSETDEBUG, &level))
1821130617Smlaier			err(1, "DIOCSETDEBUG");
1822130617Smlaier
1823130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1824130617Smlaier		printf("set debug %s\n", d);
1825130617Smlaier
1826130617Smlaier	return (0);
1827130617Smlaier}
1828130617Smlaier
1829130617Smlaierint
1830145840Smlaierpfctl_load_debug(struct pfctl *pf, unsigned int level)
1831145840Smlaier{
1832145840Smlaier	if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1833145840Smlaier		warnx("DIOCSETDEBUG");
1834145840Smlaier		return (1);
1835145840Smlaier	}
1836145840Smlaier	return (0);
1837145840Smlaier}
1838145840Smlaier
1839145840Smlaierint
1840145840Smlaierpfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1841145840Smlaier{
1842145840Smlaier	struct pfioc_iface	pi;
1843145840Smlaier
1844145840Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1845145840Smlaier		return (0);
1846145840Smlaier
1847145840Smlaier	bzero(&pi, sizeof(pi));
1848145840Smlaier
1849145840Smlaier	pi.pfiio_flags = flags;
1850145840Smlaier
1851145840Smlaier	if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
1852145840Smlaier	    sizeof(pi.pfiio_name))
1853145840Smlaier		errx(1, "pfctl_set_interface_flags: strlcpy");
1854145840Smlaier
1855145840Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1856145840Smlaier		if (how == 0) {
1857145840Smlaier			if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
1858145840Smlaier				err(1, "DIOCCLRIFFLAG");
1859145840Smlaier		} else {
1860145840Smlaier			if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
1861145840Smlaier				err(1, "DIOCSETIFFLAG");
1862145840Smlaier		}
1863145840Smlaier	}
1864145840Smlaier	return (0);
1865145840Smlaier}
1866145840Smlaier
1867145840Smlaiervoid
1868126353Smlaierpfctl_debug(int dev, u_int32_t level, int opts)
1869126353Smlaier{
1870126353Smlaier	if (ioctl(dev, DIOCSETDEBUG, &level))
1871126353Smlaier		err(1, "DIOCSETDEBUG");
1872126353Smlaier	if ((opts & PF_OPT_QUIET) == 0) {
1873126353Smlaier		fprintf(stderr, "debug level set to '");
1874126353Smlaier		switch (level) {
1875126353Smlaier		case PF_DEBUG_NONE:
1876126353Smlaier			fprintf(stderr, "none");
1877126353Smlaier			break;
1878126353Smlaier		case PF_DEBUG_URGENT:
1879126353Smlaier			fprintf(stderr, "urgent");
1880126353Smlaier			break;
1881126353Smlaier		case PF_DEBUG_MISC:
1882126353Smlaier			fprintf(stderr, "misc");
1883126353Smlaier			break;
1884126353Smlaier		case PF_DEBUG_NOISY:
1885126353Smlaier			fprintf(stderr, "loud");
1886126353Smlaier			break;
1887126353Smlaier		default:
1888126353Smlaier			fprintf(stderr, "<invalid>");
1889126353Smlaier			break;
1890126353Smlaier		}
1891126353Smlaier		fprintf(stderr, "'\n");
1892126353Smlaier	}
1893126353Smlaier}
1894126353Smlaier
1895126353Smlaierint
1896126353Smlaierpfctl_test_altqsupport(int dev, int opts)
1897126353Smlaier{
1898126355Smlaier#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
1899126355Smlaier	return (0);
1900126355Smlaier#else
1901126353Smlaier	struct pfioc_altq pa;
1902126353Smlaier
1903126353Smlaier	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1904126353Smlaier		if (errno == ENODEV) {
1905126353Smlaier			if (!(opts & PF_OPT_QUIET))
1906126353Smlaier				fprintf(stderr, "No ALTQ support in kernel\n"
1907126353Smlaier				    "ALTQ related functions disabled\n");
1908126353Smlaier			return (0);
1909126353Smlaier		} else
1910126353Smlaier			err(1, "DIOCGETALTQS");
1911126353Smlaier	}
1912126353Smlaier	return (1);
1913126355Smlaier#endif
1914126353Smlaier}
1915126353Smlaier
1916126353Smlaierint
1917126353Smlaierpfctl_show_anchors(int dev, int opts, char *anchorname)
1918126353Smlaier{
1919145840Smlaier	struct pfioc_ruleset	 pr;
1920145840Smlaier	u_int32_t		 mnr, nr;
1921126353Smlaier
1922145840Smlaier	memset(&pr, 0, sizeof(pr));
1923145840Smlaier	memcpy(pr.path, anchorname, sizeof(pr.path));
1924145840Smlaier	if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1925145840Smlaier		if (errno == EINVAL)
1926145840Smlaier			fprintf(stderr, "Anchor '%s' not found.\n",
1927145840Smlaier			    anchorname);
1928145840Smlaier		else
1929145840Smlaier			err(1, "DIOCGETRULESETS");
1930145840Smlaier		return (-1);
1931145840Smlaier	}
1932145840Smlaier	mnr = pr.nr;
1933145840Smlaier	for (nr = 0; nr < mnr; ++nr) {
1934145840Smlaier		char sub[MAXPATHLEN];
1935126353Smlaier
1936145840Smlaier		pr.nr = nr;
1937145840Smlaier		if (ioctl(dev, DIOCGETRULESET, &pr))
1938145840Smlaier			err(1, "DIOCGETRULESET");
1939145840Smlaier		if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
1940145840Smlaier			continue;
1941145840Smlaier		sub[0] = 0;
1942145840Smlaier		if (pr.path[0]) {
1943145840Smlaier			strlcat(sub, pr.path, sizeof(sub));
1944145840Smlaier			strlcat(sub, "/", sizeof(sub));
1945126353Smlaier		}
1946145840Smlaier		strlcat(sub, pr.name, sizeof(sub));
1947171172Smlaier		if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
1948171172Smlaier			printf("  %s\n", sub);
1949171172Smlaier		if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
1950126353Smlaier			return (-1);
1951126353Smlaier	}
1952126353Smlaier	return (0);
1953126353Smlaier}
1954126353Smlaier
1955126353Smlaierconst char *
1956126353Smlaierpfctl_lookup_option(char *cmd, const char **list)
1957126353Smlaier{
1958126353Smlaier	if (cmd != NULL && *cmd)
1959126353Smlaier		for (; *list; list++)
1960126353Smlaier			if (!strncmp(cmd, *list, strlen(cmd)))
1961126353Smlaier				return (*list);
1962126353Smlaier	return (NULL);
1963126353Smlaier}
1964126353Smlaier
1965126353Smlaierint
1966126353Smlaiermain(int argc, char *argv[])
1967126353Smlaier{
1968171172Smlaier	int	 error = 0;
1969171172Smlaier	int	 ch;
1970171172Smlaier	int	 mode = O_RDONLY;
1971171172Smlaier	int	 opts = 0;
1972171172Smlaier	int	 optimize = 0;
1973171172Smlaier	char	 anchorname[MAXPATHLEN];
1974171172Smlaier	char	*path;
1975171172Smlaier	FILE	*fin = NULL;
1976126353Smlaier
1977126353Smlaier	if (argc < 2)
1978126353Smlaier		usage();
1979126353Smlaier
1980130617Smlaier	while ((ch = getopt(argc, argv,
1981171172Smlaier	    "a:AdD:eqf:F:ghi:k:K:mnNOo::p:rRs:t:T:vx:z")) != -1) {
1982126353Smlaier		switch (ch) {
1983126353Smlaier		case 'a':
1984126353Smlaier			anchoropt = optarg;
1985126353Smlaier			break;
1986126353Smlaier		case 'd':
1987126353Smlaier			opts |= PF_OPT_DISABLE;
1988126353Smlaier			mode = O_RDWR;
1989126353Smlaier			break;
1990126353Smlaier		case 'D':
1991126353Smlaier			if (pfctl_cmdline_symset(optarg) < 0)
1992126353Smlaier				warnx("could not parse macro definition %s",
1993126353Smlaier				    optarg);
1994126353Smlaier			break;
1995126353Smlaier		case 'e':
1996126353Smlaier			opts |= PF_OPT_ENABLE;
1997126353Smlaier			mode = O_RDWR;
1998126353Smlaier			break;
1999126353Smlaier		case 'q':
2000126353Smlaier			opts |= PF_OPT_QUIET;
2001126353Smlaier			break;
2002126353Smlaier		case 'F':
2003126353Smlaier			clearopt = pfctl_lookup_option(optarg, clearopt_list);
2004126353Smlaier			if (clearopt == NULL) {
2005126353Smlaier				warnx("Unknown flush modifier '%s'", optarg);
2006126353Smlaier				usage();
2007126353Smlaier			}
2008126353Smlaier			mode = O_RDWR;
2009126353Smlaier			break;
2010130617Smlaier		case 'i':
2011130617Smlaier			ifaceopt = optarg;
2012130617Smlaier			break;
2013126353Smlaier		case 'k':
2014126353Smlaier			if (state_killers >= 2) {
2015126353Smlaier				warnx("can only specify -k twice");
2016126353Smlaier				usage();
2017126353Smlaier				/* NOTREACHED */
2018126353Smlaier			}
2019126353Smlaier			state_kill[state_killers++] = optarg;
2020126353Smlaier			mode = O_RDWR;
2021126353Smlaier			break;
2022171172Smlaier		case 'K':
2023171172Smlaier			if (src_node_killers >= 2) {
2024171172Smlaier				warnx("can only specify -K twice");
2025171172Smlaier				usage();
2026171172Smlaier				/* NOTREACHED */
2027171172Smlaier			}
2028171172Smlaier			src_node_kill[src_node_killers++] = optarg;
2029171172Smlaier			mode = O_RDWR;
2030171172Smlaier			break;
2031145840Smlaier		case 'm':
2032145840Smlaier			opts |= PF_OPT_MERGE;
2033145840Smlaier			break;
2034126353Smlaier		case 'n':
2035126353Smlaier			opts |= PF_OPT_NOACTION;
2036126353Smlaier			break;
2037126353Smlaier		case 'N':
2038126353Smlaier			loadopt |= PFCTL_FLAG_NAT;
2039126353Smlaier			break;
2040126353Smlaier		case 'r':
2041126353Smlaier			opts |= PF_OPT_USEDNS;
2042126353Smlaier			break;
2043126353Smlaier		case 'f':
2044126353Smlaier			rulesopt = optarg;
2045126353Smlaier			mode = O_RDWR;
2046126353Smlaier			break;
2047126353Smlaier		case 'g':
2048126353Smlaier			opts |= PF_OPT_DEBUG;
2049126353Smlaier			break;
2050126353Smlaier		case 'A':
2051126353Smlaier			loadopt |= PFCTL_FLAG_ALTQ;
2052126353Smlaier			break;
2053126353Smlaier		case 'R':
2054126353Smlaier			loadopt |= PFCTL_FLAG_FILTER;
2055126353Smlaier			break;
2056145840Smlaier		case 'o':
2057171172Smlaier			if (optarg) {
2058171172Smlaier				optiopt = pfctl_lookup_option(optarg,
2059171172Smlaier				    optiopt_list);
2060171172Smlaier					if (optiopt == NULL) {
2061171172Smlaier					warnx("Unknown optimization '%s'",
2062171172Smlaier					    optarg);
2063171172Smlaier					usage();
2064171172Smlaier				}
2065171172Smlaier			}
2066171172Smlaier			if (opts & PF_OPT_OPTIMIZE) {
2067171172Smlaier				if (optiopt != NULL) {
2068171172Smlaier					warnx("Cannot specify -o multiple times"
2069171172Smlaier					    "with optimizer level");
2070171172Smlaier					usage();
2071171172Smlaier				}
2072171172Smlaier				optimize |= PF_OPTIMIZE_PROFILE;
2073171172Smlaier			}
2074171172Smlaier			optimize |= PF_OPTIMIZE_BASIC;
2075171172Smlaier			opts |= PF_OPT_OPTIMIZE;
2076145840Smlaier			break;
2077126353Smlaier		case 'O':
2078126353Smlaier			loadopt |= PFCTL_FLAG_OPTION;
2079126353Smlaier			break;
2080130617Smlaier		case 'p':
2081130617Smlaier			pf_device = optarg;
2082130617Smlaier			break;
2083126353Smlaier		case 's':
2084126353Smlaier			showopt = pfctl_lookup_option(optarg, showopt_list);
2085126353Smlaier			if (showopt == NULL) {
2086126353Smlaier				warnx("Unknown show modifier '%s'", optarg);
2087126353Smlaier				usage();
2088126353Smlaier			}
2089126353Smlaier			break;
2090126353Smlaier		case 't':
2091126353Smlaier			tableopt = optarg;
2092126353Smlaier			break;
2093126353Smlaier		case 'T':
2094126353Smlaier			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
2095126353Smlaier			if (tblcmdopt == NULL) {
2096126353Smlaier				warnx("Unknown table command '%s'", optarg);
2097126353Smlaier				usage();
2098126353Smlaier			}
2099126353Smlaier			break;
2100126353Smlaier		case 'v':
2101126353Smlaier			if (opts & PF_OPT_VERBOSE)
2102126353Smlaier				opts |= PF_OPT_VERBOSE2;
2103126353Smlaier			opts |= PF_OPT_VERBOSE;
2104126353Smlaier			break;
2105126353Smlaier		case 'x':
2106126353Smlaier			debugopt = pfctl_lookup_option(optarg, debugopt_list);
2107126353Smlaier			if (debugopt == NULL) {
2108126353Smlaier				warnx("Unknown debug level '%s'", optarg);
2109126353Smlaier				usage();
2110126353Smlaier			}
2111126353Smlaier			mode = O_RDWR;
2112126353Smlaier			break;
2113126353Smlaier		case 'z':
2114126353Smlaier			opts |= PF_OPT_CLRRULECTRS;
2115126353Smlaier			mode = O_RDWR;
2116126353Smlaier			break;
2117126353Smlaier		case 'h':
2118126353Smlaier			/* FALLTHROUGH */
2119126353Smlaier		default:
2120126353Smlaier			usage();
2121126353Smlaier			/* NOTREACHED */
2122126353Smlaier		}
2123126353Smlaier	}
2124126353Smlaier
2125126353Smlaier	if (tblcmdopt != NULL) {
2126126353Smlaier		argc -= optind;
2127126353Smlaier		argv += optind;
2128126353Smlaier		ch = *tblcmdopt;
2129126353Smlaier		if (ch == 'l') {
2130126353Smlaier			loadopt |= PFCTL_FLAG_TABLE;
2131126353Smlaier			tblcmdopt = NULL;
2132130617Smlaier		} else
2133171172Smlaier			mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
2134126353Smlaier	} else if (argc != optind) {
2135126353Smlaier		warnx("unknown command line argument: %s ...", argv[optind]);
2136126353Smlaier		usage();
2137126353Smlaier		/* NOTREACHED */
2138126353Smlaier	}
2139126353Smlaier	if (loadopt == 0)
2140126353Smlaier		loadopt = ~0;
2141126353Smlaier
2142171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
2143171172Smlaier		errx(1, "pfctl: calloc");
2144126353Smlaier	memset(anchorname, 0, sizeof(anchorname));
2145126353Smlaier	if (anchoropt != NULL) {
2146171172Smlaier		int len = strlen(anchoropt);
2147171172Smlaier
2148171172Smlaier		if (anchoropt[len - 1] == '*') {
2149171172Smlaier			if (len >= 2 && anchoropt[len - 2] == '/')
2150171172Smlaier				anchoropt[len - 2] = '\0';
2151171172Smlaier			else
2152171172Smlaier				anchoropt[len - 1] = '\0';
2153171172Smlaier			opts |= PF_OPT_RECURSE;
2154171172Smlaier		}
2155145840Smlaier		if (strlcpy(anchorname, anchoropt,
2156145840Smlaier		    sizeof(anchorname)) >= sizeof(anchorname))
2157145840Smlaier			errx(1, "anchor name '%s' too long",
2158145840Smlaier			    anchoropt);
2159126353Smlaier		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
2160126353Smlaier	}
2161126353Smlaier
2162126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
2163130617Smlaier		dev = open(pf_device, mode);
2164126353Smlaier		if (dev == -1)
2165130617Smlaier			err(1, "%s", pf_device);
2166126353Smlaier		altqsupport = pfctl_test_altqsupport(dev, opts);
2167126353Smlaier	} else {
2168130617Smlaier		dev = open(pf_device, O_RDONLY);
2169130617Smlaier		if (dev >= 0)
2170130617Smlaier			opts |= PF_OPT_DUMMYACTION;
2171126353Smlaier		/* turn off options */
2172126353Smlaier		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
2173126353Smlaier		clearopt = showopt = debugopt = NULL;
2174126355Smlaier#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
2175126355Smlaier		altqsupport = 0;
2176126355Smlaier#else
2177126353Smlaier		altqsupport = 1;
2178126355Smlaier#endif
2179126353Smlaier	}
2180126353Smlaier
2181126353Smlaier	if (opts & PF_OPT_DISABLE)
2182126353Smlaier		if (pfctl_disable(dev, opts))
2183126353Smlaier			error = 1;
2184126353Smlaier
2185126353Smlaier	if (showopt != NULL) {
2186126353Smlaier		switch (*showopt) {
2187126353Smlaier		case 'A':
2188126353Smlaier			pfctl_show_anchors(dev, opts, anchorname);
2189126353Smlaier			break;
2190126353Smlaier		case 'r':
2191126353Smlaier			pfctl_load_fingerprints(dev, opts);
2192171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
2193171172Smlaier			    anchorname, 0);
2194126353Smlaier			break;
2195126353Smlaier		case 'l':
2196126353Smlaier			pfctl_load_fingerprints(dev, opts);
2197171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
2198171172Smlaier			    anchorname, 0);
2199126353Smlaier			break;
2200126353Smlaier		case 'n':
2201126353Smlaier			pfctl_load_fingerprints(dev, opts);
2202145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2203126353Smlaier			break;
2204126353Smlaier		case 'q':
2205130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts,
2206130617Smlaier			    opts & PF_OPT_VERBOSE2);
2207126353Smlaier			break;
2208126353Smlaier		case 's':
2209130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2210126353Smlaier			break;
2211130617Smlaier		case 'S':
2212130617Smlaier			pfctl_show_src_nodes(dev, opts);
2213130617Smlaier			break;
2214126353Smlaier		case 'i':
2215130617Smlaier			pfctl_show_status(dev, opts);
2216126353Smlaier			break;
2217126353Smlaier		case 't':
2218130617Smlaier			pfctl_show_timeouts(dev, opts);
2219126353Smlaier			break;
2220126353Smlaier		case 'm':
2221130617Smlaier			pfctl_show_limits(dev, opts);
2222126353Smlaier			break;
2223126353Smlaier		case 'a':
2224130617Smlaier			opts |= PF_OPT_SHOWALL;
2225126353Smlaier			pfctl_load_fingerprints(dev, opts);
2226126353Smlaier
2227145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2228171172Smlaier			pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
2229130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts, 0);
2230130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2231130617Smlaier			pfctl_show_src_nodes(dev, opts);
2232130617Smlaier			pfctl_show_status(dev, opts);
2233171172Smlaier			pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
2234130617Smlaier			pfctl_show_timeouts(dev, opts);
2235130617Smlaier			pfctl_show_limits(dev, opts);
2236145840Smlaier			pfctl_show_tables(anchorname, opts);
2237126353Smlaier			pfctl_show_fingerprints(opts);
2238126353Smlaier			break;
2239126353Smlaier		case 'T':
2240145840Smlaier			pfctl_show_tables(anchorname, opts);
2241126353Smlaier			break;
2242126353Smlaier		case 'o':
2243126353Smlaier			pfctl_load_fingerprints(dev, opts);
2244126353Smlaier			pfctl_show_fingerprints(opts);
2245126353Smlaier			break;
2246130617Smlaier		case 'I':
2247130617Smlaier			pfctl_show_ifaces(ifaceopt, opts);
2248130617Smlaier			break;
2249126353Smlaier		}
2250126353Smlaier	}
2251126353Smlaier
2252171172Smlaier	if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
2253171172Smlaier		pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
2254171172Smlaier		    anchorname, 0);
2255171172Smlaier
2256126353Smlaier	if (clearopt != NULL) {
2257171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2258171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2259171172Smlaier			    "be modified from the command line");
2260171172Smlaier
2261126353Smlaier		switch (*clearopt) {
2262126353Smlaier		case 'r':
2263145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2264126353Smlaier			break;
2265126353Smlaier		case 'n':
2266145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2267126353Smlaier			break;
2268126353Smlaier		case 'q':
2269126353Smlaier			pfctl_clear_altq(dev, opts);
2270126353Smlaier			break;
2271126353Smlaier		case 's':
2272130617Smlaier			pfctl_clear_states(dev, ifaceopt, opts);
2273126353Smlaier			break;
2274130617Smlaier		case 'S':
2275130617Smlaier			pfctl_clear_src_nodes(dev, opts);
2276130617Smlaier			break;
2277126353Smlaier		case 'i':
2278126353Smlaier			pfctl_clear_stats(dev, opts);
2279126353Smlaier			break;
2280126353Smlaier		case 'a':
2281145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2282145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2283145840Smlaier			pfctl_clear_tables(anchorname, opts);
2284145840Smlaier			if (!*anchorname) {
2285130617Smlaier				pfctl_clear_altq(dev, opts);
2286130617Smlaier				pfctl_clear_states(dev, ifaceopt, opts);
2287130617Smlaier				pfctl_clear_src_nodes(dev, opts);
2288130617Smlaier				pfctl_clear_stats(dev, opts);
2289130617Smlaier				pfctl_clear_fingerprints(dev, opts);
2290145840Smlaier				pfctl_clear_interface_flags(dev, opts);
2291130617Smlaier			}
2292126353Smlaier			break;
2293126353Smlaier		case 'o':
2294126353Smlaier			pfctl_clear_fingerprints(dev, opts);
2295126353Smlaier			break;
2296126353Smlaier		case 'T':
2297145840Smlaier			pfctl_clear_tables(anchorname, opts);
2298126353Smlaier			break;
2299126353Smlaier		}
2300126353Smlaier	}
2301126353Smlaier	if (state_killers)
2302130617Smlaier		pfctl_kill_states(dev, ifaceopt, opts);
2303126353Smlaier
2304171172Smlaier	if (src_node_killers)
2305171172Smlaier		pfctl_kill_src_nodes(dev, ifaceopt, opts);
2306171172Smlaier
2307126353Smlaier	if (tblcmdopt != NULL) {
2308126353Smlaier		error = pfctl_command_tables(argc, argv, tableopt,
2309145840Smlaier		    tblcmdopt, rulesopt, anchorname, opts);
2310126353Smlaier		rulesopt = NULL;
2311126353Smlaier	}
2312171172Smlaier	if (optiopt != NULL) {
2313171172Smlaier		switch (*optiopt) {
2314171172Smlaier		case 'n':
2315171172Smlaier			optimize = 0;
2316171172Smlaier			break;
2317171172Smlaier		case 'b':
2318171172Smlaier			optimize |= PF_OPTIMIZE_BASIC;
2319171172Smlaier			break;
2320171172Smlaier		case 'o':
2321171172Smlaier		case 'p':
2322171172Smlaier			optimize |= PF_OPTIMIZE_PROFILE;
2323171172Smlaier			break;
2324171172Smlaier		}
2325171172Smlaier	}
2326126353Smlaier
2327171172Smlaier 	if (rulesopt != NULL) {
2328171172Smlaier		if (strcmp(rulesopt, "-") == 0) {
2329171172Smlaier			fin = stdin;
2330171172Smlaier			rulesopt = "stdin";
2331171172Smlaier		} else {
2332171172Smlaier			if ((fin = pfctl_fopen(rulesopt, "r")) == NULL)
2333171172Smlaier				err(1, "%s", rulesopt);
2334171172Smlaier		}
2335171172Smlaier	}
2336171172Smlaier	if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
2337171172Smlaier	    !anchorname[0])
2338145840Smlaier		if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
2339145840Smlaier			error = 1;
2340145840Smlaier
2341145840Smlaier	if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
2342145840Smlaier	    !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
2343126353Smlaier		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
2344126353Smlaier			error = 1;
2345126353Smlaier
2346126353Smlaier	if (rulesopt != NULL) {
2347171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2348171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2349171172Smlaier			    "be modified from the command line");
2350171172Smlaier		if (pfctl_rules(dev, rulesopt, fin, opts, optimize,
2351171172Smlaier		    anchorname, NULL))
2352126353Smlaier			error = 1;
2353126353Smlaier		else if (!(opts & PF_OPT_NOACTION) &&
2354126353Smlaier		    (loadopt & PFCTL_FLAG_TABLE))
2355126353Smlaier			warn_namespace_collision(NULL);
2356126353Smlaier	}
2357126353Smlaier
2358126353Smlaier	if (opts & PF_OPT_ENABLE)
2359126353Smlaier		if (pfctl_enable(dev, opts))
2360126353Smlaier			error = 1;
2361126353Smlaier
2362126353Smlaier	if (debugopt != NULL) {
2363126353Smlaier		switch (*debugopt) {
2364126353Smlaier		case 'n':
2365126353Smlaier			pfctl_debug(dev, PF_DEBUG_NONE, opts);
2366126353Smlaier			break;
2367126353Smlaier		case 'u':
2368126353Smlaier			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
2369126353Smlaier			break;
2370126353Smlaier		case 'm':
2371126353Smlaier			pfctl_debug(dev, PF_DEBUG_MISC, opts);
2372126353Smlaier			break;
2373126353Smlaier		case 'l':
2374126353Smlaier			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
2375126353Smlaier			break;
2376126353Smlaier		}
2377126353Smlaier	}
2378126353Smlaier
2379126353Smlaier	exit(error);
2380126353Smlaier}
2381