1223637Sbz/*	$OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */
2126353Smlaier
3126353Smlaier/*
4126353Smlaier * Copyright (c) 2001 Daniel Hartmeier
5130617Smlaier * Copyright (c) 2002,2003 Henning Brauer
6126353Smlaier * All rights reserved.
7126353Smlaier *
8126353Smlaier * Redistribution and use in source and binary forms, with or without
9126353Smlaier * modification, are permitted provided that the following conditions
10126353Smlaier * are met:
11126353Smlaier *
12126353Smlaier *    - Redistributions of source code must retain the above copyright
13126353Smlaier *      notice, this list of conditions and the following disclaimer.
14126353Smlaier *    - Redistributions in binary form must reproduce the above
15126353Smlaier *      copyright notice, this list of conditions and the following
16126353Smlaier *      disclaimer in the documentation and/or other materials provided
17126353Smlaier *      with the distribution.
18126353Smlaier *
19126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20126353Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21126353Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22126353Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23126353Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24126353Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25126353Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26126353Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27126353Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29126353Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30126353Smlaier * POSSIBILITY OF SUCH DAMAGE.
31126353Smlaier *
32126353Smlaier */
33126353Smlaier
34127082Sobrien#include <sys/cdefs.h>
35127082Sobrien__FBSDID("$FreeBSD$");
36127082Sobrien
37126353Smlaier#include <sys/types.h>
38126353Smlaier#include <sys/ioctl.h>
39126353Smlaier#include <sys/socket.h>
40145840Smlaier#include <sys/stat.h>
41126353Smlaier
42223637Sbz#ifdef __FreeBSD__
43223637Sbz#include <sys/endian.h>
44223637Sbz#endif
45223637Sbz
46126353Smlaier#include <net/if.h>
47126353Smlaier#include <netinet/in.h>
48126353Smlaier#include <net/pfvar.h>
49126353Smlaier#include <arpa/inet.h>
50126353Smlaier#include <altq/altq.h>
51171172Smlaier#include <sys/sysctl.h>
52126353Smlaier
53126353Smlaier#include <err.h>
54126353Smlaier#include <errno.h>
55126353Smlaier#include <fcntl.h>
56126353Smlaier#include <limits.h>
57126353Smlaier#include <netdb.h>
58126353Smlaier#include <stdio.h>
59126353Smlaier#include <stdlib.h>
60126353Smlaier#include <string.h>
61126353Smlaier#include <unistd.h>
62126353Smlaier
63126353Smlaier#include "pfctl_parser.h"
64126353Smlaier#include "pfctl.h"
65126353Smlaier
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);
78223637Sbzint	 pfctl_net_kill_states(int, const char *, int);
79223637Sbzint	 pfctl_label_kill_states(int, const char *, int);
80223637Sbzint	 pfctl_id_kill_states(int, const char *, int);
81145840Smlaiervoid	 pfctl_init_options(struct pfctl *);
82145840Smlaierint	 pfctl_load_options(struct pfctl *);
83145840Smlaierint	 pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
84145840Smlaierint	 pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
85145840Smlaierint	 pfctl_load_debug(struct pfctl *, unsigned int);
86145840Smlaierint	 pfctl_load_logif(struct pfctl *, char *);
87145840Smlaierint	 pfctl_load_hostid(struct pfctl *, unsigned int);
88126353Smlaierint	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
89145840Smlaier	    char *);
90126353Smlaiervoid	 pfctl_print_rule_counters(struct pf_rule *, int);
91171172Smlaierint	 pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
92145840Smlaierint	 pfctl_show_nat(int, int, char *);
93130617Smlaierint	 pfctl_show_src_nodes(int, int);
94130617Smlaierint	 pfctl_show_states(int, const char *, int);
95130617Smlaierint	 pfctl_show_status(int, int);
96130617Smlaierint	 pfctl_show_timeouts(int, int);
97130617Smlaierint	 pfctl_show_limits(int, int);
98145840Smlaiervoid	 pfctl_debug(int, u_int32_t, int);
99126353Smlaierint	 pfctl_test_altqsupport(int, int);
100126353Smlaierint	 pfctl_show_anchors(int, int, char *);
101171172Smlaierint	 pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
102171172Smlaierint	 pfctl_load_ruleset(struct pfctl *, char *,
103171172Smlaier		struct pf_ruleset *, int, int);
104171172Smlaierint	 pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
105126353Smlaierconst char	*pfctl_lookup_option(char *, const char **);
106126353Smlaier
107171172Smlaierstruct pf_anchor_global	 pf_anchors;
108171172Smlaierstruct pf_anchor	 pf_main_anchor;
109171172Smlaier
110126353Smlaierconst char	*clearopt;
111126353Smlaierchar		*rulesopt;
112126353Smlaierconst char	*showopt;
113126353Smlaierconst char	*debugopt;
114126353Smlaierchar		*anchoropt;
115171172Smlaierconst char	*optiopt = NULL;
116130617Smlaierchar		*pf_device = "/dev/pf";
117130617Smlaierchar		*ifaceopt;
118126353Smlaierchar		*tableopt;
119126353Smlaierconst char	*tblcmdopt;
120171172Smlaierint		 src_node_killers;
121171172Smlaierchar		*src_node_kill[2];
122126353Smlaierint		 state_killers;
123126353Smlaierchar		*state_kill[2];
124126353Smlaierint		 loadopt;
125126353Smlaierint		 altqsupport;
126126353Smlaier
127126353Smlaierint		 dev = -1;
128130617Smlaierint		 first_title = 1;
129130617Smlaierint		 labels = 0;
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",
211223637Sbz	"states", "info", "Tables", "osfp", "all", NULL
212126353Smlaier};
213126353Smlaier
214126353Smlaierstatic const char *showopt_list[] = {
215223637Sbz	"nat", "queue", "rules", "Anchors", "Sources", "states", "info",
216130617Smlaier	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
217130617Smlaier	"all", NULL
218126353Smlaier};
219126353Smlaier
220126353Smlaierstatic const char *tblcmdopt_list[] = {
221126353Smlaier	"kill", "flush", "add", "delete", "load", "replace", "show",
222171172Smlaier	"test", "zero", "expire", NULL
223126353Smlaier};
224126353Smlaier
225126353Smlaierstatic const char *debugopt_list[] = {
226126353Smlaier	"none", "urgent", "misc", "loud", NULL
227126353Smlaier};
228126353Smlaier
229171172Smlaierstatic const char *optiopt_list[] = {
230223637Sbz	"none", "basic", "profile", NULL
231171172Smlaier};
232126353Smlaier
233126353Smlaiervoid
234126353Smlaierusage(void)
235126353Smlaier{
236126353Smlaier	extern char *__progname;
237126353Smlaier
238223057Sbz	fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] ", __progname);
239145840Smlaier	fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
240223637Sbz	fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n");
241223637Sbz	fprintf(stderr, "\t[-k host | network | label | id] ");
242223637Sbz	fprintf(stderr, "[-o level] [-p device]\n");
243223637Sbz	fprintf(stderr, "\t[-s modifier] ");
244223637Sbz	fprintf(stderr, "[-t table -T command [address ...]] [-x level]\n");
245126353Smlaier	exit(1);
246126353Smlaier}
247126353Smlaier
248126353Smlaierint
249126353Smlaierpfctl_enable(int dev, int opts)
250126353Smlaier{
251126353Smlaier	if (ioctl(dev, DIOCSTART)) {
252126353Smlaier		if (errno == EEXIST)
253126353Smlaier			errx(1, "pf already enabled");
254127024Smlaier#ifdef __FreeBSD__
255126355Smlaier		else if (errno == ESRCH)
256126355Smlaier			errx(1, "pfil registeration failed");
257126355Smlaier#endif
258126353Smlaier		else
259126353Smlaier			err(1, "DIOCSTART");
260126353Smlaier	}
261126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
262126353Smlaier		fprintf(stderr, "pf enabled\n");
263126353Smlaier
264126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
265126353Smlaier		if (errno != EEXIST)
266126353Smlaier			err(1, "DIOCSTARTALTQ");
267126353Smlaier
268126353Smlaier	return (0);
269126353Smlaier}
270126353Smlaier
271126353Smlaierint
272126353Smlaierpfctl_disable(int dev, int opts)
273126353Smlaier{
274126353Smlaier	if (ioctl(dev, DIOCSTOP)) {
275126353Smlaier		if (errno == ENOENT)
276126353Smlaier			errx(1, "pf not enabled");
277126353Smlaier		else
278126353Smlaier			err(1, "DIOCSTOP");
279126353Smlaier	}
280126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
281126353Smlaier		fprintf(stderr, "pf disabled\n");
282126353Smlaier
283126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
284126353Smlaier			if (errno != ENOENT)
285126353Smlaier				err(1, "DIOCSTOPALTQ");
286126353Smlaier
287126353Smlaier	return (0);
288126353Smlaier}
289126353Smlaier
290126353Smlaierint
291126353Smlaierpfctl_clear_stats(int dev, int opts)
292126353Smlaier{
293126353Smlaier	if (ioctl(dev, DIOCCLRSTATUS))
294126353Smlaier		err(1, "DIOCCLRSTATUS");
295126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
296126353Smlaier		fprintf(stderr, "pf: statistics cleared\n");
297126353Smlaier	return (0);
298126353Smlaier}
299126353Smlaier
300126353Smlaierint
301145840Smlaierpfctl_clear_interface_flags(int dev, int opts)
302126353Smlaier{
303145840Smlaier	struct pfioc_iface	pi;
304126353Smlaier
305145840Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
306145840Smlaier		bzero(&pi, sizeof(pi));
307171172Smlaier		pi.pfiio_flags = PFI_IFLAG_SKIP;
308126353Smlaier
309145840Smlaier		if (ioctl(dev, DIOCCLRIFFLAG, &pi))
310145840Smlaier			err(1, "DIOCCLRIFFLAG");
311126353Smlaier		if ((opts & PF_OPT_QUIET) == 0)
312145840Smlaier			fprintf(stderr, "pf: interface flags reset\n");
313126353Smlaier	}
314145840Smlaier	return (0);
315145840Smlaier}
316145840Smlaier
317145840Smlaierint
318145840Smlaierpfctl_clear_rules(int dev, int opts, char *anchorname)
319145840Smlaier{
320145840Smlaier	struct pfr_buffer t;
321145840Smlaier
322130617Smlaier	memset(&t, 0, sizeof(t));
323130617Smlaier	t.pfrb_type = PFRB_TRANS;
324145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
325145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
326130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
327130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
328130617Smlaier		err(1, "pfctl_clear_rules");
329126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
330126353Smlaier		fprintf(stderr, "rules cleared\n");
331126353Smlaier	return (0);
332126353Smlaier}
333126353Smlaier
334126353Smlaierint
335145840Smlaierpfctl_clear_nat(int dev, int opts, char *anchorname)
336126353Smlaier{
337130617Smlaier	struct pfr_buffer t;
338126353Smlaier
339130617Smlaier	memset(&t, 0, sizeof(t));
340130617Smlaier	t.pfrb_type = PFRB_TRANS;
341145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
342145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
343145840Smlaier	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
344130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
345130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
346130617Smlaier		err(1, "pfctl_clear_nat");
347126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
348126353Smlaier		fprintf(stderr, "nat cleared\n");
349126353Smlaier	return (0);
350126353Smlaier}
351126353Smlaier
352126353Smlaierint
353126353Smlaierpfctl_clear_altq(int dev, int opts)
354126353Smlaier{
355130617Smlaier	struct pfr_buffer t;
356126353Smlaier
357126353Smlaier	if (!altqsupport)
358126353Smlaier		return (-1);
359130617Smlaier	memset(&t, 0, sizeof(t));
360130617Smlaier	t.pfrb_type = PFRB_TRANS;
361145840Smlaier	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
362130617Smlaier	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
363130617Smlaier	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
364130617Smlaier		err(1, "pfctl_clear_altq");
365126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
366126353Smlaier		fprintf(stderr, "altq cleared\n");
367126353Smlaier	return (0);
368126353Smlaier}
369126353Smlaier
370126353Smlaierint
371130617Smlaierpfctl_clear_src_nodes(int dev, int opts)
372126353Smlaier{
373130617Smlaier	if (ioctl(dev, DIOCCLRSRCNODES))
374130617Smlaier		err(1, "DIOCCLRSRCNODES");
375130617Smlaier	if ((opts & PF_OPT_QUIET) == 0)
376130617Smlaier		fprintf(stderr, "source tracking entries cleared\n");
377130617Smlaier	return (0);
378130617Smlaier}
379130617Smlaier
380130617Smlaierint
381130617Smlaierpfctl_clear_states(int dev, const char *iface, int opts)
382130617Smlaier{
383130617Smlaier	struct pfioc_state_kill psk;
384130617Smlaier
385130617Smlaier	memset(&psk, 0, sizeof(psk));
386130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
387130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
388130617Smlaier		errx(1, "invalid interface: %s", iface);
389130617Smlaier
390130617Smlaier	if (ioctl(dev, DIOCCLRSTATES, &psk))
391126353Smlaier		err(1, "DIOCCLRSTATES");
392126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
393223637Sbz		fprintf(stderr, "%d states cleared\n", psk.psk_killed);
394126353Smlaier	return (0);
395126353Smlaier}
396126353Smlaier
397171172Smlaiervoid
398171172Smlaierpfctl_addrprefix(char *addr, struct pf_addr *mask)
399171172Smlaier{
400171172Smlaier	char *p;
401171172Smlaier	const char *errstr;
402171172Smlaier	int prefix, ret_ga, q, r;
403171172Smlaier	struct addrinfo hints, *res;
404171172Smlaier
405171172Smlaier	if ((p = strchr(addr, '/')) == NULL)
406171172Smlaier		return;
407171172Smlaier
408171172Smlaier	*p++ = '\0';
409171172Smlaier	prefix = strtonum(p, 0, 128, &errstr);
410171172Smlaier	if (errstr)
411171172Smlaier		errx(1, "prefix is %s: %s", errstr, p);
412171172Smlaier
413171172Smlaier	bzero(&hints, sizeof(hints));
414171172Smlaier	/* prefix only with numeric addresses */
415171172Smlaier	hints.ai_flags |= AI_NUMERICHOST;
416171172Smlaier
417171172Smlaier	if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
418171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
419171172Smlaier		/* NOTREACHED */
420171172Smlaier	}
421171172Smlaier
422171172Smlaier	if (res->ai_family == AF_INET && prefix > 32)
423171172Smlaier		errx(1, "prefix too long for AF_INET");
424171172Smlaier	else if (res->ai_family == AF_INET6 && prefix > 128)
425171172Smlaier		errx(1, "prefix too long for AF_INET6");
426171172Smlaier
427171172Smlaier	q = prefix >> 3;
428171172Smlaier	r = prefix & 7;
429171172Smlaier	switch (res->ai_family) {
430171172Smlaier	case AF_INET:
431171172Smlaier		bzero(&mask->v4, sizeof(mask->v4));
432171172Smlaier		mask->v4.s_addr = htonl((u_int32_t)
433171172Smlaier		    (0xffffffffffULL << (32 - prefix)));
434171172Smlaier		break;
435171172Smlaier	case AF_INET6:
436171172Smlaier		bzero(&mask->v6, sizeof(mask->v6));
437171172Smlaier		if (q > 0)
438171172Smlaier			memset((void *)&mask->v6, 0xff, q);
439171172Smlaier		if (r > 0)
440171172Smlaier			*((u_char *)&mask->v6 + q) =
441171172Smlaier			    (0xff00 >> r) & 0xff;
442171172Smlaier		break;
443171172Smlaier	}
444171172Smlaier	freeaddrinfo(res);
445171172Smlaier}
446171172Smlaier
447126353Smlaierint
448171172Smlaierpfctl_kill_src_nodes(int dev, const char *iface, int opts)
449171172Smlaier{
450171172Smlaier	struct pfioc_src_node_kill psnk;
451171172Smlaier	struct addrinfo *res[2], *resp[2];
452171172Smlaier	struct sockaddr last_src, last_dst;
453171172Smlaier	int killed, sources, dests;
454171172Smlaier	int ret_ga;
455171172Smlaier
456171172Smlaier	killed = sources = dests = 0;
457171172Smlaier
458171172Smlaier	memset(&psnk, 0, sizeof(psnk));
459171172Smlaier	memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
460171172Smlaier	    sizeof(psnk.psnk_src.addr.v.a.mask));
461171172Smlaier	memset(&last_src, 0xff, sizeof(last_src));
462171172Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
463171172Smlaier
464171172Smlaier	pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
465171172Smlaier
466171172Smlaier	if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
467171172Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
468171172Smlaier		/* NOTREACHED */
469171172Smlaier	}
470171172Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
471171172Smlaier		if (resp[0]->ai_addr == NULL)
472171172Smlaier			continue;
473171172Smlaier		/* We get lots of duplicates.  Catch the easy ones */
474171172Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
475171172Smlaier			continue;
476171172Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
477171172Smlaier
478171172Smlaier		psnk.psnk_af = resp[0]->ai_family;
479171172Smlaier		sources++;
480171172Smlaier
481171172Smlaier		if (psnk.psnk_af == AF_INET)
482171172Smlaier			psnk.psnk_src.addr.v.a.addr.v4 =
483171172Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
484171172Smlaier		else if (psnk.psnk_af == AF_INET6)
485171172Smlaier			psnk.psnk_src.addr.v.a.addr.v6 =
486171172Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
487171172Smlaier			    sin6_addr;
488171172Smlaier		else
489171172Smlaier			errx(1, "Unknown address family %d", psnk.psnk_af);
490171172Smlaier
491171172Smlaier		if (src_node_killers > 1) {
492171172Smlaier			dests = 0;
493171172Smlaier			memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
494171172Smlaier			    sizeof(psnk.psnk_dst.addr.v.a.mask));
495171172Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
496171172Smlaier			pfctl_addrprefix(src_node_kill[1],
497171172Smlaier			    &psnk.psnk_dst.addr.v.a.mask);
498171172Smlaier			if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
499171172Smlaier			    &res[1]))) {
500171172Smlaier				errx(1, "getaddrinfo: %s",
501171172Smlaier				    gai_strerror(ret_ga));
502171172Smlaier				/* NOTREACHED */
503171172Smlaier			}
504171172Smlaier			for (resp[1] = res[1]; resp[1];
505171172Smlaier			    resp[1] = resp[1]->ai_next) {
506171172Smlaier				if (resp[1]->ai_addr == NULL)
507171172Smlaier					continue;
508171172Smlaier				if (psnk.psnk_af != resp[1]->ai_family)
509171172Smlaier					continue;
510171172Smlaier
511171172Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
512171172Smlaier				    sizeof(last_dst)) == 0)
513171172Smlaier					continue;
514171172Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
515171172Smlaier
516171172Smlaier				dests++;
517171172Smlaier
518171172Smlaier				if (psnk.psnk_af == AF_INET)
519171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v4 =
520171172Smlaier					    ((struct sockaddr_in *)resp[1]->
521171172Smlaier					    ai_addr)->sin_addr;
522171172Smlaier				else if (psnk.psnk_af == AF_INET6)
523171172Smlaier					psnk.psnk_dst.addr.v.a.addr.v6 =
524171172Smlaier					    ((struct sockaddr_in6 *)resp[1]->
525171172Smlaier					    ai_addr)->sin6_addr;
526171172Smlaier				else
527171172Smlaier					errx(1, "Unknown address family %d",
528171172Smlaier					    psnk.psnk_af);
529171172Smlaier
530171172Smlaier				if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
531171172Smlaier					err(1, "DIOCKILLSRCNODES");
532223637Sbz				killed += psnk.psnk_killed;
533171172Smlaier			}
534171172Smlaier			freeaddrinfo(res[1]);
535171172Smlaier		} else {
536171172Smlaier			if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
537171172Smlaier				err(1, "DIOCKILLSRCNODES");
538223637Sbz			killed += psnk.psnk_killed;
539171172Smlaier		}
540171172Smlaier	}
541171172Smlaier
542171172Smlaier	freeaddrinfo(res[0]);
543171172Smlaier
544171172Smlaier	if ((opts & PF_OPT_QUIET) == 0)
545171172Smlaier		fprintf(stderr, "killed %d src nodes from %d sources and %d "
546171172Smlaier		    "destinations\n", killed, sources, dests);
547171172Smlaier	return (0);
548171172Smlaier}
549171172Smlaier
550171172Smlaierint
551223637Sbzpfctl_net_kill_states(int dev, const char *iface, int opts)
552126353Smlaier{
553126353Smlaier	struct pfioc_state_kill psk;
554126353Smlaier	struct addrinfo *res[2], *resp[2];
555126353Smlaier	struct sockaddr last_src, last_dst;
556126353Smlaier	int killed, sources, dests;
557126353Smlaier	int ret_ga;
558126353Smlaier
559126353Smlaier	killed = sources = dests = 0;
560126353Smlaier
561126353Smlaier	memset(&psk, 0, sizeof(psk));
562126353Smlaier	memset(&psk.psk_src.addr.v.a.mask, 0xff,
563126353Smlaier	    sizeof(psk.psk_src.addr.v.a.mask));
564126353Smlaier	memset(&last_src, 0xff, sizeof(last_src));
565126353Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
566130617Smlaier	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
567130617Smlaier	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
568130617Smlaier		errx(1, "invalid interface: %s", iface);
569126353Smlaier
570171172Smlaier	pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
571171172Smlaier
572126353Smlaier	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
573126353Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
574126353Smlaier		/* NOTREACHED */
575126353Smlaier	}
576126353Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
577126353Smlaier		if (resp[0]->ai_addr == NULL)
578126353Smlaier			continue;
579126353Smlaier		/* We get lots of duplicates.  Catch the easy ones */
580126353Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
581126353Smlaier			continue;
582126353Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
583126353Smlaier
584126353Smlaier		psk.psk_af = resp[0]->ai_family;
585126353Smlaier		sources++;
586126353Smlaier
587126353Smlaier		if (psk.psk_af == AF_INET)
588126353Smlaier			psk.psk_src.addr.v.a.addr.v4 =
589126353Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
590126353Smlaier		else if (psk.psk_af == AF_INET6)
591126353Smlaier			psk.psk_src.addr.v.a.addr.v6 =
592126353Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
593126353Smlaier			    sin6_addr;
594126353Smlaier		else
595126353Smlaier			errx(1, "Unknown address family %d", psk.psk_af);
596126353Smlaier
597126353Smlaier		if (state_killers > 1) {
598126353Smlaier			dests = 0;
599126353Smlaier			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
600126353Smlaier			    sizeof(psk.psk_dst.addr.v.a.mask));
601126353Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
602171172Smlaier			pfctl_addrprefix(state_kill[1],
603171172Smlaier			    &psk.psk_dst.addr.v.a.mask);
604126353Smlaier			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
605126353Smlaier			    &res[1]))) {
606130617Smlaier				errx(1, "getaddrinfo: %s",
607130617Smlaier				    gai_strerror(ret_ga));
608126353Smlaier				/* NOTREACHED */
609126353Smlaier			}
610126353Smlaier			for (resp[1] = res[1]; resp[1];
611126353Smlaier			    resp[1] = resp[1]->ai_next) {
612126353Smlaier				if (resp[1]->ai_addr == NULL)
613126353Smlaier					continue;
614126353Smlaier				if (psk.psk_af != resp[1]->ai_family)
615126353Smlaier					continue;
616126353Smlaier
617126353Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
618126353Smlaier				    sizeof(last_dst)) == 0)
619126353Smlaier					continue;
620126353Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
621126353Smlaier
622126353Smlaier				dests++;
623126353Smlaier
624126353Smlaier				if (psk.psk_af == AF_INET)
625126353Smlaier					psk.psk_dst.addr.v.a.addr.v4 =
626126353Smlaier					    ((struct sockaddr_in *)resp[1]->
627126353Smlaier					    ai_addr)->sin_addr;
628126353Smlaier				else if (psk.psk_af == AF_INET6)
629126353Smlaier					psk.psk_dst.addr.v.a.addr.v6 =
630126353Smlaier					    ((struct sockaddr_in6 *)resp[1]->
631126353Smlaier					    ai_addr)->sin6_addr;
632126353Smlaier				else
633126353Smlaier					errx(1, "Unknown address family %d",
634126353Smlaier					    psk.psk_af);
635126353Smlaier
636126353Smlaier				if (ioctl(dev, DIOCKILLSTATES, &psk))
637126353Smlaier					err(1, "DIOCKILLSTATES");
638223637Sbz				killed += psk.psk_killed;
639126353Smlaier			}
640126353Smlaier			freeaddrinfo(res[1]);
641126353Smlaier		} else {
642126353Smlaier			if (ioctl(dev, DIOCKILLSTATES, &psk))
643126353Smlaier				err(1, "DIOCKILLSTATES");
644223637Sbz			killed += psk.psk_killed;
645126353Smlaier		}
646126353Smlaier	}
647126353Smlaier
648126353Smlaier	freeaddrinfo(res[0]);
649126353Smlaier
650126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
651126353Smlaier		fprintf(stderr, "killed %d states from %d sources and %d "
652126353Smlaier		    "destinations\n", killed, sources, dests);
653126353Smlaier	return (0);
654126353Smlaier}
655126353Smlaier
656126353Smlaierint
657223637Sbzpfctl_label_kill_states(int dev, const char *iface, int opts)
658223637Sbz{
659223637Sbz	struct pfioc_state_kill psk;
660223637Sbz
661223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
662223637Sbz		warnx("no label specified");
663223637Sbz		usage();
664223637Sbz	}
665223637Sbz	memset(&psk, 0, sizeof(psk));
666223637Sbz	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
667223637Sbz	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
668223637Sbz		errx(1, "invalid interface: %s", iface);
669223637Sbz
670223637Sbz	if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
671223637Sbz	    sizeof(psk.psk_label))
672223637Sbz		errx(1, "label too long: %s", state_kill[1]);
673223637Sbz
674223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
675223637Sbz		err(1, "DIOCKILLSTATES");
676223637Sbz
677223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
678223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
679223637Sbz
680223637Sbz	return (0);
681223637Sbz}
682223637Sbz
683223637Sbzint
684223637Sbzpfctl_id_kill_states(int dev, const char *iface, int opts)
685223637Sbz{
686223637Sbz	struct pfioc_state_kill psk;
687223637Sbz
688223637Sbz	if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
689223637Sbz		warnx("no id specified");
690223637Sbz		usage();
691223637Sbz	}
692223637Sbz
693223637Sbz	memset(&psk, 0, sizeof(psk));
694223637Sbz	if ((sscanf(state_kill[1], "%jx/%x",
695223637Sbz	    &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
696223637Sbz		HTONL(psk.psk_pfcmp.creatorid);
697223637Sbz	else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
698223637Sbz		psk.psk_pfcmp.creatorid = 0;
699223637Sbz	} else {
700223637Sbz		warnx("wrong id format specified");
701223637Sbz		usage();
702223637Sbz	}
703223637Sbz	if (psk.psk_pfcmp.id == 0) {
704223637Sbz		warnx("cannot kill id 0");
705223637Sbz		usage();
706223637Sbz	}
707223637Sbz
708223637Sbz	psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
709223637Sbz	if (ioctl(dev, DIOCKILLSTATES, &psk))
710223637Sbz		err(1, "DIOCKILLSTATES");
711223637Sbz
712223637Sbz	if ((opts & PF_OPT_QUIET) == 0)
713223637Sbz		fprintf(stderr, "killed %d states\n", psk.psk_killed);
714223637Sbz
715223637Sbz	return (0);
716223637Sbz}
717223637Sbz
718223637Sbzint
719126353Smlaierpfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
720145840Smlaier    u_int32_t ticket, int r_action, char *anchorname)
721126353Smlaier{
722126353Smlaier	struct pfioc_pooladdr pp;
723126353Smlaier	struct pf_pooladdr *pa;
724126353Smlaier	u_int32_t pnr, mpnr;
725126353Smlaier
726126353Smlaier	memset(&pp, 0, sizeof(pp));
727126353Smlaier	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
728126353Smlaier	pp.r_action = r_action;
729126353Smlaier	pp.r_num = nr;
730126353Smlaier	pp.ticket = ticket;
731126353Smlaier	if (ioctl(dev, DIOCGETADDRS, &pp)) {
732126353Smlaier		warn("DIOCGETADDRS");
733126353Smlaier		return (-1);
734126353Smlaier	}
735126353Smlaier	mpnr = pp.nr;
736126353Smlaier	TAILQ_INIT(&pool->list);
737126353Smlaier	for (pnr = 0; pnr < mpnr; ++pnr) {
738126353Smlaier		pp.nr = pnr;
739126353Smlaier		if (ioctl(dev, DIOCGETADDR, &pp)) {
740126353Smlaier			warn("DIOCGETADDR");
741126353Smlaier			return (-1);
742126353Smlaier		}
743126353Smlaier		pa = calloc(1, sizeof(struct pf_pooladdr));
744126353Smlaier		if (pa == NULL)
745126353Smlaier			err(1, "calloc");
746126353Smlaier		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
747126353Smlaier		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
748126353Smlaier	}
749126353Smlaier
750126353Smlaier	return (0);
751126353Smlaier}
752126353Smlaier
753126353Smlaiervoid
754171172Smlaierpfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
755171172Smlaier{
756171172Smlaier	struct pf_pooladdr *pa;
757171172Smlaier
758171172Smlaier	while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
759171172Smlaier		TAILQ_REMOVE(&src->list, pa, entries);
760171172Smlaier		TAILQ_INSERT_TAIL(&dst->list, pa, entries);
761171172Smlaier	}
762171172Smlaier}
763171172Smlaier
764171172Smlaiervoid
765126353Smlaierpfctl_clear_pool(struct pf_pool *pool)
766126353Smlaier{
767126353Smlaier	struct pf_pooladdr *pa;
768126353Smlaier
769126353Smlaier	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
770126353Smlaier		TAILQ_REMOVE(&pool->list, pa, entries);
771126353Smlaier		free(pa);
772126353Smlaier	}
773126353Smlaier}
774126353Smlaier
775126353Smlaiervoid
776126353Smlaierpfctl_print_rule_counters(struct pf_rule *rule, int opts)
777126353Smlaier{
778126353Smlaier	if (opts & PF_OPT_DEBUG) {
779126353Smlaier		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
780126353Smlaier		    "p", "sa", "sp", "da", "dp" };
781126353Smlaier		int i;
782126353Smlaier
783126353Smlaier		printf("  [ Skip steps: ");
784126353Smlaier		for (i = 0; i < PF_SKIP_COUNT; ++i) {
785126353Smlaier			if (rule->skip[i].nr == rule->nr + 1)
786126353Smlaier				continue;
787126353Smlaier			printf("%s=", t[i]);
788126353Smlaier			if (rule->skip[i].nr == -1)
789126353Smlaier				printf("end ");
790126353Smlaier			else
791126353Smlaier				printf("%u ", rule->skip[i].nr);
792126353Smlaier		}
793126353Smlaier		printf("]\n");
794126353Smlaier
795126353Smlaier		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
796126353Smlaier		    rule->qname, rule->qid, rule->pqname, rule->pqid);
797126353Smlaier	}
798171172Smlaier	if (opts & PF_OPT_VERBOSE) {
799127024Smlaier		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
800127024Smlaier			    "Bytes: %-10llu  States: %-6u]\n",
801127024Smlaier			    (unsigned long long)rule->evaluations,
802171172Smlaier			    (unsigned long long)(rule->packets[0] +
803171172Smlaier			    rule->packets[1]),
804171172Smlaier			    (unsigned long long)(rule->bytes[0] +
805223637Sbz			    rule->bytes[1]), rule->states_cur);
806171172Smlaier		if (!(opts & PF_OPT_DEBUG))
807223637Sbz			printf("  [ Inserted: uid %u pid %u "
808223637Sbz			    "State Creations: %-6u]\n",
809223637Sbz			    (unsigned)rule->cuid, (unsigned)rule->cpid,
810223637Sbz			    rule->states_tot);
811171172Smlaier	}
812126353Smlaier}
813126353Smlaier
814130617Smlaiervoid
815130617Smlaierpfctl_print_title(char *title)
816130617Smlaier{
817130617Smlaier	if (!first_title)
818130617Smlaier		printf("\n");
819130617Smlaier	first_title = 0;
820130617Smlaier	printf("%s\n", title);
821130617Smlaier}
822130617Smlaier
823126353Smlaierint
824171172Smlaierpfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
825171172Smlaier    char *anchorname, int depth)
826126353Smlaier{
827126353Smlaier	struct pfioc_rule pr;
828130617Smlaier	u_int32_t nr, mnr, header = 0;
829126353Smlaier	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
830223057Sbz	int numeric = opts & PF_OPT_NUMERIC;
831171172Smlaier	int len = strlen(path);
832171172Smlaier	int brace;
833171172Smlaier	char *p;
834126353Smlaier
835171172Smlaier	if (path[0])
836171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
837171172Smlaier	else
838171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
839171172Smlaier
840126353Smlaier	memset(&pr, 0, sizeof(pr));
841171172Smlaier	memcpy(pr.anchor, path, sizeof(pr.anchor));
842130617Smlaier	if (opts & PF_OPT_SHOWALL) {
843130617Smlaier		pr.rule.action = PF_PASS;
844130617Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
845130617Smlaier			warn("DIOCGETRULES");
846171172Smlaier			goto error;
847130617Smlaier		}
848130617Smlaier		header++;
849130617Smlaier	}
850126353Smlaier	pr.rule.action = PF_SCRUB;
851126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
852126353Smlaier		warn("DIOCGETRULES");
853171172Smlaier		goto error;
854126353Smlaier	}
855130617Smlaier	if (opts & PF_OPT_SHOWALL) {
856171172Smlaier		if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
857130617Smlaier			pfctl_print_title("FILTER RULES:");
858171172Smlaier		else if (format == PFCTL_SHOW_LABELS && labels)
859130617Smlaier			pfctl_print_title("LABEL COUNTERS:");
860130617Smlaier	}
861126353Smlaier	mnr = pr.nr;
862171172Smlaier	if (opts & PF_OPT_CLRRULECTRS)
863171172Smlaier		pr.action = PF_GET_CLR_CNTR;
864171172Smlaier
865126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
866126353Smlaier		pr.nr = nr;
867126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
868126353Smlaier			warn("DIOCGETRULE");
869171172Smlaier			goto error;
870126353Smlaier		}
871126353Smlaier
872126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
873171172Smlaier		    nr, pr.ticket, PF_SCRUB, path) != 0)
874171172Smlaier			goto error;
875126353Smlaier
876126353Smlaier		switch (format) {
877171172Smlaier		case PFCTL_SHOW_LABELS:
878126353Smlaier			break;
879171172Smlaier		case PFCTL_SHOW_RULES:
880130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
881130617Smlaier				labels = 1;
882223057Sbz			print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
883171172Smlaier			printf("\n");
884126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
885171172Smlaier			break;
886171172Smlaier		case PFCTL_SHOW_NOTHING:
887171172Smlaier			break;
888126353Smlaier		}
889126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
890126353Smlaier	}
891126353Smlaier	pr.rule.action = PF_PASS;
892126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
893126353Smlaier		warn("DIOCGETRULES");
894171172Smlaier		goto error;
895126353Smlaier	}
896126353Smlaier	mnr = pr.nr;
897126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
898126353Smlaier		pr.nr = nr;
899126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
900126353Smlaier			warn("DIOCGETRULE");
901171172Smlaier			goto error;
902126353Smlaier		}
903126353Smlaier
904126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
905171172Smlaier		    nr, pr.ticket, PF_PASS, path) != 0)
906171172Smlaier			goto error;
907126353Smlaier
908126353Smlaier		switch (format) {
909171172Smlaier		case PFCTL_SHOW_LABELS:
910126353Smlaier			if (pr.rule.label[0]) {
911223637Sbz				printf("%s %llu %llu %llu %llu"
912223637Sbz				    " %llu %llu %llu %llu\n",
913223637Sbz				    pr.rule.label,
914127024Smlaier				    (unsigned long long)pr.rule.evaluations,
915171172Smlaier				    (unsigned long long)(pr.rule.packets[0] +
916171172Smlaier				    pr.rule.packets[1]),
917171172Smlaier				    (unsigned long long)(pr.rule.bytes[0] +
918171172Smlaier				    pr.rule.bytes[1]),
919171172Smlaier				    (unsigned long long)pr.rule.packets[0],
920171172Smlaier				    (unsigned long long)pr.rule.bytes[0],
921171172Smlaier				    (unsigned long long)pr.rule.packets[1],
922223637Sbz				    (unsigned long long)pr.rule.bytes[1],
923223637Sbz				    (unsigned long long)pr.rule.states_tot);
924126353Smlaier			}
925126353Smlaier			break;
926171172Smlaier		case PFCTL_SHOW_RULES:
927171172Smlaier			brace = 0;
928130617Smlaier			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
929130617Smlaier				labels = 1;
930171172Smlaier			INDENT(depth, !(opts & PF_OPT_VERBOSE));
931171172Smlaier			if (pr.anchor_call[0] &&
932171172Smlaier			   ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
933171172Smlaier			   ((void *)p == (void *)pr.anchor_call ||
934171172Smlaier			   *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
935171172Smlaier				brace++;
936171172Smlaier				if ((p = strrchr(pr.anchor_call, '/')) !=
937171172Smlaier				    NULL)
938171172Smlaier					p++;
939171172Smlaier				else
940171172Smlaier					p = &pr.anchor_call[0];
941171172Smlaier			} else
942171172Smlaier				p = &pr.anchor_call[0];
943171172Smlaier
944223057Sbz			print_rule(&pr.rule, p, rule_numbers, numeric);
945171172Smlaier			if (brace)
946171172Smlaier				printf(" {\n");
947171172Smlaier			else
948171172Smlaier				printf("\n");
949126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
950171172Smlaier			if (brace) {
951171172Smlaier				pfctl_show_rules(dev, path, opts, format,
952171172Smlaier				    p, depth + 1);
953171172Smlaier				INDENT(depth, !(opts & PF_OPT_VERBOSE));
954171172Smlaier				printf("}\n");
955171172Smlaier			}
956171172Smlaier			break;
957171172Smlaier		case PFCTL_SHOW_NOTHING:
958171172Smlaier			break;
959126353Smlaier		}
960126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
961126353Smlaier	}
962171172Smlaier	path[len] = '\0';
963126353Smlaier	return (0);
964171172Smlaier
965171172Smlaier error:
966171172Smlaier	path[len] = '\0';
967171172Smlaier	return (-1);
968126353Smlaier}
969126353Smlaier
970126353Smlaierint
971145840Smlaierpfctl_show_nat(int dev, int opts, char *anchorname)
972126353Smlaier{
973126353Smlaier	struct pfioc_rule pr;
974126353Smlaier	u_int32_t mnr, nr;
975126353Smlaier	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
976130617Smlaier	int i, dotitle = opts & PF_OPT_SHOWALL;
977126353Smlaier
978126353Smlaier	memset(&pr, 0, sizeof(pr));
979126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
980126353Smlaier	for (i = 0; i < 3; i++) {
981126353Smlaier		pr.rule.action = nattype[i];
982126353Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
983126353Smlaier			warn("DIOCGETRULES");
984126353Smlaier			return (-1);
985126353Smlaier		}
986126353Smlaier		mnr = pr.nr;
987126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
988126353Smlaier			pr.nr = nr;
989126353Smlaier			if (ioctl(dev, DIOCGETRULE, &pr)) {
990126353Smlaier				warn("DIOCGETRULE");
991126353Smlaier				return (-1);
992126353Smlaier			}
993126353Smlaier			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
994145840Smlaier			    pr.ticket, nattype[i], anchorname) != 0)
995126353Smlaier				return (-1);
996130617Smlaier			if (dotitle) {
997130617Smlaier				pfctl_print_title("TRANSLATION RULES:");
998130617Smlaier				dotitle = 0;
999130617Smlaier			}
1000145840Smlaier			print_rule(&pr.rule, pr.anchor_call,
1001223057Sbz			    opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
1002171172Smlaier			printf("\n");
1003126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
1004126353Smlaier			pfctl_clear_pool(&pr.rule.rpool);
1005126353Smlaier		}
1006126353Smlaier	}
1007126353Smlaier	return (0);
1008126353Smlaier}
1009126353Smlaier
1010126353Smlaierint
1011130617Smlaierpfctl_show_src_nodes(int dev, int opts)
1012126353Smlaier{
1013130617Smlaier	struct pfioc_src_nodes psn;
1014130617Smlaier	struct pf_src_node *p;
1015130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1016223637Sbz	unsigned int len = 0;
1017130617Smlaier	int i;
1018130617Smlaier
1019130617Smlaier	memset(&psn, 0, sizeof(psn));
1020130617Smlaier	for (;;) {
1021130617Smlaier		psn.psn_len = len;
1022130617Smlaier		if (len) {
1023130617Smlaier			newinbuf = realloc(inbuf, len);
1024130617Smlaier			if (newinbuf == NULL)
1025130617Smlaier				err(1, "realloc");
1026130617Smlaier			psn.psn_buf = inbuf = newinbuf;
1027130617Smlaier		}
1028130617Smlaier		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
1029130617Smlaier			warn("DIOCGETSRCNODES");
1030171172Smlaier			free(inbuf);
1031130617Smlaier			return (-1);
1032130617Smlaier		}
1033130617Smlaier		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
1034130617Smlaier			break;
1035130617Smlaier		if (len == 0 && psn.psn_len == 0)
1036171172Smlaier			goto done;
1037130617Smlaier		if (len == 0 && psn.psn_len != 0)
1038130617Smlaier			len = psn.psn_len;
1039130617Smlaier		if (psn.psn_len == 0)
1040171172Smlaier			goto done;	/* no src_nodes */
1041130617Smlaier		len *= 2;
1042130617Smlaier	}
1043130617Smlaier	p = psn.psn_src_nodes;
1044130617Smlaier	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
1045130617Smlaier		pfctl_print_title("SOURCE TRACKING NODES:");
1046130617Smlaier	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
1047130617Smlaier		print_src_node(p, opts);
1048130617Smlaier		p++;
1049130617Smlaier	}
1050171172Smlaierdone:
1051171172Smlaier	free(inbuf);
1052130617Smlaier	return (0);
1053130617Smlaier}
1054130617Smlaier
1055130617Smlaierint
1056130617Smlaierpfctl_show_states(int dev, const char *iface, int opts)
1057130617Smlaier{
1058126353Smlaier	struct pfioc_states ps;
1059223637Sbz	struct pfsync_state *p;
1060130617Smlaier	char *inbuf = NULL, *newinbuf = NULL;
1061223637Sbz	unsigned int len = 0;
1062130617Smlaier	int i, dotitle = (opts & PF_OPT_SHOWALL);
1063126353Smlaier
1064126353Smlaier	memset(&ps, 0, sizeof(ps));
1065126353Smlaier	for (;;) {
1066126353Smlaier		ps.ps_len = len;
1067126353Smlaier		if (len) {
1068130617Smlaier			newinbuf = realloc(inbuf, len);
1069130617Smlaier			if (newinbuf == NULL)
1070126353Smlaier				err(1, "realloc");
1071130617Smlaier			ps.ps_buf = inbuf = newinbuf;
1072126353Smlaier		}
1073126353Smlaier		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
1074126353Smlaier			warn("DIOCGETSTATES");
1075171172Smlaier			free(inbuf);
1076126353Smlaier			return (-1);
1077126353Smlaier		}
1078126353Smlaier		if (ps.ps_len + sizeof(struct pfioc_states) < len)
1079126353Smlaier			break;
1080126353Smlaier		if (len == 0 && ps.ps_len == 0)
1081171172Smlaier			goto done;
1082126353Smlaier		if (len == 0 && ps.ps_len != 0)
1083126353Smlaier			len = ps.ps_len;
1084126353Smlaier		if (ps.ps_len == 0)
1085171172Smlaier			goto done;	/* no states */
1086126353Smlaier		len *= 2;
1087126353Smlaier	}
1088126353Smlaier	p = ps.ps_states;
1089130617Smlaier	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
1090223637Sbz		if (iface != NULL && strcmp(p->ifname, iface))
1091130617Smlaier			continue;
1092130617Smlaier		if (dotitle) {
1093130617Smlaier			pfctl_print_title("STATES:");
1094130617Smlaier			dotitle = 0;
1095130617Smlaier		}
1096130617Smlaier		print_state(p, opts);
1097126353Smlaier	}
1098171172Smlaierdone:
1099171172Smlaier	free(inbuf);
1100126353Smlaier	return (0);
1101126353Smlaier}
1102126353Smlaier
1103126353Smlaierint
1104130617Smlaierpfctl_show_status(int dev, int opts)
1105126353Smlaier{
1106126353Smlaier	struct pf_status status;
1107126353Smlaier
1108126353Smlaier	if (ioctl(dev, DIOCGETSTATUS, &status)) {
1109126353Smlaier		warn("DIOCGETSTATUS");
1110126353Smlaier		return (-1);
1111126353Smlaier	}
1112130617Smlaier	if (opts & PF_OPT_SHOWALL)
1113130617Smlaier		pfctl_print_title("INFO:");
1114130617Smlaier	print_status(&status, opts);
1115126353Smlaier	return (0);
1116126353Smlaier}
1117126353Smlaier
1118126353Smlaierint
1119130617Smlaierpfctl_show_timeouts(int dev, int opts)
1120126353Smlaier{
1121126353Smlaier	struct pfioc_tm pt;
1122126353Smlaier	int i;
1123126353Smlaier
1124130617Smlaier	if (opts & PF_OPT_SHOWALL)
1125130617Smlaier		pfctl_print_title("TIMEOUTS:");
1126126353Smlaier	memset(&pt, 0, sizeof(pt));
1127126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1128126353Smlaier		pt.timeout = pf_timeouts[i].timeout;
1129126353Smlaier		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
1130126353Smlaier			err(1, "DIOCGETTIMEOUT");
1131126353Smlaier		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
1132145840Smlaier		if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1133145840Smlaier		    pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1134126353Smlaier			printf(" states");
1135126353Smlaier		else
1136126353Smlaier			printf("s");
1137126353Smlaier		printf("\n");
1138126353Smlaier	}
1139126353Smlaier	return (0);
1140126353Smlaier
1141126353Smlaier}
1142126353Smlaier
1143126353Smlaierint
1144130617Smlaierpfctl_show_limits(int dev, int opts)
1145126353Smlaier{
1146126353Smlaier	struct pfioc_limit pl;
1147126353Smlaier	int i;
1148126353Smlaier
1149130617Smlaier	if (opts & PF_OPT_SHOWALL)
1150130617Smlaier		pfctl_print_title("LIMITS:");
1151126353Smlaier	memset(&pl, 0, sizeof(pl));
1152126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1153130617Smlaier		pl.index = pf_limits[i].index;
1154126353Smlaier		if (ioctl(dev, DIOCGETLIMIT, &pl))
1155126353Smlaier			err(1, "DIOCGETLIMIT");
1156171172Smlaier		printf("%-13s ", pf_limits[i].name);
1157126353Smlaier		if (pl.limit == UINT_MAX)
1158126353Smlaier			printf("unlimited\n");
1159126353Smlaier		else
1160171172Smlaier			printf("hard limit %8u\n", pl.limit);
1161126353Smlaier	}
1162126353Smlaier	return (0);
1163126353Smlaier}
1164126353Smlaier
1165126353Smlaier/* callbacks for rule/nat/rdr/addr */
1166126353Smlaierint
1167126353Smlaierpfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
1168126353Smlaier{
1169126353Smlaier	struct pf_pooladdr *pa;
1170126353Smlaier
1171126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1172126353Smlaier		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
1173126353Smlaier			err(1, "DIOCBEGINADDRS");
1174126353Smlaier	}
1175126353Smlaier
1176126353Smlaier	pf->paddr.af = af;
1177126353Smlaier	TAILQ_FOREACH(pa, &p->list, entries) {
1178126353Smlaier		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
1179126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1180126353Smlaier			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
1181126353Smlaier				err(1, "DIOCADDADDR");
1182126353Smlaier		}
1183126353Smlaier	}
1184126353Smlaier	return (0);
1185126353Smlaier}
1186126353Smlaier
1187126353Smlaierint
1188145840Smlaierpfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
1189126353Smlaier{
1190130617Smlaier	u_int8_t		rs_num;
1191171172Smlaier	struct pf_rule		*rule;
1192171172Smlaier	struct pf_ruleset	*rs;
1193171172Smlaier	char 			*p;
1194126353Smlaier
1195171172Smlaier	rs_num = pf_get_ruleset_number(r->action);
1196171172Smlaier	if (rs_num == PF_RULESET_MAX)
1197145840Smlaier		errx(1, "Invalid rule type %d", r->action);
1198126353Smlaier
1199171172Smlaier	rs = &pf->anchor->ruleset;
1200145840Smlaier
1201171172Smlaier	if (anchor_call[0] && r->anchor == NULL) {
1202171172Smlaier		/*
1203171172Smlaier		 * Don't make non-brace anchors part of the main anchor pool.
1204145840Smlaier		 */
1205171172Smlaier		if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1206171172Smlaier			err(1, "pfctl_add_rule: calloc");
1207171172Smlaier
1208171172Smlaier		pf_init_ruleset(&r->anchor->ruleset);
1209171172Smlaier		r->anchor->ruleset.anchor = r->anchor;
1210171172Smlaier		if (strlcpy(r->anchor->path, anchor_call,
1211171172Smlaier		    sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1212223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1213171172Smlaier		if ((p = strrchr(anchor_call, '/')) != NULL) {
1214171172Smlaier			if (!strlen(p))
1215171172Smlaier				err(1, "pfctl_add_rule: bad anchor name %s",
1216171172Smlaier				    anchor_call);
1217171172Smlaier		} else
1218171172Smlaier			p = (char *)anchor_call;
1219171172Smlaier		if (strlcpy(r->anchor->name, p,
1220171172Smlaier		    sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1221223637Sbz			errx(1, "pfctl_add_rule: strlcpy");
1222171172Smlaier	}
1223145840Smlaier
1224171172Smlaier	if ((rule = calloc(1, sizeof(*rule))) == NULL)
1225171172Smlaier		err(1, "calloc");
1226171172Smlaier	bcopy(r, rule, sizeof(*rule));
1227171172Smlaier	TAILQ_INIT(&rule->rpool.list);
1228171172Smlaier	pfctl_move_pool(&r->rpool, &rule->rpool);
1229145840Smlaier
1230171172Smlaier	TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1231171172Smlaier	return (0);
1232171172Smlaier}
1233171172Smlaier
1234171172Smlaierint
1235171172Smlaierpfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
1236171172Smlaier{
1237171172Smlaier	int osize = pf->trans->pfrb_size;
1238171172Smlaier
1239171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1240171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1241171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1242171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1243171172Smlaier			return (1);
1244171172Smlaier	}
1245171172Smlaier	if (a == pf->astack[0] && ((altqsupport &&
1246223637Sbz	    (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1247171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1248171172Smlaier			return (2);
1249171172Smlaier	}
1250171172Smlaier	if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1251171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1252171172Smlaier		    pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1253171172Smlaier			return (3);
1254171172Smlaier	}
1255171172Smlaier	if (pf->loadopt & PFCTL_FLAG_TABLE)
1256171172Smlaier		if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1257171172Smlaier			return (4);
1258171172Smlaier	if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1259171172Smlaier		return (5);
1260171172Smlaier
1261171172Smlaier	return (0);
1262171172Smlaier}
1263171172Smlaier
1264171172Smlaierint
1265171172Smlaierpfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
1266171172Smlaier    int rs_num, int depth)
1267171172Smlaier{
1268171172Smlaier	struct pf_rule *r;
1269171172Smlaier	int		error, len = strlen(path);
1270171172Smlaier	int		brace = 0;
1271171172Smlaier
1272171172Smlaier	pf->anchor = rs->anchor;
1273171172Smlaier
1274171172Smlaier	if (path[0])
1275171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
1276171172Smlaier	else
1277171172Smlaier		snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
1278171172Smlaier
1279171172Smlaier	if (depth) {
1280171172Smlaier		if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
1281171172Smlaier			brace++;
1282171172Smlaier			if (pf->opts & PF_OPT_VERBOSE)
1283171172Smlaier				printf(" {\n");
1284171172Smlaier			if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1285171172Smlaier			    (error = pfctl_ruleset_trans(pf,
1286171172Smlaier			    path, rs->anchor))) {
1287171172Smlaier				printf("pfctl_load_rulesets: "
1288171172Smlaier				    "pfctl_ruleset_trans %d\n", error);
1289171172Smlaier				goto error;
1290145840Smlaier			}
1291171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1292171172Smlaier			printf("\n");
1293145840Smlaier
1294145840Smlaier	}
1295145840Smlaier
1296171172Smlaier	if (pf->optimize && rs_num == PF_RULESET_FILTER)
1297171172Smlaier		pfctl_optimize_ruleset(pf, rs);
1298171172Smlaier
1299171172Smlaier	while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
1300171172Smlaier		TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
1301171172Smlaier		if ((error = pfctl_load_rule(pf, path, r, depth)))
1302171172Smlaier			goto error;
1303171172Smlaier		if (r->anchor) {
1304171172Smlaier			if ((error = pfctl_load_ruleset(pf, path,
1305171172Smlaier			    &r->anchor->ruleset, rs_num, depth + 1)))
1306171172Smlaier				goto error;
1307171172Smlaier		} else if (pf->opts & PF_OPT_VERBOSE)
1308171172Smlaier			printf("\n");
1309171172Smlaier		free(r);
1310171172Smlaier	}
1311171172Smlaier	if (brace && pf->opts & PF_OPT_VERBOSE) {
1312171172Smlaier		INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
1313171172Smlaier		printf("}\n");
1314171172Smlaier	}
1315171172Smlaier	path[len] = '\0';
1316171172Smlaier	return (0);
1317171172Smlaier
1318171172Smlaier error:
1319171172Smlaier	path[len] = '\0';
1320171172Smlaier	return (error);
1321171172Smlaier
1322171172Smlaier}
1323171172Smlaier
1324171172Smlaierint
1325171172Smlaierpfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
1326171172Smlaier{
1327171172Smlaier	u_int8_t		rs_num = pf_get_ruleset_number(r->action);
1328171172Smlaier	char			*name;
1329171172Smlaier	struct pfioc_rule	pr;
1330171172Smlaier	int			len = strlen(path);
1331171172Smlaier
1332171172Smlaier	bzero(&pr, sizeof(pr));
1333171172Smlaier	/* set up anchor before adding to path for anchor_call */
1334171172Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1335171172Smlaier		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
1336171172Smlaier	if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
1337171172Smlaier		errx(1, "pfctl_load_rule: strlcpy");
1338171172Smlaier
1339171172Smlaier	if (r->anchor) {
1340171172Smlaier		if (r->anchor->match) {
1341171172Smlaier			if (path[0])
1342171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1343171172Smlaier				    "/%s", r->anchor->name);
1344171172Smlaier			else
1345171172Smlaier				snprintf(&path[len], MAXPATHLEN - len,
1346171172Smlaier				    "%s", r->anchor->name);
1347171172Smlaier			name = path;
1348171172Smlaier		} else
1349171172Smlaier			name = r->anchor->path;
1350171172Smlaier	} else
1351171172Smlaier		name = "";
1352171172Smlaier
1353126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1354126353Smlaier		if (pfctl_add_pool(pf, &r->rpool, r->af))
1355126353Smlaier			return (1);
1356130617Smlaier		pr.pool_ticket = pf->paddr.ticket;
1357130617Smlaier		memcpy(&pr.rule, r, sizeof(pr.rule));
1358171172Smlaier		if (r->anchor && strlcpy(pr.anchor_call, name,
1359171172Smlaier		    sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
1360171172Smlaier			errx(1, "pfctl_load_rule: strlcpy");
1361130617Smlaier		if (ioctl(pf->dev, DIOCADDRULE, &pr))
1362126353Smlaier			err(1, "DIOCADDRULE");
1363126353Smlaier	}
1364171172Smlaier
1365171172Smlaier	if (pf->opts & PF_OPT_VERBOSE) {
1366171172Smlaier		INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
1367171172Smlaier		print_rule(r, r->anchor ? r->anchor->name : "",
1368223057Sbz		    pf->opts & PF_OPT_VERBOSE2,
1369223057Sbz		    pf->opts & PF_OPT_NUMERIC);
1370171172Smlaier	}
1371171172Smlaier	path[len] = '\0';
1372126353Smlaier	pfctl_clear_pool(&r->rpool);
1373126353Smlaier	return (0);
1374126353Smlaier}
1375126353Smlaier
1376126353Smlaierint
1377126353Smlaierpfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1378126353Smlaier{
1379126353Smlaier	if (altqsupport &&
1380126353Smlaier	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1381126353Smlaier		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1382126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
1383126353Smlaier			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1384126353Smlaier				if (errno == ENXIO)
1385126353Smlaier					errx(1, "qtype not configured");
1386126353Smlaier				else if (errno == ENODEV)
1387126353Smlaier					errx(1, "%s: driver does not support "
1388126353Smlaier					    "altq", a->ifname);
1389126353Smlaier				else
1390126353Smlaier					err(1, "DIOCADDALTQ");
1391126353Smlaier			}
1392126353Smlaier		}
1393126353Smlaier		pfaltq_store(&pf->paltq->altq);
1394126353Smlaier	}
1395126353Smlaier	return (0);
1396126353Smlaier}
1397126353Smlaier
1398126353Smlaierint
1399223637Sbzpfctl_rules(int dev, char *filename, int opts, int optimize,
1400171172Smlaier    char *anchorname, struct pfr_buffer *trans)
1401126353Smlaier{
1402126353Smlaier#define ERR(x) do { warn(x); goto _error; } while(0)
1403126353Smlaier#define ERRX(x) do { warnx(x); goto _error; } while(0)
1404126353Smlaier
1405130617Smlaier	struct pfr_buffer	*t, buf;
1406130617Smlaier	struct pfioc_altq	 pa;
1407130617Smlaier	struct pfctl		 pf;
1408171172Smlaier	struct pf_ruleset	*rs;
1409130617Smlaier	struct pfr_table	 trs;
1410171172Smlaier	char			*path;
1411130617Smlaier	int			 osize;
1412126353Smlaier
1413171172Smlaier	RB_INIT(&pf_anchors);
1414171172Smlaier	memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
1415171172Smlaier	pf_init_ruleset(&pf_main_anchor.ruleset);
1416171172Smlaier	pf_main_anchor.ruleset.anchor = &pf_main_anchor;
1417130617Smlaier	if (trans == NULL) {
1418171172Smlaier		bzero(&buf, sizeof(buf));
1419171172Smlaier		buf.pfrb_type = PFRB_TRANS;
1420171172Smlaier		t = &buf;
1421171172Smlaier		osize = 0;
1422130617Smlaier	} else {
1423171172Smlaier		t = trans;
1424171172Smlaier		osize = t->pfrb_size;
1425130617Smlaier	}
1426130617Smlaier
1427126353Smlaier	memset(&pa, 0, sizeof(pa));
1428126353Smlaier	memset(&pf, 0, sizeof(pf));
1429126353Smlaier	memset(&trs, 0, sizeof(trs));
1430171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
1431171172Smlaier		ERRX("pfctl_rules: calloc");
1432126353Smlaier	if (strlcpy(trs.pfrt_anchor, anchorname,
1433145840Smlaier	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1434126353Smlaier		ERRX("pfctl_rules: strlcpy");
1435126353Smlaier	pf.dev = dev;
1436126353Smlaier	pf.opts = opts;
1437171172Smlaier	pf.optimize = optimize;
1438126353Smlaier	pf.loadopt = loadopt;
1439171172Smlaier
1440171172Smlaier	/* non-brace anchor, create without resolving the path */
1441171172Smlaier	if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
1442171172Smlaier		ERRX("pfctl_rules: calloc");
1443171172Smlaier	rs = &pf.anchor->ruleset;
1444171172Smlaier	pf_init_ruleset(rs);
1445171172Smlaier	rs->anchor = pf.anchor;
1446171172Smlaier	if (strlcpy(pf.anchor->path, anchorname,
1447171172Smlaier	    sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
1448171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1449171172Smlaier	if (strlcpy(pf.anchor->name, anchorname,
1450171172Smlaier	    sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
1451171172Smlaier		errx(1, "pfctl_add_rule: strlcpy");
1452171172Smlaier
1453171172Smlaier
1454171172Smlaier	pf.astack[0] = pf.anchor;
1455171172Smlaier	pf.asd = 0;
1456130617Smlaier	if (anchorname[0])
1457130617Smlaier		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1458126353Smlaier	pf.paltq = &pa;
1459130617Smlaier	pf.trans = t;
1460145840Smlaier	pfctl_init_options(&pf);
1461130617Smlaier
1462130617Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
1463171172Smlaier		/*
1464171172Smlaier		 * XXX For the time being we need to open transactions for
1465171172Smlaier		 * the main ruleset before parsing, because tables are still
1466171172Smlaier		 * loaded at parse time.
1467171172Smlaier		 */
1468171172Smlaier		if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
1469171172Smlaier			ERRX("pfctl_rules");
1470130617Smlaier		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1471171172Smlaier			pa.ticket =
1472171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
1473130617Smlaier		if (pf.loadopt & PFCTL_FLAG_TABLE)
1474171172Smlaier			pf.astack[0]->ruleset.tticket =
1475171172Smlaier			    pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
1476130617Smlaier	}
1477171172Smlaier
1478223637Sbz	if (parse_config(filename, &pf) < 0) {
1479126353Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1480126353Smlaier			ERRX("Syntax error in config file: "
1481126353Smlaier			    "pf rules not loaded");
1482126353Smlaier		else
1483126353Smlaier			goto _error;
1484126353Smlaier	}
1485171172Smlaier
1486171172Smlaier	if ((pf.loadopt & PFCTL_FLAG_FILTER &&
1487171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
1488171172Smlaier	    (pf.loadopt & PFCTL_FLAG_NAT &&
1489171172Smlaier	    (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
1490171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
1491171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
1492171172Smlaier	    (pf.loadopt & PFCTL_FLAG_FILTER &&
1493171172Smlaier	    pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
1494171172Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1495171172Smlaier			ERRX("Unable to load rules into kernel");
1496171172Smlaier		else
1497171172Smlaier			goto _error;
1498145840Smlaier	}
1499145840Smlaier
1500130617Smlaier	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1501126353Smlaier		if (check_commit_altq(dev, opts) != 0)
1502126353Smlaier			ERRX("errors in altq config");
1503145840Smlaier
1504126353Smlaier	/* process "load anchor" directives */
1505145840Smlaier	if (!anchorname[0])
1506171172Smlaier		if (pfctl_load_anchors(dev, &pf, t) == -1)
1507126353Smlaier			ERRX("load anchors");
1508126353Smlaier
1509145840Smlaier	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1510145840Smlaier		if (!anchorname[0])
1511145840Smlaier			if (pfctl_load_options(&pf))
1512145840Smlaier				goto _error;
1513171172Smlaier		if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
1514130617Smlaier			ERR("DIOCXCOMMIT");
1515145840Smlaier	}
1516126353Smlaier	return (0);
1517126353Smlaier
1518126353Smlaier_error:
1519130617Smlaier	if (trans == NULL) {	/* main ruleset */
1520130617Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1521171172Smlaier			if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
1522130617Smlaier				err(1, "DIOCXROLLBACK");
1523130617Smlaier		exit(1);
1524145840Smlaier	} else {		/* sub ruleset */
1525130617Smlaier		return (-1);
1526145840Smlaier	}
1527126353Smlaier
1528126353Smlaier#undef ERR
1529126353Smlaier#undef ERRX
1530126353Smlaier}
1531126353Smlaier
1532145840SmlaierFILE *
1533145840Smlaierpfctl_fopen(const char *name, const char *mode)
1534145840Smlaier{
1535145840Smlaier	struct stat	 st;
1536145840Smlaier	FILE		*fp;
1537145840Smlaier
1538145840Smlaier	fp = fopen(name, mode);
1539145840Smlaier	if (fp == NULL)
1540145840Smlaier		return (NULL);
1541145840Smlaier	if (fstat(fileno(fp), &st)) {
1542145840Smlaier		fclose(fp);
1543145840Smlaier		return (NULL);
1544145840Smlaier	}
1545145840Smlaier	if (S_ISDIR(st.st_mode)) {
1546145840Smlaier		fclose(fp);
1547145840Smlaier		errno = EISDIR;
1548145840Smlaier		return (NULL);
1549145840Smlaier	}
1550145840Smlaier	return (fp);
1551145840Smlaier}
1552145840Smlaier
1553145840Smlaiervoid
1554145840Smlaierpfctl_init_options(struct pfctl *pf)
1555145840Smlaier{
1556223637Sbz	int64_t mem;
1557223637Sbz	int mib[2];
1558171172Smlaier	size_t size;
1559171172Smlaier
1560145840Smlaier	pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1561145840Smlaier	pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1562145840Smlaier	pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1563145840Smlaier	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1564145840Smlaier	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1565145840Smlaier	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1566145840Smlaier	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1567145840Smlaier	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1568145840Smlaier	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1569145840Smlaier	pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1570145840Smlaier	pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1571145840Smlaier	pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1572145840Smlaier	pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1573145840Smlaier	pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1574145840Smlaier	pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1575145840Smlaier	pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1576145840Smlaier	pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1577145840Smlaier	pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1578171172Smlaier	pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
1579171172Smlaier	pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
1580145840Smlaier
1581171172Smlaier	pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
1582171172Smlaier	pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
1583171172Smlaier	pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
1584171172Smlaier	pf->limit[PF_LIMIT_TABLES] = PFR_KTABLE_HIWAT;
1585171172Smlaier	pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
1586145840Smlaier
1587171172Smlaier	mib[0] = CTL_HW;
1588223637Sbz#ifdef __FreeBSD__
1589171172Smlaier	mib[1] = HW_PHYSMEM;
1590223637Sbz#else
1591223637Sbz	mib[1] = HW_PHYSMEM64;
1592223637Sbz#endif
1593171172Smlaier	size = sizeof(mem);
1594223637Sbz	if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1)
1595223637Sbz		err(1, "sysctl");
1596171172Smlaier	if (mem <= 100*1024*1024)
1597171172Smlaier		pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL;
1598171172Smlaier
1599145840Smlaier	pf->debug = PF_DEBUG_URGENT;
1600145840Smlaier}
1601145840Smlaier
1602126353Smlaierint
1603145840Smlaierpfctl_load_options(struct pfctl *pf)
1604126353Smlaier{
1605145840Smlaier	int i, error = 0;
1606126353Smlaier
1607126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1608126353Smlaier		return (0);
1609126353Smlaier
1610145840Smlaier	/* load limits */
1611145840Smlaier	for (i = 0; i < PF_LIMIT_MAX; i++) {
1612145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1613145840Smlaier			continue;
1614145840Smlaier		if (pfctl_load_limit(pf, i, pf->limit[i]))
1615145840Smlaier			error = 1;
1616145840Smlaier	}
1617145840Smlaier
1618171172Smlaier	/*
1619223637Sbz	 * If we've set the limit, but haven't explicitly set adaptive
1620171172Smlaier	 * timeouts, do it now with a start of 60% and end of 120%.
1621171172Smlaier	 */
1622171172Smlaier	if (pf->limit_set[PF_LIMIT_STATES] &&
1623171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_START] &&
1624171172Smlaier	    !pf->timeout_set[PFTM_ADAPTIVE_END]) {
1625171172Smlaier		pf->timeout[PFTM_ADAPTIVE_START] =
1626171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 6;
1627171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
1628171172Smlaier		pf->timeout[PFTM_ADAPTIVE_END] =
1629171172Smlaier			(pf->limit[PF_LIMIT_STATES] / 10) * 12;
1630171172Smlaier		pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
1631171172Smlaier	}
1632171172Smlaier
1633145840Smlaier	/* load timeouts */
1634145840Smlaier	for (i = 0; i < PFTM_MAX; i++) {
1635145840Smlaier		if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1636145840Smlaier			continue;
1637145840Smlaier		if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1638145840Smlaier			error = 1;
1639145840Smlaier	}
1640145840Smlaier
1641145840Smlaier	/* load debug */
1642145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1643145840Smlaier		if (pfctl_load_debug(pf, pf->debug))
1644145840Smlaier			error = 1;
1645145840Smlaier
1646145840Smlaier	/* load logif */
1647145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1648145840Smlaier		if (pfctl_load_logif(pf, pf->ifname))
1649145840Smlaier			error = 1;
1650145840Smlaier
1651145840Smlaier	/* load hostid */
1652145840Smlaier	if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1653145840Smlaier		if (pfctl_load_hostid(pf, pf->hostid))
1654145840Smlaier			error = 1;
1655145840Smlaier
1656145840Smlaier	return (error);
1657145840Smlaier}
1658145840Smlaier
1659145840Smlaierint
1660145840Smlaierpfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1661145840Smlaier{
1662145840Smlaier	int i;
1663145840Smlaier
1664145840Smlaier
1665126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1666126353Smlaier		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1667145840Smlaier			pf->limit[pf_limits[i].index] = limit;
1668145840Smlaier			pf->limit_set[pf_limits[i].index] = 1;
1669126353Smlaier			break;
1670126353Smlaier		}
1671126353Smlaier	}
1672126353Smlaier	if (pf_limits[i].name == NULL) {
1673126353Smlaier		warnx("Bad pool name.");
1674126353Smlaier		return (1);
1675126353Smlaier	}
1676126353Smlaier
1677126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1678126353Smlaier		printf("set limit %s %d\n", opt, limit);
1679126353Smlaier
1680126353Smlaier	return (0);
1681126353Smlaier}
1682126353Smlaier
1683126353Smlaierint
1684145840Smlaierpfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1685145840Smlaier{
1686145840Smlaier	struct pfioc_limit pl;
1687145840Smlaier
1688145840Smlaier	memset(&pl, 0, sizeof(pl));
1689145840Smlaier	pl.index = index;
1690145840Smlaier	pl.limit = limit;
1691145840Smlaier	if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1692145840Smlaier		if (errno == EBUSY)
1693145840Smlaier			warnx("Current pool size exceeds requested hard limit");
1694145840Smlaier		else
1695145840Smlaier			warnx("DIOCSETLIMIT");
1696145840Smlaier		return (1);
1697145840Smlaier	}
1698145840Smlaier	return (0);
1699145840Smlaier}
1700145840Smlaier
1701145840Smlaierint
1702126353Smlaierpfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1703126353Smlaier{
1704126353Smlaier	int i;
1705126353Smlaier
1706126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1707126353Smlaier		return (0);
1708126353Smlaier
1709126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1710126353Smlaier		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1711145840Smlaier			pf->timeout[pf_timeouts[i].timeout] = seconds;
1712145840Smlaier			pf->timeout_set[pf_timeouts[i].timeout] = 1;
1713126353Smlaier			break;
1714126353Smlaier		}
1715126353Smlaier	}
1716126353Smlaier
1717126353Smlaier	if (pf_timeouts[i].name == NULL) {
1718126353Smlaier		warnx("Bad timeout name.");
1719126353Smlaier		return (1);
1720126353Smlaier	}
1721126353Smlaier
1722126353Smlaier
1723126353Smlaier	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1724126353Smlaier		printf("set timeout %s %d\n", opt, seconds);
1725126353Smlaier
1726126353Smlaier	return (0);
1727126353Smlaier}
1728126353Smlaier
1729126353Smlaierint
1730145840Smlaierpfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1731145840Smlaier{
1732145840Smlaier	struct pfioc_tm pt;
1733145840Smlaier
1734145840Smlaier	memset(&pt, 0, sizeof(pt));
1735145840Smlaier	pt.timeout = timeout;
1736145840Smlaier	pt.seconds = seconds;
1737145840Smlaier	if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1738145840Smlaier		warnx("DIOCSETTIMEOUT");
1739145840Smlaier		return (1);
1740145840Smlaier	}
1741145840Smlaier	return (0);
1742145840Smlaier}
1743145840Smlaier
1744145840Smlaierint
1745126353Smlaierpfctl_set_optimization(struct pfctl *pf, const char *opt)
1746126353Smlaier{
1747126353Smlaier	const struct pf_hint *hint;
1748126353Smlaier	int i, r;
1749126353Smlaier
1750126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1751126353Smlaier		return (0);
1752126353Smlaier
1753126353Smlaier	for (i = 0; pf_hints[i].name; i++)
1754126353Smlaier		if (strcasecmp(opt, pf_hints[i].name) == 0)
1755126353Smlaier			break;
1756126353Smlaier
1757126353Smlaier	hint = pf_hints[i].hint;
1758126353Smlaier	if (hint == NULL) {
1759171172Smlaier		warnx("invalid state timeouts optimization");
1760126353Smlaier		return (1);
1761126353Smlaier	}
1762126353Smlaier
1763126353Smlaier	for (i = 0; hint[i].name; i++)
1764126353Smlaier		if ((r = pfctl_set_timeout(pf, hint[i].name,
1765126353Smlaier		    hint[i].timeout, 1)))
1766126353Smlaier			return (r);
1767126353Smlaier
1768126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1769126353Smlaier		printf("set optimization %s\n", opt);
1770126353Smlaier
1771126353Smlaier	return (0);
1772126353Smlaier}
1773126353Smlaier
1774126353Smlaierint
1775126353Smlaierpfctl_set_logif(struct pfctl *pf, char *ifname)
1776126353Smlaier{
1777126353Smlaier
1778126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1779126353Smlaier		return (0);
1780126353Smlaier
1781145840Smlaier	if (!strcmp(ifname, "none")) {
1782145840Smlaier		free(pf->ifname);
1783145840Smlaier		pf->ifname = NULL;
1784145840Smlaier	} else {
1785145840Smlaier		pf->ifname = strdup(ifname);
1786145840Smlaier		if (!pf->ifname)
1787145840Smlaier			errx(1, "pfctl_set_logif: strdup");
1788126353Smlaier	}
1789145840Smlaier	pf->ifname_set = 1;
1790126353Smlaier
1791126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1792126353Smlaier		printf("set loginterface %s\n", ifname);
1793126353Smlaier
1794126353Smlaier	return (0);
1795126353Smlaier}
1796126353Smlaier
1797126353Smlaierint
1798145840Smlaierpfctl_load_logif(struct pfctl *pf, char *ifname)
1799145840Smlaier{
1800145840Smlaier	struct pfioc_if pi;
1801145840Smlaier
1802145840Smlaier	memset(&pi, 0, sizeof(pi));
1803145840Smlaier	if (ifname && strlcpy(pi.ifname, ifname,
1804145840Smlaier	    sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1805171172Smlaier		warnx("pfctl_load_logif: strlcpy");
1806145840Smlaier		return (1);
1807145840Smlaier	}
1808145840Smlaier	if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1809145840Smlaier		warnx("DIOCSETSTATUSIF");
1810145840Smlaier		return (1);
1811145840Smlaier	}
1812145840Smlaier	return (0);
1813145840Smlaier}
1814145840Smlaier
1815145840Smlaierint
1816130617Smlaierpfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1817130617Smlaier{
1818130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1819130617Smlaier		return (0);
1820130617Smlaier
1821130617Smlaier	HTONL(hostid);
1822130617Smlaier
1823145840Smlaier	pf->hostid = hostid;
1824145840Smlaier	pf->hostid_set = 1;
1825130617Smlaier
1826130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1827130617Smlaier		printf("set hostid 0x%08x\n", ntohl(hostid));
1828130617Smlaier
1829130617Smlaier	return (0);
1830130617Smlaier}
1831130617Smlaier
1832130617Smlaierint
1833145840Smlaierpfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1834145840Smlaier{
1835145840Smlaier	if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1836145840Smlaier		warnx("DIOCSETHOSTID");
1837145840Smlaier		return (1);
1838145840Smlaier	}
1839145840Smlaier	return (0);
1840145840Smlaier}
1841145840Smlaier
1842145840Smlaierint
1843130617Smlaierpfctl_set_debug(struct pfctl *pf, char *d)
1844130617Smlaier{
1845130617Smlaier	u_int32_t	level;
1846130617Smlaier
1847130617Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1848130617Smlaier		return (0);
1849130617Smlaier
1850130617Smlaier	if (!strcmp(d, "none"))
1851145840Smlaier		pf->debug = PF_DEBUG_NONE;
1852130617Smlaier	else if (!strcmp(d, "urgent"))
1853145840Smlaier		pf->debug = PF_DEBUG_URGENT;
1854130617Smlaier	else if (!strcmp(d, "misc"))
1855145840Smlaier		pf->debug = PF_DEBUG_MISC;
1856130617Smlaier	else if (!strcmp(d, "loud"))
1857145840Smlaier		pf->debug = PF_DEBUG_NOISY;
1858130617Smlaier	else {
1859130617Smlaier		warnx("unknown debug level \"%s\"", d);
1860130617Smlaier		return (-1);
1861130617Smlaier	}
1862130617Smlaier
1863145840Smlaier	pf->debug_set = 1;
1864145840Smlaier
1865130617Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0)
1866130617Smlaier		if (ioctl(dev, DIOCSETDEBUG, &level))
1867130617Smlaier			err(1, "DIOCSETDEBUG");
1868130617Smlaier
1869130617Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1870130617Smlaier		printf("set debug %s\n", d);
1871130617Smlaier
1872130617Smlaier	return (0);
1873130617Smlaier}
1874130617Smlaier
1875130617Smlaierint
1876145840Smlaierpfctl_load_debug(struct pfctl *pf, unsigned int level)
1877145840Smlaier{
1878145840Smlaier	if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1879145840Smlaier		warnx("DIOCSETDEBUG");
1880145840Smlaier		return (1);
1881145840Smlaier	}
1882145840Smlaier	return (0);
1883145840Smlaier}
1884145840Smlaier
1885145840Smlaierint
1886145840Smlaierpfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1887145840Smlaier{
1888145840Smlaier	struct pfioc_iface	pi;
1889145840Smlaier
1890145840Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1891145840Smlaier		return (0);
1892145840Smlaier
1893145840Smlaier	bzero(&pi, sizeof(pi));
1894145840Smlaier
1895145840Smlaier	pi.pfiio_flags = flags;
1896145840Smlaier
1897145840Smlaier	if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
1898145840Smlaier	    sizeof(pi.pfiio_name))
1899145840Smlaier		errx(1, "pfctl_set_interface_flags: strlcpy");
1900145840Smlaier
1901145840Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1902145840Smlaier		if (how == 0) {
1903145840Smlaier			if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
1904145840Smlaier				err(1, "DIOCCLRIFFLAG");
1905145840Smlaier		} else {
1906145840Smlaier			if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
1907145840Smlaier				err(1, "DIOCSETIFFLAG");
1908145840Smlaier		}
1909145840Smlaier	}
1910145840Smlaier	return (0);
1911145840Smlaier}
1912145840Smlaier
1913145840Smlaiervoid
1914126353Smlaierpfctl_debug(int dev, u_int32_t level, int opts)
1915126353Smlaier{
1916126353Smlaier	if (ioctl(dev, DIOCSETDEBUG, &level))
1917126353Smlaier		err(1, "DIOCSETDEBUG");
1918126353Smlaier	if ((opts & PF_OPT_QUIET) == 0) {
1919126353Smlaier		fprintf(stderr, "debug level set to '");
1920126353Smlaier		switch (level) {
1921126353Smlaier		case PF_DEBUG_NONE:
1922126353Smlaier			fprintf(stderr, "none");
1923126353Smlaier			break;
1924126353Smlaier		case PF_DEBUG_URGENT:
1925126353Smlaier			fprintf(stderr, "urgent");
1926126353Smlaier			break;
1927126353Smlaier		case PF_DEBUG_MISC:
1928126353Smlaier			fprintf(stderr, "misc");
1929126353Smlaier			break;
1930126353Smlaier		case PF_DEBUG_NOISY:
1931126353Smlaier			fprintf(stderr, "loud");
1932126353Smlaier			break;
1933126353Smlaier		default:
1934126353Smlaier			fprintf(stderr, "<invalid>");
1935126353Smlaier			break;
1936126353Smlaier		}
1937126353Smlaier		fprintf(stderr, "'\n");
1938126353Smlaier	}
1939126353Smlaier}
1940126353Smlaier
1941126353Smlaierint
1942126353Smlaierpfctl_test_altqsupport(int dev, int opts)
1943126353Smlaier{
1944126353Smlaier	struct pfioc_altq pa;
1945126353Smlaier
1946126353Smlaier	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1947126353Smlaier		if (errno == ENODEV) {
1948126353Smlaier			if (!(opts & PF_OPT_QUIET))
1949126353Smlaier				fprintf(stderr, "No ALTQ support in kernel\n"
1950126353Smlaier				    "ALTQ related functions disabled\n");
1951126353Smlaier			return (0);
1952126353Smlaier		} else
1953126353Smlaier			err(1, "DIOCGETALTQS");
1954126353Smlaier	}
1955126353Smlaier	return (1);
1956126353Smlaier}
1957126353Smlaier
1958126353Smlaierint
1959126353Smlaierpfctl_show_anchors(int dev, int opts, char *anchorname)
1960126353Smlaier{
1961145840Smlaier	struct pfioc_ruleset	 pr;
1962145840Smlaier	u_int32_t		 mnr, nr;
1963126353Smlaier
1964145840Smlaier	memset(&pr, 0, sizeof(pr));
1965145840Smlaier	memcpy(pr.path, anchorname, sizeof(pr.path));
1966145840Smlaier	if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1967145840Smlaier		if (errno == EINVAL)
1968145840Smlaier			fprintf(stderr, "Anchor '%s' not found.\n",
1969145840Smlaier			    anchorname);
1970145840Smlaier		else
1971145840Smlaier			err(1, "DIOCGETRULESETS");
1972145840Smlaier		return (-1);
1973145840Smlaier	}
1974145840Smlaier	mnr = pr.nr;
1975145840Smlaier	for (nr = 0; nr < mnr; ++nr) {
1976145840Smlaier		char sub[MAXPATHLEN];
1977126353Smlaier
1978145840Smlaier		pr.nr = nr;
1979145840Smlaier		if (ioctl(dev, DIOCGETRULESET, &pr))
1980145840Smlaier			err(1, "DIOCGETRULESET");
1981145840Smlaier		if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
1982145840Smlaier			continue;
1983145840Smlaier		sub[0] = 0;
1984145840Smlaier		if (pr.path[0]) {
1985145840Smlaier			strlcat(sub, pr.path, sizeof(sub));
1986145840Smlaier			strlcat(sub, "/", sizeof(sub));
1987126353Smlaier		}
1988145840Smlaier		strlcat(sub, pr.name, sizeof(sub));
1989171172Smlaier		if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
1990171172Smlaier			printf("  %s\n", sub);
1991171172Smlaier		if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
1992126353Smlaier			return (-1);
1993126353Smlaier	}
1994126353Smlaier	return (0);
1995126353Smlaier}
1996126353Smlaier
1997126353Smlaierconst char *
1998126353Smlaierpfctl_lookup_option(char *cmd, const char **list)
1999126353Smlaier{
2000126353Smlaier	if (cmd != NULL && *cmd)
2001126353Smlaier		for (; *list; list++)
2002126353Smlaier			if (!strncmp(cmd, *list, strlen(cmd)))
2003126353Smlaier				return (*list);
2004126353Smlaier	return (NULL);
2005126353Smlaier}
2006126353Smlaier
2007126353Smlaierint
2008126353Smlaiermain(int argc, char *argv[])
2009126353Smlaier{
2010171172Smlaier	int	 error = 0;
2011171172Smlaier	int	 ch;
2012171172Smlaier	int	 mode = O_RDONLY;
2013171172Smlaier	int	 opts = 0;
2014223637Sbz	int	 optimize = PF_OPTIMIZE_BASIC;
2015171172Smlaier	char	 anchorname[MAXPATHLEN];
2016171172Smlaier	char	*path;
2017126353Smlaier
2018126353Smlaier	if (argc < 2)
2019126353Smlaier		usage();
2020126353Smlaier
2021130617Smlaier	while ((ch = getopt(argc, argv,
2022223637Sbz	    "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
2023126353Smlaier		switch (ch) {
2024126353Smlaier		case 'a':
2025126353Smlaier			anchoropt = optarg;
2026126353Smlaier			break;
2027126353Smlaier		case 'd':
2028126353Smlaier			opts |= PF_OPT_DISABLE;
2029126353Smlaier			mode = O_RDWR;
2030126353Smlaier			break;
2031126353Smlaier		case 'D':
2032126353Smlaier			if (pfctl_cmdline_symset(optarg) < 0)
2033126353Smlaier				warnx("could not parse macro definition %s",
2034126353Smlaier				    optarg);
2035126353Smlaier			break;
2036126353Smlaier		case 'e':
2037126353Smlaier			opts |= PF_OPT_ENABLE;
2038126353Smlaier			mode = O_RDWR;
2039126353Smlaier			break;
2040126353Smlaier		case 'q':
2041126353Smlaier			opts |= PF_OPT_QUIET;
2042126353Smlaier			break;
2043126353Smlaier		case 'F':
2044126353Smlaier			clearopt = pfctl_lookup_option(optarg, clearopt_list);
2045126353Smlaier			if (clearopt == NULL) {
2046126353Smlaier				warnx("Unknown flush modifier '%s'", optarg);
2047126353Smlaier				usage();
2048126353Smlaier			}
2049126353Smlaier			mode = O_RDWR;
2050126353Smlaier			break;
2051130617Smlaier		case 'i':
2052130617Smlaier			ifaceopt = optarg;
2053130617Smlaier			break;
2054126353Smlaier		case 'k':
2055126353Smlaier			if (state_killers >= 2) {
2056126353Smlaier				warnx("can only specify -k twice");
2057126353Smlaier				usage();
2058126353Smlaier				/* NOTREACHED */
2059126353Smlaier			}
2060126353Smlaier			state_kill[state_killers++] = optarg;
2061126353Smlaier			mode = O_RDWR;
2062126353Smlaier			break;
2063171172Smlaier		case 'K':
2064171172Smlaier			if (src_node_killers >= 2) {
2065171172Smlaier				warnx("can only specify -K twice");
2066171172Smlaier				usage();
2067171172Smlaier				/* NOTREACHED */
2068171172Smlaier			}
2069171172Smlaier			src_node_kill[src_node_killers++] = optarg;
2070171172Smlaier			mode = O_RDWR;
2071171172Smlaier			break;
2072145840Smlaier		case 'm':
2073145840Smlaier			opts |= PF_OPT_MERGE;
2074145840Smlaier			break;
2075126353Smlaier		case 'n':
2076126353Smlaier			opts |= PF_OPT_NOACTION;
2077126353Smlaier			break;
2078126353Smlaier		case 'N':
2079126353Smlaier			loadopt |= PFCTL_FLAG_NAT;
2080126353Smlaier			break;
2081126353Smlaier		case 'r':
2082126353Smlaier			opts |= PF_OPT_USEDNS;
2083126353Smlaier			break;
2084126353Smlaier		case 'f':
2085126353Smlaier			rulesopt = optarg;
2086126353Smlaier			mode = O_RDWR;
2087126353Smlaier			break;
2088126353Smlaier		case 'g':
2089126353Smlaier			opts |= PF_OPT_DEBUG;
2090126353Smlaier			break;
2091126353Smlaier		case 'A':
2092126353Smlaier			loadopt |= PFCTL_FLAG_ALTQ;
2093126353Smlaier			break;
2094126353Smlaier		case 'R':
2095126353Smlaier			loadopt |= PFCTL_FLAG_FILTER;
2096126353Smlaier			break;
2097145840Smlaier		case 'o':
2098223637Sbz			optiopt = pfctl_lookup_option(optarg, optiopt_list);
2099223637Sbz			if (optiopt == NULL) {
2100223637Sbz				warnx("Unknown optimization '%s'", optarg);
2101223637Sbz				usage();
2102171172Smlaier			}
2103171172Smlaier			opts |= PF_OPT_OPTIMIZE;
2104145840Smlaier			break;
2105126353Smlaier		case 'O':
2106126353Smlaier			loadopt |= PFCTL_FLAG_OPTION;
2107126353Smlaier			break;
2108130617Smlaier		case 'p':
2109130617Smlaier			pf_device = optarg;
2110130617Smlaier			break;
2111223057Sbz		case 'P':
2112223057Sbz			opts |= PF_OPT_NUMERIC;
2113223057Sbz			break;
2114126353Smlaier		case 's':
2115126353Smlaier			showopt = pfctl_lookup_option(optarg, showopt_list);
2116126353Smlaier			if (showopt == NULL) {
2117126353Smlaier				warnx("Unknown show modifier '%s'", optarg);
2118126353Smlaier				usage();
2119126353Smlaier			}
2120126353Smlaier			break;
2121126353Smlaier		case 't':
2122126353Smlaier			tableopt = optarg;
2123126353Smlaier			break;
2124126353Smlaier		case 'T':
2125126353Smlaier			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
2126126353Smlaier			if (tblcmdopt == NULL) {
2127126353Smlaier				warnx("Unknown table command '%s'", optarg);
2128126353Smlaier				usage();
2129126353Smlaier			}
2130126353Smlaier			break;
2131126353Smlaier		case 'v':
2132126353Smlaier			if (opts & PF_OPT_VERBOSE)
2133126353Smlaier				opts |= PF_OPT_VERBOSE2;
2134126353Smlaier			opts |= PF_OPT_VERBOSE;
2135126353Smlaier			break;
2136126353Smlaier		case 'x':
2137126353Smlaier			debugopt = pfctl_lookup_option(optarg, debugopt_list);
2138126353Smlaier			if (debugopt == NULL) {
2139126353Smlaier				warnx("Unknown debug level '%s'", optarg);
2140126353Smlaier				usage();
2141126353Smlaier			}
2142126353Smlaier			mode = O_RDWR;
2143126353Smlaier			break;
2144126353Smlaier		case 'z':
2145126353Smlaier			opts |= PF_OPT_CLRRULECTRS;
2146126353Smlaier			mode = O_RDWR;
2147126353Smlaier			break;
2148126353Smlaier		case 'h':
2149126353Smlaier			/* FALLTHROUGH */
2150126353Smlaier		default:
2151126353Smlaier			usage();
2152126353Smlaier			/* NOTREACHED */
2153126353Smlaier		}
2154126353Smlaier	}
2155126353Smlaier
2156126353Smlaier	if (tblcmdopt != NULL) {
2157126353Smlaier		argc -= optind;
2158126353Smlaier		argv += optind;
2159126353Smlaier		ch = *tblcmdopt;
2160126353Smlaier		if (ch == 'l') {
2161126353Smlaier			loadopt |= PFCTL_FLAG_TABLE;
2162126353Smlaier			tblcmdopt = NULL;
2163130617Smlaier		} else
2164171172Smlaier			mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
2165126353Smlaier	} else if (argc != optind) {
2166126353Smlaier		warnx("unknown command line argument: %s ...", argv[optind]);
2167126353Smlaier		usage();
2168126353Smlaier		/* NOTREACHED */
2169126353Smlaier	}
2170126353Smlaier	if (loadopt == 0)
2171126353Smlaier		loadopt = ~0;
2172126353Smlaier
2173171172Smlaier	if ((path = calloc(1, MAXPATHLEN)) == NULL)
2174171172Smlaier		errx(1, "pfctl: calloc");
2175126353Smlaier	memset(anchorname, 0, sizeof(anchorname));
2176126353Smlaier	if (anchoropt != NULL) {
2177171172Smlaier		int len = strlen(anchoropt);
2178171172Smlaier
2179171172Smlaier		if (anchoropt[len - 1] == '*') {
2180171172Smlaier			if (len >= 2 && anchoropt[len - 2] == '/')
2181171172Smlaier				anchoropt[len - 2] = '\0';
2182171172Smlaier			else
2183171172Smlaier				anchoropt[len - 1] = '\0';
2184171172Smlaier			opts |= PF_OPT_RECURSE;
2185171172Smlaier		}
2186145840Smlaier		if (strlcpy(anchorname, anchoropt,
2187145840Smlaier		    sizeof(anchorname)) >= sizeof(anchorname))
2188145840Smlaier			errx(1, "anchor name '%s' too long",
2189145840Smlaier			    anchoropt);
2190126353Smlaier		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
2191126353Smlaier	}
2192126353Smlaier
2193126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
2194130617Smlaier		dev = open(pf_device, mode);
2195126353Smlaier		if (dev == -1)
2196130617Smlaier			err(1, "%s", pf_device);
2197126353Smlaier		altqsupport = pfctl_test_altqsupport(dev, opts);
2198126353Smlaier	} else {
2199130617Smlaier		dev = open(pf_device, O_RDONLY);
2200130617Smlaier		if (dev >= 0)
2201130617Smlaier			opts |= PF_OPT_DUMMYACTION;
2202126353Smlaier		/* turn off options */
2203126353Smlaier		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
2204126353Smlaier		clearopt = showopt = debugopt = NULL;
2205126355Smlaier#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
2206126355Smlaier		altqsupport = 0;
2207126355Smlaier#else
2208126353Smlaier		altqsupport = 1;
2209126355Smlaier#endif
2210126353Smlaier	}
2211126353Smlaier
2212126353Smlaier	if (opts & PF_OPT_DISABLE)
2213126353Smlaier		if (pfctl_disable(dev, opts))
2214126353Smlaier			error = 1;
2215126353Smlaier
2216126353Smlaier	if (showopt != NULL) {
2217126353Smlaier		switch (*showopt) {
2218126353Smlaier		case 'A':
2219126353Smlaier			pfctl_show_anchors(dev, opts, anchorname);
2220126353Smlaier			break;
2221126353Smlaier		case 'r':
2222126353Smlaier			pfctl_load_fingerprints(dev, opts);
2223171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
2224171172Smlaier			    anchorname, 0);
2225126353Smlaier			break;
2226126353Smlaier		case 'l':
2227126353Smlaier			pfctl_load_fingerprints(dev, opts);
2228171172Smlaier			pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
2229171172Smlaier			    anchorname, 0);
2230126353Smlaier			break;
2231126353Smlaier		case 'n':
2232126353Smlaier			pfctl_load_fingerprints(dev, opts);
2233145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2234126353Smlaier			break;
2235126353Smlaier		case 'q':
2236130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts,
2237130617Smlaier			    opts & PF_OPT_VERBOSE2);
2238126353Smlaier			break;
2239126353Smlaier		case 's':
2240130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2241126353Smlaier			break;
2242130617Smlaier		case 'S':
2243130617Smlaier			pfctl_show_src_nodes(dev, opts);
2244130617Smlaier			break;
2245126353Smlaier		case 'i':
2246130617Smlaier			pfctl_show_status(dev, opts);
2247126353Smlaier			break;
2248126353Smlaier		case 't':
2249130617Smlaier			pfctl_show_timeouts(dev, opts);
2250126353Smlaier			break;
2251126353Smlaier		case 'm':
2252130617Smlaier			pfctl_show_limits(dev, opts);
2253126353Smlaier			break;
2254126353Smlaier		case 'a':
2255130617Smlaier			opts |= PF_OPT_SHOWALL;
2256126353Smlaier			pfctl_load_fingerprints(dev, opts);
2257126353Smlaier
2258145840Smlaier			pfctl_show_nat(dev, opts, anchorname);
2259171172Smlaier			pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
2260130617Smlaier			pfctl_show_altq(dev, ifaceopt, opts, 0);
2261130617Smlaier			pfctl_show_states(dev, ifaceopt, opts);
2262130617Smlaier			pfctl_show_src_nodes(dev, opts);
2263130617Smlaier			pfctl_show_status(dev, opts);
2264171172Smlaier			pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
2265130617Smlaier			pfctl_show_timeouts(dev, opts);
2266130617Smlaier			pfctl_show_limits(dev, opts);
2267145840Smlaier			pfctl_show_tables(anchorname, opts);
2268126353Smlaier			pfctl_show_fingerprints(opts);
2269126353Smlaier			break;
2270126353Smlaier		case 'T':
2271145840Smlaier			pfctl_show_tables(anchorname, opts);
2272126353Smlaier			break;
2273126353Smlaier		case 'o':
2274126353Smlaier			pfctl_load_fingerprints(dev, opts);
2275126353Smlaier			pfctl_show_fingerprints(opts);
2276126353Smlaier			break;
2277130617Smlaier		case 'I':
2278130617Smlaier			pfctl_show_ifaces(ifaceopt, opts);
2279130617Smlaier			break;
2280126353Smlaier		}
2281126353Smlaier	}
2282126353Smlaier
2283171172Smlaier	if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
2284171172Smlaier		pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
2285171172Smlaier		    anchorname, 0);
2286171172Smlaier
2287126353Smlaier	if (clearopt != NULL) {
2288171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2289171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2290171172Smlaier			    "be modified from the command line");
2291171172Smlaier
2292126353Smlaier		switch (*clearopt) {
2293126353Smlaier		case 'r':
2294145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2295126353Smlaier			break;
2296126353Smlaier		case 'n':
2297145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2298126353Smlaier			break;
2299126353Smlaier		case 'q':
2300126353Smlaier			pfctl_clear_altq(dev, opts);
2301126353Smlaier			break;
2302126353Smlaier		case 's':
2303130617Smlaier			pfctl_clear_states(dev, ifaceopt, opts);
2304126353Smlaier			break;
2305130617Smlaier		case 'S':
2306130617Smlaier			pfctl_clear_src_nodes(dev, opts);
2307130617Smlaier			break;
2308126353Smlaier		case 'i':
2309126353Smlaier			pfctl_clear_stats(dev, opts);
2310126353Smlaier			break;
2311126353Smlaier		case 'a':
2312145840Smlaier			pfctl_clear_rules(dev, opts, anchorname);
2313145840Smlaier			pfctl_clear_nat(dev, opts, anchorname);
2314145840Smlaier			pfctl_clear_tables(anchorname, opts);
2315145840Smlaier			if (!*anchorname) {
2316130617Smlaier				pfctl_clear_altq(dev, opts);
2317130617Smlaier				pfctl_clear_states(dev, ifaceopt, opts);
2318130617Smlaier				pfctl_clear_src_nodes(dev, opts);
2319130617Smlaier				pfctl_clear_stats(dev, opts);
2320130617Smlaier				pfctl_clear_fingerprints(dev, opts);
2321145840Smlaier				pfctl_clear_interface_flags(dev, opts);
2322130617Smlaier			}
2323126353Smlaier			break;
2324126353Smlaier		case 'o':
2325126353Smlaier			pfctl_clear_fingerprints(dev, opts);
2326126353Smlaier			break;
2327126353Smlaier		case 'T':
2328145840Smlaier			pfctl_clear_tables(anchorname, opts);
2329126353Smlaier			break;
2330126353Smlaier		}
2331126353Smlaier	}
2332223637Sbz	if (state_killers) {
2333223637Sbz		if (!strcmp(state_kill[0], "label"))
2334223637Sbz			pfctl_label_kill_states(dev, ifaceopt, opts);
2335223637Sbz		else if (!strcmp(state_kill[0], "id"))
2336223637Sbz			pfctl_id_kill_states(dev, ifaceopt, opts);
2337223637Sbz		else
2338223637Sbz			pfctl_net_kill_states(dev, ifaceopt, opts);
2339223637Sbz	}
2340126353Smlaier
2341171172Smlaier	if (src_node_killers)
2342171172Smlaier		pfctl_kill_src_nodes(dev, ifaceopt, opts);
2343171172Smlaier
2344126353Smlaier	if (tblcmdopt != NULL) {
2345126353Smlaier		error = pfctl_command_tables(argc, argv, tableopt,
2346145840Smlaier		    tblcmdopt, rulesopt, anchorname, opts);
2347126353Smlaier		rulesopt = NULL;
2348126353Smlaier	}
2349171172Smlaier	if (optiopt != NULL) {
2350171172Smlaier		switch (*optiopt) {
2351171172Smlaier		case 'n':
2352171172Smlaier			optimize = 0;
2353171172Smlaier			break;
2354171172Smlaier		case 'b':
2355171172Smlaier			optimize |= PF_OPTIMIZE_BASIC;
2356171172Smlaier			break;
2357171172Smlaier		case 'o':
2358171172Smlaier		case 'p':
2359171172Smlaier			optimize |= PF_OPTIMIZE_PROFILE;
2360171172Smlaier			break;
2361171172Smlaier		}
2362171172Smlaier	}
2363126353Smlaier
2364171172Smlaier	if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
2365171172Smlaier	    !anchorname[0])
2366145840Smlaier		if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
2367145840Smlaier			error = 1;
2368145840Smlaier
2369145840Smlaier	if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
2370145840Smlaier	    !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
2371126353Smlaier		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
2372126353Smlaier			error = 1;
2373126353Smlaier
2374126353Smlaier	if (rulesopt != NULL) {
2375171172Smlaier		if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2376171172Smlaier			errx(1, "anchor names beginning with '_' cannot "
2377171172Smlaier			    "be modified from the command line");
2378223637Sbz		if (pfctl_rules(dev, rulesopt, opts, optimize,
2379171172Smlaier		    anchorname, NULL))
2380126353Smlaier			error = 1;
2381126353Smlaier		else if (!(opts & PF_OPT_NOACTION) &&
2382126353Smlaier		    (loadopt & PFCTL_FLAG_TABLE))
2383126353Smlaier			warn_namespace_collision(NULL);
2384126353Smlaier	}
2385126353Smlaier
2386126353Smlaier	if (opts & PF_OPT_ENABLE)
2387126353Smlaier		if (pfctl_enable(dev, opts))
2388126353Smlaier			error = 1;
2389126353Smlaier
2390126353Smlaier	if (debugopt != NULL) {
2391126353Smlaier		switch (*debugopt) {
2392126353Smlaier		case 'n':
2393126353Smlaier			pfctl_debug(dev, PF_DEBUG_NONE, opts);
2394126353Smlaier			break;
2395126353Smlaier		case 'u':
2396126353Smlaier			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
2397126353Smlaier			break;
2398126353Smlaier		case 'm':
2399126353Smlaier			pfctl_debug(dev, PF_DEBUG_MISC, opts);
2400126353Smlaier			break;
2401126353Smlaier		case 'l':
2402126353Smlaier			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
2403126353Smlaier			break;
2404126353Smlaier		}
2405126353Smlaier	}
2406126353Smlaier
2407126353Smlaier	exit(error);
2408126353Smlaier}
2409