pfctl.c revision 127082
1126353Smlaier/*	$OpenBSD: pfctl.c,v 1.188 2003/08/29 21:47:36 cedric Exp $ */
2126353Smlaier
3126353Smlaier/*
4126353Smlaier * Copyright (c) 2001 Daniel Hartmeier
5126353Smlaier * All rights reserved.
6126353Smlaier *
7126353Smlaier * Redistribution and use in source and binary forms, with or without
8126353Smlaier * modification, are permitted provided that the following conditions
9126353Smlaier * are met:
10126353Smlaier *
11126353Smlaier *    - Redistributions of source code must retain the above copyright
12126353Smlaier *      notice, this list of conditions and the following disclaimer.
13126353Smlaier *    - Redistributions in binary form must reproduce the above
14126353Smlaier *      copyright notice, this list of conditions and the following
15126353Smlaier *      disclaimer in the documentation and/or other materials provided
16126353Smlaier *      with the distribution.
17126353Smlaier *
18126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19126353Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20126353Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21126353Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22126353Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23126353Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24126353Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25126353Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26126353Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28126353Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29126353Smlaier * POSSIBILITY OF SUCH DAMAGE.
30126353Smlaier *
31126353Smlaier */
32126353Smlaier
33127082Sobrien#include <sys/cdefs.h>
34127082Sobrien__FBSDID("$FreeBSD: head/contrib/pf/pfctl/pfctl.c 127082 2004-03-16 17:24:06Z obrien $");
35127082Sobrien
36126353Smlaier#include <sys/types.h>
37126353Smlaier#include <sys/ioctl.h>
38126353Smlaier#include <sys/socket.h>
39126353Smlaier
40126353Smlaier#include <net/if.h>
41126353Smlaier#include <netinet/in.h>
42126353Smlaier#include <net/pfvar.h>
43126353Smlaier#include <arpa/inet.h>
44126353Smlaier#include <altq/altq.h>
45126353Smlaier
46126353Smlaier#include <err.h>
47126353Smlaier#include <errno.h>
48126353Smlaier#include <fcntl.h>
49126353Smlaier#include <limits.h>
50126353Smlaier#include <netdb.h>
51126353Smlaier#include <stdio.h>
52126353Smlaier#include <stdlib.h>
53126353Smlaier#include <string.h>
54126353Smlaier#include <unistd.h>
55126353Smlaier
56126353Smlaier#include "pfctl_parser.h"
57126353Smlaier#include "pfctl.h"
58126353Smlaier
59126353Smlaiervoid	 usage(void);
60126353Smlaierint	 pfctl_enable(int, int);
61126353Smlaierint	 pfctl_disable(int, int);
62126353Smlaierint	 pfctl_clear_stats(int, int);
63126353Smlaierint	 pfctl_clear_rules(int, int, char *, char *);
64126353Smlaierint	 pfctl_clear_nat(int, int, char *, char *);
65126353Smlaierint	 pfctl_clear_altq(int, int);
66126353Smlaierint	 pfctl_clear_states(int, int);
67126353Smlaierint	 pfctl_kill_states(int, int);
68126353Smlaierint	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
69126353Smlaier	     char *, char *);
70126353Smlaiervoid	 pfctl_print_rule_counters(struct pf_rule *, int);
71126353Smlaierint	 pfctl_show_rules(int, int, int, char *, char *);
72126353Smlaierint	 pfctl_show_nat(int, int, char *, char *);
73126353Smlaierint	 pfctl_show_states(int, u_int8_t, int);
74126353Smlaierint	 pfctl_show_status(int);
75126353Smlaierint	 pfctl_show_timeouts(int);
76126353Smlaierint	 pfctl_show_limits(int);
77126353Smlaierint	 pfctl_debug(int, u_int32_t, int);
78126353Smlaierint	 pfctl_clear_rule_counters(int, int);
79126353Smlaierint	 pfctl_test_altqsupport(int, int);
80126353Smlaierint	 pfctl_show_anchors(int, int, char *);
81126353Smlaierconst char	*pfctl_lookup_option(char *, const char **);
82126353Smlaier
83126353Smlaierconst char	*clearopt;
84126353Smlaierchar		*rulesopt;
85126353Smlaierconst char	*showopt;
86126353Smlaierconst char	*debugopt;
87126353Smlaierchar		*anchoropt;
88126353Smlaierchar		*tableopt;
89126353Smlaierconst char	*tblcmdopt;
90126353Smlaierint		 state_killers;
91126353Smlaierchar		*state_kill[2];
92126353Smlaierint		 loadopt;
93126353Smlaierint		 altqsupport;
94126353Smlaier
95126353Smlaierint		 dev = -1;
96126353Smlaier
97126353Smlaierconst char	*infile;
98126353Smlaier
99126353Smlaierstatic const struct {
100126353Smlaier	const char	*name;
101126353Smlaier	int		index;
102126353Smlaier} pf_limits[] = {
103126353Smlaier	{ "states",	PF_LIMIT_STATES },
104126353Smlaier	{ "frags",	PF_LIMIT_FRAGS },
105126353Smlaier	{ NULL,		0 }
106126353Smlaier};
107126353Smlaier
108126353Smlaierstruct pf_hint {
109126353Smlaier	const char	*name;
110126353Smlaier	int		timeout;
111126353Smlaier};
112126353Smlaierstatic const struct pf_hint pf_hint_normal[] = {
113126353Smlaier	{ "tcp.first",		2 * 60 },
114126353Smlaier	{ "tcp.opening",	30 },
115126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
116126353Smlaier	{ "tcp.closing",	15 * 60 },
117126353Smlaier	{ "tcp.finwait",	45 },
118126353Smlaier	{ "tcp.closed",		90 },
119126353Smlaier	{ NULL,			0 }
120126353Smlaier};
121126353Smlaierstatic const struct pf_hint pf_hint_satellite[] = {
122126353Smlaier	{ "tcp.first",		3 * 60 },
123126353Smlaier	{ "tcp.opening",	30 + 5 },
124126353Smlaier	{ "tcp.established",	24 * 60 * 60 },
125126353Smlaier	{ "tcp.closing",	15 * 60 + 5 },
126126353Smlaier	{ "tcp.finwait",	45 + 5 },
127126353Smlaier	{ "tcp.closed",		90 + 5 },
128126353Smlaier	{ NULL,			0 }
129126353Smlaier};
130126353Smlaierstatic const struct pf_hint pf_hint_conservative[] = {
131126353Smlaier	{ "tcp.first",		60 * 60 },
132126353Smlaier	{ "tcp.opening",	15 * 60 },
133126353Smlaier	{ "tcp.established",	5 * 24 * 60 * 60 },
134126353Smlaier	{ "tcp.closing",	60 * 60 },
135126353Smlaier	{ "tcp.finwait",	10 * 60 },
136126353Smlaier	{ "tcp.closed",		3 * 60 },
137126353Smlaier	{ NULL,			0 }
138126353Smlaier};
139126353Smlaierstatic const struct pf_hint pf_hint_aggressive[] = {
140126353Smlaier	{ "tcp.first",		30 },
141126353Smlaier	{ "tcp.opening",	5 },
142126353Smlaier	{ "tcp.established",	5 * 60 * 60 },
143126353Smlaier	{ "tcp.closing",	60 },
144126353Smlaier	{ "tcp.finwait",	30 },
145126353Smlaier	{ "tcp.closed",		30 },
146126353Smlaier	{ NULL,			0 }
147126353Smlaier};
148126353Smlaier
149126353Smlaierstatic const struct {
150126353Smlaier	const char *name;
151126353Smlaier	const struct pf_hint *hint;
152126353Smlaier} pf_hints[] = {
153126353Smlaier	{ "normal",		pf_hint_normal },
154126353Smlaier	{ "satellite",		pf_hint_satellite },
155126353Smlaier	{ "high-latency",	pf_hint_satellite },
156126353Smlaier	{ "conservative",	pf_hint_conservative },
157126353Smlaier	{ "aggressive",		pf_hint_aggressive },
158126353Smlaier	{ NULL,			NULL }
159126353Smlaier};
160126353Smlaier
161126353Smlaierstatic const char *clearopt_list[] = {
162126353Smlaier	"nat", "queue", "rules", "state", "info", "Tables", "osfp", "all", NULL
163126353Smlaier};
164126353Smlaier
165126353Smlaierstatic const char *showopt_list[] = {
166126353Smlaier	"nat", "queue", "rules", "Anchors", "state", "info", "labels",
167126353Smlaier	"timeouts", "memory", "Tables", "osfp", "all", NULL
168126353Smlaier};
169126353Smlaier
170126353Smlaierstatic const char *tblcmdopt_list[] = {
171126353Smlaier	"kill", "flush", "add", "delete", "load", "replace", "show",
172126353Smlaier	"test", "zero", NULL
173126353Smlaier};
174126353Smlaier
175126353Smlaierstatic const char *debugopt_list[] = {
176126353Smlaier	"none", "urgent", "misc", "loud", NULL
177126353Smlaier};
178126353Smlaier
179126353Smlaier
180126353Smlaiervoid
181126353Smlaierusage(void)
182126353Smlaier{
183126353Smlaier	extern char *__progname;
184126353Smlaier
185126353Smlaier	fprintf(stderr, "usage: %s [-AdeghnNqrROvz] ", __progname);
186126353Smlaier	fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n");
187126353Smlaier	fprintf(stderr, "             ");
188126353Smlaier	fprintf(stderr, "[-f file] [-F modifier] [-k host] [-s modifier]\n");
189126353Smlaier	fprintf(stderr, "             ");
190126353Smlaier	fprintf(stderr, "[-t table] [-T command [address ...]] [-x level]\n");
191126353Smlaier	exit(1);
192126353Smlaier}
193126353Smlaier
194126353Smlaierint
195126353Smlaierpfctl_enable(int dev, int opts)
196126353Smlaier{
197126353Smlaier	if (ioctl(dev, DIOCSTART)) {
198126353Smlaier		if (errno == EEXIST)
199126353Smlaier			errx(1, "pf already enabled");
200127024Smlaier#ifdef __FreeBSD__
201126355Smlaier		else if (errno == ESRCH)
202126355Smlaier			errx(1, "pfil registeration failed");
203126355Smlaier#endif
204126353Smlaier		else
205126353Smlaier			err(1, "DIOCSTART");
206126353Smlaier	}
207126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
208126353Smlaier		fprintf(stderr, "pf enabled\n");
209126353Smlaier
210126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
211126353Smlaier		if (errno != EEXIST)
212126353Smlaier			err(1, "DIOCSTARTALTQ");
213126353Smlaier
214126353Smlaier	return (0);
215126353Smlaier}
216126353Smlaier
217126353Smlaierint
218126353Smlaierpfctl_disable(int dev, int opts)
219126353Smlaier{
220126353Smlaier	if (ioctl(dev, DIOCSTOP)) {
221126353Smlaier		if (errno == ENOENT)
222126353Smlaier			errx(1, "pf not enabled");
223126353Smlaier		else
224126353Smlaier			err(1, "DIOCSTOP");
225126353Smlaier	}
226126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
227126353Smlaier		fprintf(stderr, "pf disabled\n");
228126353Smlaier
229126353Smlaier	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
230126353Smlaier			if (errno != ENOENT)
231126353Smlaier				err(1, "DIOCSTOPALTQ");
232126353Smlaier
233126353Smlaier	return (0);
234126353Smlaier}
235126353Smlaier
236126353Smlaierint
237126353Smlaierpfctl_clear_stats(int dev, int opts)
238126353Smlaier{
239126353Smlaier	if (ioctl(dev, DIOCCLRSTATUS))
240126353Smlaier		err(1, "DIOCCLRSTATUS");
241126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
242126353Smlaier		fprintf(stderr, "pf: statistics cleared\n");
243126353Smlaier	return (0);
244126353Smlaier}
245126353Smlaier
246126353Smlaierint
247126353Smlaierpfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
248126353Smlaier{
249126353Smlaier	struct pfioc_rule pr;
250126353Smlaier
251126353Smlaier	if (*anchorname && !*rulesetname) {
252126353Smlaier		struct pfioc_ruleset pr;
253126353Smlaier		int mnr, nr, r;
254126353Smlaier
255126353Smlaier		memset(&pr, 0, sizeof(pr));
256126353Smlaier		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
257126353Smlaier		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
258126353Smlaier			if (errno == EINVAL)
259126353Smlaier				fprintf(stderr, "No rulesets in anchor '%s'.\n",
260126353Smlaier				    anchorname);
261126353Smlaier			else
262126353Smlaier				err(1, "DIOCGETRULESETS");
263126353Smlaier			return (-1);
264126353Smlaier		}
265126353Smlaier		mnr = pr.nr;
266126353Smlaier		for (nr = mnr - 1; nr >= 0; --nr) {
267126353Smlaier			pr.nr = nr;
268126353Smlaier			if (ioctl(dev, DIOCGETRULESET, &pr))
269126353Smlaier				err(1, "DIOCGETRULESET");
270126353Smlaier			r = pfctl_clear_rules(dev, opts | PF_OPT_QUIET,
271126353Smlaier			    anchorname, pr.name);
272126353Smlaier			if (r)
273126353Smlaier				return (r);
274126353Smlaier		}
275126353Smlaier		if ((opts & PF_OPT_QUIET) == 0)
276126353Smlaier			fprintf(stderr, "rules cleared\n");
277126353Smlaier		return (0);
278126353Smlaier	}
279126353Smlaier	memset(&pr, 0, sizeof(pr));
280126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
281126353Smlaier	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
282126353Smlaier	pr.rule.action = PF_SCRUB;
283126353Smlaier	if (ioctl(dev, DIOCBEGINRULES, &pr))
284126353Smlaier		err(1, "DIOCBEGINRULES");
285126353Smlaier	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
286126353Smlaier		err(1, "DIOCCOMMITRULES");
287126353Smlaier	pr.rule.action = PF_PASS;
288126353Smlaier	if (ioctl(dev, DIOCBEGINRULES, &pr))
289126353Smlaier		err(1, "DIOCBEGINRULES");
290126353Smlaier	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
291126353Smlaier		err(1, "DIOCCOMMITRULES");
292126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
293126353Smlaier		fprintf(stderr, "rules cleared\n");
294126353Smlaier	return (0);
295126353Smlaier}
296126353Smlaier
297126353Smlaierint
298126353Smlaierpfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
299126353Smlaier{
300126353Smlaier	struct pfioc_rule pr;
301126353Smlaier
302126353Smlaier	if (*anchorname && !*rulesetname) {
303126353Smlaier		struct pfioc_ruleset pr;
304126353Smlaier		int mnr, nr, r;
305126353Smlaier
306126353Smlaier		memset(&pr, 0, sizeof(pr));
307126353Smlaier		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
308126353Smlaier		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
309126353Smlaier			if (errno == EINVAL)
310126353Smlaier				fprintf(stderr, "No rulesets in anchor '%s'.\n",
311126353Smlaier				    anchorname);
312126353Smlaier			else
313126353Smlaier				err(1, "DIOCGETRULESETS");
314126353Smlaier			return (-1);
315126353Smlaier		}
316126353Smlaier		mnr = pr.nr;
317126353Smlaier		for (nr = mnr - 1; nr >= 0; --nr) {
318126353Smlaier			pr.nr = nr;
319126353Smlaier			if (ioctl(dev, DIOCGETRULESET, &pr))
320126353Smlaier				err(1, "DIOCGETRULESET");
321126353Smlaier			r = pfctl_clear_nat(dev, opts | PF_OPT_QUIET,
322126353Smlaier			    anchorname, pr.name);
323126353Smlaier			if (r)
324126353Smlaier				return (r);
325126353Smlaier		}
326126353Smlaier		if ((opts & PF_OPT_QUIET) == 0)
327126353Smlaier			fprintf(stderr, "nat cleared\n");
328126353Smlaier		return (0);
329126353Smlaier	}
330126353Smlaier	memset(&pr, 0, sizeof(pr));
331126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
332126353Smlaier	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
333126353Smlaier	pr.rule.action = PF_NAT;
334126353Smlaier	if (ioctl(dev, DIOCBEGINRULES, &pr))
335126353Smlaier		err(1, "DIOCBEGINRULES");
336126353Smlaier	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
337126353Smlaier		err(1, "DIOCCOMMITRULES");
338126353Smlaier	pr.rule.action = PF_BINAT;
339126353Smlaier	if (ioctl(dev, DIOCBEGINRULES, &pr))
340126353Smlaier		err(1, "DIOCBEGINRULES");
341126353Smlaier	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
342126353Smlaier		err(1, "DIOCCOMMITRULES");
343126353Smlaier	pr.rule.action = PF_RDR;
344126353Smlaier	if (ioctl(dev, DIOCBEGINRULES, &pr))
345126353Smlaier		err(1, "DIOCBEGINRULES");
346126353Smlaier	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
347126353Smlaier		err(1, "DIOCCOMMITRULES");
348126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
349126353Smlaier		fprintf(stderr, "nat cleared\n");
350126353Smlaier	return (0);
351126353Smlaier}
352126353Smlaier
353126353Smlaierint
354126353Smlaierpfctl_clear_altq(int dev, int opts)
355126353Smlaier{
356126353Smlaier	struct pfioc_altq pa;
357126353Smlaier
358126353Smlaier	if (!altqsupport)
359126353Smlaier		return (-1);
360126353Smlaier	memset(&pa, 0, sizeof(pa));
361126353Smlaier	if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket))
362126353Smlaier		err(1, "DIOCBEGINALTQS");
363126353Smlaier	else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
364126353Smlaier		err(1, "DIOCCOMMITALTQS");
365126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
366126353Smlaier		fprintf(stderr, "altq cleared\n");
367126353Smlaier	return (0);
368126353Smlaier}
369126353Smlaier
370126353Smlaierint
371126353Smlaierpfctl_clear_states(int dev, int opts)
372126353Smlaier{
373126353Smlaier	if (ioctl(dev, DIOCCLRSTATES))
374126353Smlaier		err(1, "DIOCCLRSTATES");
375126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
376126353Smlaier		fprintf(stderr, "states cleared\n");
377126353Smlaier	return (0);
378126353Smlaier}
379126353Smlaier
380126353Smlaierint
381126353Smlaierpfctl_kill_states(int dev, int opts)
382126353Smlaier{
383126353Smlaier	struct pfioc_state_kill psk;
384126353Smlaier	struct addrinfo *res[2], *resp[2];
385126353Smlaier	struct sockaddr last_src, last_dst;
386126353Smlaier	int killed, sources, dests;
387126353Smlaier	int ret_ga;
388126353Smlaier
389126353Smlaier	killed = sources = dests = 0;
390126353Smlaier
391126353Smlaier	memset(&psk, 0, sizeof(psk));
392126353Smlaier	memset(&psk.psk_src.addr.v.a.mask, 0xff,
393126353Smlaier	    sizeof(psk.psk_src.addr.v.a.mask));
394126353Smlaier	memset(&last_src, 0xff, sizeof(last_src));
395126353Smlaier	memset(&last_dst, 0xff, sizeof(last_dst));
396126353Smlaier
397126353Smlaier	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
398126353Smlaier		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
399126353Smlaier		/* NOTREACHED */
400126353Smlaier	}
401126353Smlaier	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
402126353Smlaier		if (resp[0]->ai_addr == NULL)
403126353Smlaier			continue;
404126353Smlaier		/* We get lots of duplicates.  Catch the easy ones */
405126353Smlaier		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
406126353Smlaier			continue;
407126353Smlaier		last_src = *(struct sockaddr *)resp[0]->ai_addr;
408126353Smlaier
409126353Smlaier		psk.psk_af = resp[0]->ai_family;
410126353Smlaier		sources++;
411126353Smlaier
412126353Smlaier		if (psk.psk_af == AF_INET)
413126353Smlaier			psk.psk_src.addr.v.a.addr.v4 =
414126353Smlaier			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
415126353Smlaier		else if (psk.psk_af == AF_INET6)
416126353Smlaier			psk.psk_src.addr.v.a.addr.v6 =
417126353Smlaier			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
418126353Smlaier			    sin6_addr;
419126353Smlaier		else
420126353Smlaier			errx(1, "Unknown address family %d", psk.psk_af);
421126353Smlaier
422126353Smlaier		if (state_killers > 1) {
423126353Smlaier			dests = 0;
424126353Smlaier			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
425126353Smlaier			    sizeof(psk.psk_dst.addr.v.a.mask));
426126353Smlaier			memset(&last_dst, 0xff, sizeof(last_dst));
427126353Smlaier			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
428126353Smlaier			    &res[1]))) {
429126353Smlaier				errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
430126353Smlaier				/* NOTREACHED */
431126353Smlaier			}
432126353Smlaier			for (resp[1] = res[1]; resp[1];
433126353Smlaier			    resp[1] = resp[1]->ai_next) {
434126353Smlaier				if (resp[1]->ai_addr == NULL)
435126353Smlaier					continue;
436126353Smlaier				if (psk.psk_af != resp[1]->ai_family)
437126353Smlaier					continue;
438126353Smlaier
439126353Smlaier				if (memcmp(&last_dst, resp[1]->ai_addr,
440126353Smlaier				    sizeof(last_dst)) == 0)
441126353Smlaier					continue;
442126353Smlaier				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
443126353Smlaier
444126353Smlaier				dests++;
445126353Smlaier
446126353Smlaier				if (psk.psk_af == AF_INET)
447126353Smlaier					psk.psk_dst.addr.v.a.addr.v4 =
448126353Smlaier					    ((struct sockaddr_in *)resp[1]->
449126353Smlaier					    ai_addr)->sin_addr;
450126353Smlaier				else if (psk.psk_af == AF_INET6)
451126353Smlaier					psk.psk_dst.addr.v.a.addr.v6 =
452126353Smlaier					    ((struct sockaddr_in6 *)resp[1]->
453126353Smlaier					    ai_addr)->sin6_addr;
454126353Smlaier				else
455126353Smlaier					errx(1, "Unknown address family %d",
456126353Smlaier					    psk.psk_af);
457126353Smlaier
458126353Smlaier				if (ioctl(dev, DIOCKILLSTATES, &psk))
459126353Smlaier					err(1, "DIOCKILLSTATES");
460126353Smlaier				killed += psk.psk_af;
461126353Smlaier				/* fixup psk.psk_af */
462126353Smlaier				psk.psk_af = resp[1]->ai_family;
463126353Smlaier			}
464126353Smlaier			freeaddrinfo(res[1]);
465126353Smlaier		} else {
466126353Smlaier			if (ioctl(dev, DIOCKILLSTATES, &psk))
467126353Smlaier				err(1, "DIOCKILLSTATES");
468126353Smlaier			killed += psk.psk_af;
469126353Smlaier			/* fixup psk.psk_af */
470126353Smlaier			psk.psk_af = res[0]->ai_family;
471126353Smlaier		}
472126353Smlaier	}
473126353Smlaier
474126353Smlaier	freeaddrinfo(res[0]);
475126353Smlaier
476126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
477126353Smlaier		fprintf(stderr, "killed %d states from %d sources and %d "
478126353Smlaier		    "destinations\n", killed, sources, dests);
479126353Smlaier	return (0);
480126353Smlaier}
481126353Smlaier
482126353Smlaierint
483126353Smlaierpfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
484126353Smlaier    u_int32_t ticket, int r_action, char *anchorname, char *rulesetname)
485126353Smlaier{
486126353Smlaier	struct pfioc_pooladdr pp;
487126353Smlaier	struct pf_pooladdr *pa;
488126353Smlaier	u_int32_t pnr, mpnr;
489126353Smlaier
490126353Smlaier	memset(&pp, 0, sizeof(pp));
491126353Smlaier	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
492126353Smlaier	memcpy(pp.ruleset, rulesetname, sizeof(pp.ruleset));
493126353Smlaier	pp.r_action = r_action;
494126353Smlaier	pp.r_num = nr;
495126353Smlaier	pp.ticket = ticket;
496126353Smlaier	if (ioctl(dev, DIOCGETADDRS, &pp)) {
497126353Smlaier		warn("DIOCGETADDRS");
498126353Smlaier		return (-1);
499126353Smlaier	}
500126353Smlaier	mpnr = pp.nr;
501126353Smlaier	TAILQ_INIT(&pool->list);
502126353Smlaier	for (pnr = 0; pnr < mpnr; ++pnr) {
503126353Smlaier		pp.nr = pnr;
504126353Smlaier		if (ioctl(dev, DIOCGETADDR, &pp)) {
505126353Smlaier			warn("DIOCGETADDR");
506126353Smlaier			return (-1);
507126353Smlaier		}
508126353Smlaier		pa = calloc(1, sizeof(struct pf_pooladdr));
509126353Smlaier		if (pa == NULL)
510126353Smlaier			err(1, "calloc");
511126353Smlaier		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
512126353Smlaier		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
513126353Smlaier	}
514126353Smlaier
515126353Smlaier	return (0);
516126353Smlaier}
517126353Smlaier
518126353Smlaiervoid
519126353Smlaierpfctl_clear_pool(struct pf_pool *pool)
520126353Smlaier{
521126353Smlaier	struct pf_pooladdr *pa;
522126353Smlaier
523126353Smlaier	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
524126353Smlaier		TAILQ_REMOVE(&pool->list, pa, entries);
525126353Smlaier		free(pa);
526126353Smlaier	}
527126353Smlaier}
528126353Smlaier
529126353Smlaiervoid
530126353Smlaierpfctl_print_rule_counters(struct pf_rule *rule, int opts)
531126353Smlaier{
532126353Smlaier	if (opts & PF_OPT_DEBUG) {
533126353Smlaier		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
534126353Smlaier		    "p", "sa", "sp", "da", "dp" };
535126353Smlaier		int i;
536126353Smlaier
537126353Smlaier		printf("  [ Skip steps: ");
538126353Smlaier		for (i = 0; i < PF_SKIP_COUNT; ++i) {
539126353Smlaier			if (rule->skip[i].nr == rule->nr + 1)
540126353Smlaier				continue;
541126353Smlaier			printf("%s=", t[i]);
542126353Smlaier			if (rule->skip[i].nr == -1)
543126353Smlaier				printf("end ");
544126353Smlaier			else
545126353Smlaier				printf("%u ", rule->skip[i].nr);
546126353Smlaier		}
547126353Smlaier		printf("]\n");
548126353Smlaier
549126353Smlaier		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
550126353Smlaier		    rule->qname, rule->qid, rule->pqname, rule->pqid);
551126353Smlaier	}
552126353Smlaier	if (opts & PF_OPT_VERBOSE)
553127024Smlaier		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
554127024Smlaier			    "Bytes: %-10llu  States: %-6u]\n",
555127024Smlaier			    (unsigned long long)rule->evaluations,
556127024Smlaier			    (unsigned long long)rule->packets,
557127024Smlaier			    (unsigned long long)rule->bytes, rule->states);
558126353Smlaier}
559126353Smlaier
560126353Smlaierint
561126353Smlaierpfctl_show_rules(int dev, int opts, int format, char *anchorname,
562126353Smlaier    char *rulesetname)
563126353Smlaier{
564126353Smlaier	struct pfioc_rule pr;
565126353Smlaier	u_int32_t nr, mnr;
566126353Smlaier	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
567126353Smlaier
568126353Smlaier	if (*anchorname && !*rulesetname) {
569126353Smlaier		struct pfioc_ruleset pr;
570126353Smlaier		int r;
571126353Smlaier
572126353Smlaier		memset(&pr, 0, sizeof(pr));
573126353Smlaier		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
574126353Smlaier		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
575126353Smlaier			if (errno == EINVAL)
576126353Smlaier				fprintf(stderr, "No rulesets in anchor '%s'.\n",
577126353Smlaier				    anchorname);
578126353Smlaier			else
579126353Smlaier				err(1, "DIOCGETRULESETS");
580126353Smlaier			return (-1);
581126353Smlaier		}
582126353Smlaier		mnr = pr.nr;
583126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
584126353Smlaier			pr.nr = nr;
585126353Smlaier			if (ioctl(dev, DIOCGETRULESET, &pr))
586126353Smlaier				err(1, "DIOCGETRULESET");
587126353Smlaier			r = pfctl_show_rules(dev, opts, format, anchorname,
588126353Smlaier			    pr.name);
589126353Smlaier			if (r)
590126353Smlaier				return (r);
591126353Smlaier		}
592126353Smlaier		return (0);
593126353Smlaier	}
594126353Smlaier
595126353Smlaier	memset(&pr, 0, sizeof(pr));
596126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
597126353Smlaier	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
598126353Smlaier	pr.rule.action = PF_SCRUB;
599126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
600126353Smlaier		warn("DIOCGETRULES");
601126353Smlaier		return (-1);
602126353Smlaier	}
603126353Smlaier	mnr = pr.nr;
604126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
605126353Smlaier		pr.nr = nr;
606126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
607126353Smlaier			warn("DIOCGETRULE");
608126353Smlaier			return (-1);
609126353Smlaier		}
610126353Smlaier
611126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
612126353Smlaier		    nr, pr.ticket, PF_SCRUB, anchorname, rulesetname) != 0)
613126353Smlaier			return (-1);
614126353Smlaier
615126353Smlaier		switch (format) {
616126353Smlaier		case 1:
617126353Smlaier			if (pr.rule.label[0]) {
618126353Smlaier				printf("%s ", pr.rule.label);
619127024Smlaier				printf("%llu %llu %llu\n",
620127024Smlaier				    (unsigned long long)pr.rule.evaluations,
621127024Smlaier				    (unsigned long long)pr.rule.packets,
622127024Smlaier				    (unsigned long long)pr.rule.bytes);
623126353Smlaier			}
624126353Smlaier			break;
625126353Smlaier		default:
626126353Smlaier			print_rule(&pr.rule, rule_numbers);
627126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
628126353Smlaier		}
629126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
630126353Smlaier	}
631126353Smlaier	pr.rule.action = PF_PASS;
632126353Smlaier	if (ioctl(dev, DIOCGETRULES, &pr)) {
633126353Smlaier		warn("DIOCGETRULES");
634126353Smlaier		return (-1);
635126353Smlaier	}
636126353Smlaier	mnr = pr.nr;
637126353Smlaier	for (nr = 0; nr < mnr; ++nr) {
638126353Smlaier		pr.nr = nr;
639126353Smlaier		if (ioctl(dev, DIOCGETRULE, &pr)) {
640126353Smlaier			warn("DIOCGETRULE");
641126353Smlaier			return (-1);
642126353Smlaier		}
643126353Smlaier
644126353Smlaier		if (pfctl_get_pool(dev, &pr.rule.rpool,
645126353Smlaier		    nr, pr.ticket, PF_PASS, anchorname, rulesetname) != 0)
646126353Smlaier			return (-1);
647126353Smlaier
648126353Smlaier		switch (format) {
649126353Smlaier		case 1:
650126353Smlaier			if (pr.rule.label[0]) {
651126353Smlaier				printf("%s ", pr.rule.label);
652127024Smlaier				printf("%llu %llu %llu\n",
653127024Smlaier				    (unsigned long long)pr.rule.evaluations,
654127024Smlaier				    (unsigned long long)pr.rule.packets,
655127024Smlaier				    (unsigned long long)pr.rule.bytes);
656126353Smlaier			}
657126353Smlaier			break;
658126353Smlaier		default:
659126353Smlaier			print_rule(&pr.rule, rule_numbers);
660126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
661126353Smlaier		}
662126353Smlaier		pfctl_clear_pool(&pr.rule.rpool);
663126353Smlaier	}
664126353Smlaier	return (0);
665126353Smlaier}
666126353Smlaier
667126353Smlaierint
668126353Smlaierpfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname)
669126353Smlaier{
670126353Smlaier	struct pfioc_rule pr;
671126353Smlaier	u_int32_t mnr, nr;
672126353Smlaier	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
673126353Smlaier	int i;
674126353Smlaier
675126353Smlaier	if (*anchorname && !*rulesetname) {
676126353Smlaier		struct pfioc_ruleset pr;
677126353Smlaier		int r;
678126353Smlaier
679126353Smlaier		memset(&pr, 0, sizeof(pr));
680126353Smlaier		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
681126353Smlaier		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
682126353Smlaier			if (errno == EINVAL)
683126353Smlaier				fprintf(stderr, "No rulesets in anchor '%s'.\n",
684126353Smlaier				    anchorname);
685126353Smlaier			else
686126353Smlaier				err(1, "DIOCGETRULESETS");
687126353Smlaier			return (-1);
688126353Smlaier		}
689126353Smlaier		mnr = pr.nr;
690126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
691126353Smlaier			pr.nr = nr;
692126353Smlaier			if (ioctl(dev, DIOCGETRULESET, &pr))
693126353Smlaier				err(1, "DIOCGETRULESET");
694126353Smlaier			r = pfctl_show_nat(dev, opts, anchorname, pr.name);
695126353Smlaier			if (r)
696126353Smlaier				return (r);
697126353Smlaier		}
698126353Smlaier		return (0);
699126353Smlaier	}
700126353Smlaier
701126353Smlaier	memset(&pr, 0, sizeof(pr));
702126353Smlaier	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
703126353Smlaier	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
704126353Smlaier	for (i = 0; i < 3; i++) {
705126353Smlaier		pr.rule.action = nattype[i];
706126353Smlaier		if (ioctl(dev, DIOCGETRULES, &pr)) {
707126353Smlaier			warn("DIOCGETRULES");
708126353Smlaier			return (-1);
709126353Smlaier		}
710126353Smlaier		mnr = pr.nr;
711126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
712126353Smlaier			pr.nr = nr;
713126353Smlaier			if (ioctl(dev, DIOCGETRULE, &pr)) {
714126353Smlaier				warn("DIOCGETRULE");
715126353Smlaier				return (-1);
716126353Smlaier			}
717126353Smlaier			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
718126353Smlaier			    pr.ticket, nattype[i], anchorname,
719126353Smlaier			    rulesetname) != 0)
720126353Smlaier				return (-1);
721126353Smlaier			print_rule(&pr.rule, opts & PF_OPT_VERBOSE2);
722126353Smlaier			pfctl_print_rule_counters(&pr.rule, opts);
723126353Smlaier			pfctl_clear_pool(&pr.rule.rpool);
724126353Smlaier		}
725126353Smlaier	}
726126353Smlaier	return (0);
727126353Smlaier}
728126353Smlaier
729126353Smlaierint
730126353Smlaierpfctl_show_states(int dev, u_int8_t proto, int opts)
731126353Smlaier{
732126353Smlaier	struct pfioc_states ps;
733126353Smlaier	struct pf_state *p;
734126353Smlaier	char *inbuf = NULL;
735126353Smlaier	unsigned len = 0;
736126353Smlaier	int i;
737126353Smlaier
738126353Smlaier	memset(&ps, 0, sizeof(ps));
739126353Smlaier	for (;;) {
740126353Smlaier		ps.ps_len = len;
741126353Smlaier		if (len) {
742126353Smlaier			ps.ps_buf = inbuf = realloc(inbuf, len);
743126353Smlaier			if (inbuf == NULL)
744126353Smlaier				err(1, "realloc");
745126353Smlaier		}
746126353Smlaier		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
747126353Smlaier			warn("DIOCGETSTATES");
748126353Smlaier			return (-1);
749126353Smlaier		}
750126353Smlaier		if (ps.ps_len + sizeof(struct pfioc_states) < len)
751126353Smlaier			break;
752126353Smlaier		if (len == 0 && ps.ps_len == 0)
753126353Smlaier			return (0);
754126353Smlaier		if (len == 0 && ps.ps_len != 0)
755126353Smlaier			len = ps.ps_len;
756126353Smlaier		if (ps.ps_len == 0)
757126353Smlaier			return (0);	/* no states */
758126353Smlaier		len *= 2;
759126353Smlaier	}
760126353Smlaier	p = ps.ps_states;
761126353Smlaier	for (i = 0; i < ps.ps_len; i += sizeof(*p)) {
762126353Smlaier		if (!proto || (p->proto == proto))
763126353Smlaier			print_state(p, opts);
764126353Smlaier		p++;
765126353Smlaier	}
766126353Smlaier	return (0);
767126353Smlaier}
768126353Smlaier
769126353Smlaierint
770126353Smlaierpfctl_show_status(int dev)
771126353Smlaier{
772126353Smlaier	struct pf_status status;
773126353Smlaier
774126353Smlaier	if (ioctl(dev, DIOCGETSTATUS, &status)) {
775126353Smlaier		warn("DIOCGETSTATUS");
776126353Smlaier		return (-1);
777126353Smlaier	}
778126353Smlaier	print_status(&status);
779126353Smlaier	return (0);
780126353Smlaier}
781126353Smlaier
782126353Smlaierint
783126353Smlaierpfctl_show_timeouts(int dev)
784126353Smlaier{
785126353Smlaier	struct pfioc_tm pt;
786126353Smlaier	int i;
787126353Smlaier
788126353Smlaier	memset(&pt, 0, sizeof(pt));
789126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
790126353Smlaier		pt.timeout = pf_timeouts[i].timeout;
791126353Smlaier		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
792126353Smlaier			err(1, "DIOCGETTIMEOUT");
793126353Smlaier		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
794126353Smlaier		if (i >= PFTM_ADAPTIVE_START && i <= PFTM_ADAPTIVE_END)
795126353Smlaier			printf(" states");
796126353Smlaier		else
797126353Smlaier			printf("s");
798126353Smlaier		printf("\n");
799126353Smlaier	}
800126353Smlaier	return (0);
801126353Smlaier
802126353Smlaier}
803126353Smlaier
804126353Smlaierint
805126353Smlaierpfctl_show_limits(int dev)
806126353Smlaier{
807126353Smlaier	struct pfioc_limit pl;
808126353Smlaier	int i;
809126353Smlaier
810126353Smlaier	memset(&pl, 0, sizeof(pl));
811126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
812126353Smlaier		pl.index = i;
813126353Smlaier		if (ioctl(dev, DIOCGETLIMIT, &pl))
814126353Smlaier			err(1, "DIOCGETLIMIT");
815126353Smlaier		printf("%-10s ", pf_limits[i].name);
816126353Smlaier		if (pl.limit == UINT_MAX)
817126353Smlaier			printf("unlimited\n");
818126353Smlaier		else
819126353Smlaier			printf("hard limit %6u\n", pl.limit);
820126353Smlaier	}
821126353Smlaier	return (0);
822126353Smlaier}
823126353Smlaier
824126353Smlaier/* callbacks for rule/nat/rdr/addr */
825126353Smlaierint
826126353Smlaierpfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
827126353Smlaier{
828126353Smlaier	struct pf_pooladdr *pa;
829126353Smlaier
830126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
831126353Smlaier		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
832126353Smlaier			err(1, "DIOCBEGINADDRS");
833126353Smlaier	}
834126353Smlaier
835126353Smlaier	pf->paddr.af = af;
836126353Smlaier	TAILQ_FOREACH(pa, &p->list, entries) {
837126353Smlaier		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
838126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
839126353Smlaier			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
840126353Smlaier				err(1, "DIOCADDADDR");
841126353Smlaier		}
842126353Smlaier	}
843126353Smlaier	return (0);
844126353Smlaier}
845126353Smlaier
846126353Smlaierint
847126353Smlaierpfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
848126353Smlaier{
849126353Smlaier	u_int8_t rs_num;
850126353Smlaier
851126353Smlaier	switch (r->action) {
852126353Smlaier	case PF_SCRUB:
853126353Smlaier		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
854126353Smlaier			return (0);
855126353Smlaier		rs_num = PF_RULESET_SCRUB;
856126353Smlaier		break;
857126353Smlaier	case PF_DROP:
858126353Smlaier	case PF_PASS:
859126353Smlaier		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
860126353Smlaier			return (0);
861126353Smlaier		rs_num = PF_RULESET_FILTER;
862126353Smlaier		break;
863126353Smlaier	case PF_NAT:
864126353Smlaier	case PF_NONAT:
865126353Smlaier		if ((loadopt & PFCTL_FLAG_NAT) == 0)
866126353Smlaier			return (0);
867126353Smlaier		rs_num = PF_RULESET_NAT;
868126353Smlaier		break;
869126353Smlaier	case PF_RDR:
870126353Smlaier	case PF_NORDR:
871126353Smlaier		if ((loadopt & PFCTL_FLAG_NAT) == 0)
872126353Smlaier			return (0);
873126353Smlaier		rs_num = PF_RULESET_RDR;
874126353Smlaier		break;
875126353Smlaier	case PF_BINAT:
876126353Smlaier	case PF_NOBINAT:
877126353Smlaier		if ((loadopt & PFCTL_FLAG_NAT) == 0)
878126353Smlaier			return (0);
879126353Smlaier		rs_num = PF_RULESET_BINAT;
880126353Smlaier		break;
881126353Smlaier	default:
882126353Smlaier		errx(1, "Invalid rule type");
883126353Smlaier		break;
884126353Smlaier	}
885126353Smlaier
886126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
887126353Smlaier		if (pfctl_add_pool(pf, &r->rpool, r->af))
888126353Smlaier			return (1);
889126353Smlaier		memcpy(&pf->prule[rs_num]->rule, r,
890126353Smlaier		    sizeof(pf->prule[rs_num]->rule));
891126353Smlaier		pf->prule[rs_num]->pool_ticket = pf->paddr.ticket;
892126353Smlaier		if (ioctl(pf->dev, DIOCADDRULE, pf->prule[rs_num]))
893126353Smlaier			err(1, "DIOCADDRULE");
894126353Smlaier	}
895126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
896126353Smlaier		print_rule(r, pf->opts & PF_OPT_VERBOSE2);
897126353Smlaier	pfctl_clear_pool(&r->rpool);
898126353Smlaier	return (0);
899126353Smlaier}
900126353Smlaier
901126353Smlaierint
902126353Smlaierpfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
903126353Smlaier{
904126353Smlaier	if (altqsupport &&
905126353Smlaier	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
906126353Smlaier		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
907126353Smlaier		if ((pf->opts & PF_OPT_NOACTION) == 0) {
908126353Smlaier			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
909126353Smlaier				if (errno == ENXIO)
910126353Smlaier					errx(1, "qtype not configured");
911126353Smlaier				else if (errno == ENODEV)
912126353Smlaier					errx(1, "%s: driver does not support "
913126353Smlaier					    "altq", a->ifname);
914126353Smlaier				else
915126353Smlaier					err(1, "DIOCADDALTQ");
916126353Smlaier			}
917126353Smlaier		}
918126353Smlaier		pfaltq_store(&pf->paltq->altq);
919126353Smlaier	}
920126353Smlaier	return (0);
921126353Smlaier}
922126353Smlaier
923126353Smlaierint
924126353Smlaierpfctl_rules(int dev, char *filename, int opts, char *anchorname,
925126353Smlaier    char *rulesetname)
926126353Smlaier{
927126353Smlaier#define ERR(x) do { warn(x); goto _error; } while(0)
928126353Smlaier#define ERRX(x) do { warnx(x); goto _error; } while(0)
929126353Smlaier
930126353Smlaier	FILE *fin;
931126353Smlaier	struct pfioc_rule	pr[PF_RULESET_MAX];
932126353Smlaier	struct pfioc_altq	pa;
933126353Smlaier	struct pfctl		pf;
934126353Smlaier	struct pfr_table	trs;
935126353Smlaier	int			i;
936126353Smlaier
937126353Smlaier	memset(&pa, 0, sizeof(pa));
938126353Smlaier	memset(&pf, 0, sizeof(pf));
939126353Smlaier	memset(&trs, 0, sizeof(trs));
940126353Smlaier	for (i = 0; i < PF_RULESET_MAX; i++) {
941126353Smlaier		memset(&pr[i], 0, sizeof(pr[i]));
942126353Smlaier		memcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
943126353Smlaier		memcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
944126353Smlaier	}
945126353Smlaier	if (strlcpy(trs.pfrt_anchor, anchorname,
946126353Smlaier	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) ||
947126353Smlaier	    strlcpy(trs.pfrt_ruleset, rulesetname,
948126353Smlaier	    sizeof(trs.pfrt_ruleset)) >= sizeof(trs.pfrt_ruleset))
949126353Smlaier		ERRX("pfctl_rules: strlcpy");
950126353Smlaier	if (strcmp(filename, "-") == 0) {
951126353Smlaier		fin = stdin;
952126353Smlaier		infile = "stdin";
953126353Smlaier	} else {
954126353Smlaier		if ((fin = fopen(filename, "r")) == NULL) {
955126353Smlaier			warn("%s", filename);
956126353Smlaier			return (1);
957126353Smlaier		}
958126353Smlaier		infile = filename;
959126353Smlaier	}
960126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
961126353Smlaier		if ((loadopt & PFCTL_FLAG_NAT) != 0) {
962126353Smlaier			pr[PF_RULESET_NAT].rule.action = PF_NAT;
963126353Smlaier			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_NAT]))
964126353Smlaier				ERR("DIOCBEGINRULES");
965126353Smlaier			pr[PF_RULESET_RDR].rule.action = PF_RDR;
966126353Smlaier			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_RDR]))
967126353Smlaier				ERR("DIOCBEGINRULES");
968126353Smlaier			pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
969126353Smlaier			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_BINAT]))
970126353Smlaier				ERR("DIOCBEGINRULES");
971126353Smlaier		}
972126353Smlaier		if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
973126353Smlaier		    ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) {
974126353Smlaier			ERR("DIOCBEGINALTQS");
975126353Smlaier		}
976126353Smlaier		if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
977126353Smlaier			pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
978126353Smlaier			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_SCRUB]))
979126353Smlaier				ERR("DIOCBEGINRULES");
980126353Smlaier			pr[PF_RULESET_FILTER].rule.action = PF_PASS;
981126353Smlaier			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER]))
982126353Smlaier				ERR("DIOCBEGINRULES");
983126353Smlaier		}
984126353Smlaier		if (loadopt & PFCTL_FLAG_TABLE) {
985126353Smlaier			if (pfr_ina_begin(&trs, &pf.tticket, NULL, 0) != 0)
986126353Smlaier				ERR("begin table");
987126353Smlaier		}
988126353Smlaier	}
989126353Smlaier	/* fill in callback data */
990126353Smlaier	pf.dev = dev;
991126353Smlaier	pf.opts = opts;
992126353Smlaier	pf.loadopt = loadopt;
993126353Smlaier	pf.paltq = &pa;
994126353Smlaier	for (i = 0; i < PF_RULESET_MAX; i++) {
995126353Smlaier		pf.prule[i] = &pr[i];
996126353Smlaier	}
997126353Smlaier	pf.rule_nr = 0;
998126353Smlaier	pf.anchor = anchorname;
999126353Smlaier	pf.ruleset = rulesetname;
1000126353Smlaier	if (parse_rules(fin, &pf) < 0) {
1001126353Smlaier		if ((opts & PF_OPT_NOACTION) == 0)
1002126353Smlaier			ERRX("Syntax error in config file: "
1003126353Smlaier			    "pf rules not loaded");
1004126353Smlaier		else
1005126353Smlaier			goto _error;
1006126353Smlaier	}
1007126353Smlaier	if ((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0))
1008126353Smlaier		if (check_commit_altq(dev, opts) != 0)
1009126353Smlaier			ERRX("errors in altq config");
1010126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
1011126353Smlaier		if ((loadopt & PFCTL_FLAG_NAT) != 0) {
1012126353Smlaier			pr[PF_RULESET_NAT].rule.action = PF_NAT;
1013126353Smlaier			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_NAT]) &&
1014126353Smlaier			    (errno != EINVAL || pf.rule_nr))
1015126353Smlaier				ERR("DIOCCOMMITRULES NAT");
1016126353Smlaier			pr[PF_RULESET_RDR].rule.action = PF_RDR;
1017126353Smlaier			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_RDR]) &&
1018126353Smlaier			    (errno != EINVAL || pf.rule_nr))
1019126353Smlaier				ERR("DIOCCOMMITRULES RDR");
1020126353Smlaier			pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
1021126353Smlaier			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_BINAT]) &&
1022126353Smlaier			    (errno != EINVAL || pf.rule_nr))
1023126353Smlaier				ERR("DIOCCOMMITRULES BINAT");
1024126353Smlaier		}
1025126353Smlaier		if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
1026126353Smlaier		    ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
1027126353Smlaier			ERR("DIOCCOMMITALTQS");
1028126353Smlaier		if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
1029126353Smlaier			pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
1030126353Smlaier			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_SCRUB]) &&
1031126353Smlaier			    (errno != EINVAL || pf.rule_nr))
1032126353Smlaier				ERR("DIOCCOMMITRULES SCRUB");
1033126353Smlaier			pr[PF_RULESET_FILTER].rule.action = PF_PASS;
1034126353Smlaier			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]) &&
1035126353Smlaier			    (errno != EINVAL || pf.rule_nr))
1036126353Smlaier				ERR("DIOCCOMMITRULES FILTER");
1037126353Smlaier		}
1038126353Smlaier		if (loadopt & PFCTL_FLAG_TABLE) {
1039126353Smlaier			if (pfr_ina_commit(&trs, pf.tticket, NULL, NULL, 0))
1040126353Smlaier				ERR("commit table");
1041126353Smlaier			pf.tdirty = 0;
1042126353Smlaier		}
1043126353Smlaier	}
1044126353Smlaier	if (fin != stdin)
1045126353Smlaier		fclose(fin);
1046126353Smlaier
1047126353Smlaier	/* process "load anchor" directives */
1048126353Smlaier	if (!anchorname[0] && !rulesetname[0])
1049126353Smlaier		if (pfctl_load_anchors(dev, opts) == -1)
1050126353Smlaier			ERRX("load anchors");
1051126353Smlaier
1052126353Smlaier	return (0);
1053126353Smlaier
1054126353Smlaier_error:
1055126353Smlaier	if (pf.tdirty) /* cleanup kernel leftover */
1056126353Smlaier		pfr_ina_begin(&trs, NULL, NULL, 0);
1057126353Smlaier	exit(1);
1058126353Smlaier
1059126353Smlaier#undef ERR
1060126353Smlaier#undef ERRX
1061126353Smlaier}
1062126353Smlaier
1063126353Smlaierint
1064126353Smlaierpfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1065126353Smlaier{
1066126353Smlaier	struct pfioc_limit pl;
1067126353Smlaier	int i;
1068126353Smlaier
1069126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1070126353Smlaier		return (0);
1071126353Smlaier
1072126353Smlaier	memset(&pl, 0, sizeof(pl));
1073126353Smlaier	for (i = 0; pf_limits[i].name; i++) {
1074126353Smlaier		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1075126353Smlaier			pl.index = i;
1076126353Smlaier			pl.limit = limit;
1077126353Smlaier			if ((pf->opts & PF_OPT_NOACTION) == 0) {
1078126353Smlaier				if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1079126353Smlaier					if (errno == EBUSY) {
1080126353Smlaier						warnx("Current pool "
1081126353Smlaier						    "size exceeds requested "
1082126353Smlaier						    "hard limit");
1083126353Smlaier						return (1);
1084126353Smlaier					} else
1085126353Smlaier						err(1, "DIOCSETLIMIT");
1086126353Smlaier				}
1087126353Smlaier			}
1088126353Smlaier			break;
1089126353Smlaier		}
1090126353Smlaier	}
1091126353Smlaier	if (pf_limits[i].name == NULL) {
1092126353Smlaier		warnx("Bad pool name.");
1093126353Smlaier		return (1);
1094126353Smlaier	}
1095126353Smlaier
1096126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1097126353Smlaier		printf("set limit %s %d\n", opt, limit);
1098126353Smlaier
1099126353Smlaier	return (0);
1100126353Smlaier}
1101126353Smlaier
1102126353Smlaierint
1103126353Smlaierpfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1104126353Smlaier{
1105126353Smlaier	struct pfioc_tm pt;
1106126353Smlaier	int i;
1107126353Smlaier
1108126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1109126353Smlaier		return (0);
1110126353Smlaier
1111126353Smlaier	memset(&pt, 0, sizeof(pt));
1112126353Smlaier	for (i = 0; pf_timeouts[i].name; i++) {
1113126353Smlaier		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1114126353Smlaier			pt.timeout = pf_timeouts[i].timeout;
1115126353Smlaier			break;
1116126353Smlaier		}
1117126353Smlaier	}
1118126353Smlaier
1119126353Smlaier	if (pf_timeouts[i].name == NULL) {
1120126353Smlaier		warnx("Bad timeout name.");
1121126353Smlaier		return (1);
1122126353Smlaier	}
1123126353Smlaier
1124126353Smlaier	pt.seconds = seconds;
1125126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1126126353Smlaier		if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt))
1127126353Smlaier			err(1, "DIOCSETTIMEOUT");
1128126353Smlaier	}
1129126353Smlaier
1130126353Smlaier	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1131126353Smlaier		printf("set timeout %s %d\n", opt, seconds);
1132126353Smlaier
1133126353Smlaier	return (0);
1134126353Smlaier}
1135126353Smlaier
1136126353Smlaierint
1137126353Smlaierpfctl_set_optimization(struct pfctl *pf, const char *opt)
1138126353Smlaier{
1139126353Smlaier	const struct pf_hint *hint;
1140126353Smlaier	int i, r;
1141126353Smlaier
1142126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1143126353Smlaier		return (0);
1144126353Smlaier
1145126353Smlaier	for (i = 0; pf_hints[i].name; i++)
1146126353Smlaier		if (strcasecmp(opt, pf_hints[i].name) == 0)
1147126353Smlaier			break;
1148126353Smlaier
1149126353Smlaier	hint = pf_hints[i].hint;
1150126353Smlaier	if (hint == NULL) {
1151126353Smlaier		warnx("Bad hint name.");
1152126353Smlaier		return (1);
1153126353Smlaier	}
1154126353Smlaier
1155126353Smlaier	for (i = 0; hint[i].name; i++)
1156126353Smlaier		if ((r = pfctl_set_timeout(pf, hint[i].name,
1157126353Smlaier		    hint[i].timeout, 1)))
1158126353Smlaier			return (r);
1159126353Smlaier
1160126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1161126353Smlaier		printf("set optimization %s\n", opt);
1162126353Smlaier
1163126353Smlaier	return (0);
1164126353Smlaier}
1165126353Smlaier
1166126353Smlaierint
1167126353Smlaierpfctl_set_logif(struct pfctl *pf, char *ifname)
1168126353Smlaier{
1169126353Smlaier	struct pfioc_if pi;
1170126353Smlaier
1171126353Smlaier	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1172126353Smlaier		return (0);
1173126353Smlaier
1174126353Smlaier	memset(&pi, 0, sizeof(pi));
1175126353Smlaier	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1176126353Smlaier		if (!strcmp(ifname, "none"))
1177126353Smlaier			bzero(pi.ifname, sizeof(pi.ifname));
1178126353Smlaier		else {
1179126353Smlaier			if (strlcpy(pi.ifname, ifname,
1180126353Smlaier			    sizeof(pi.ifname)) >= sizeof(pi.ifname))
1181126353Smlaier				errx(1, "pfctl_set_logif: strlcpy");
1182126353Smlaier		}
1183126353Smlaier		if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi))
1184126353Smlaier			err(1, "DIOCSETSTATUSIF");
1185126353Smlaier	}
1186126353Smlaier
1187126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
1188126353Smlaier		printf("set loginterface %s\n", ifname);
1189126353Smlaier
1190126353Smlaier	return (0);
1191126353Smlaier}
1192126353Smlaier
1193126353Smlaierint
1194126353Smlaierpfctl_debug(int dev, u_int32_t level, int opts)
1195126353Smlaier{
1196126353Smlaier	if (ioctl(dev, DIOCSETDEBUG, &level))
1197126353Smlaier		err(1, "DIOCSETDEBUG");
1198126353Smlaier	if ((opts & PF_OPT_QUIET) == 0) {
1199126353Smlaier		fprintf(stderr, "debug level set to '");
1200126353Smlaier		switch (level) {
1201126353Smlaier		case PF_DEBUG_NONE:
1202126353Smlaier			fprintf(stderr, "none");
1203126353Smlaier			break;
1204126353Smlaier		case PF_DEBUG_URGENT:
1205126353Smlaier			fprintf(stderr, "urgent");
1206126353Smlaier			break;
1207126353Smlaier		case PF_DEBUG_MISC:
1208126353Smlaier			fprintf(stderr, "misc");
1209126353Smlaier			break;
1210126353Smlaier		case PF_DEBUG_NOISY:
1211126353Smlaier			fprintf(stderr, "loud");
1212126353Smlaier			break;
1213126353Smlaier		default:
1214126353Smlaier			fprintf(stderr, "<invalid>");
1215126353Smlaier			break;
1216126353Smlaier		}
1217126353Smlaier		fprintf(stderr, "'\n");
1218126353Smlaier	}
1219126353Smlaier	return (0);
1220126353Smlaier}
1221126353Smlaier
1222126353Smlaierint
1223126353Smlaierpfctl_clear_rule_counters(int dev, int opts)
1224126353Smlaier{
1225126353Smlaier	if (ioctl(dev, DIOCCLRRULECTRS))
1226126353Smlaier		err(1, "DIOCCLRRULECTRS");
1227126353Smlaier	if ((opts & PF_OPT_QUIET) == 0)
1228126353Smlaier		fprintf(stderr, "pf: rule counters cleared\n");
1229126353Smlaier	return (0);
1230126353Smlaier}
1231126353Smlaier
1232126353Smlaierint
1233126353Smlaierpfctl_test_altqsupport(int dev, int opts)
1234126353Smlaier{
1235126355Smlaier#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
1236126355Smlaier	return (0);
1237126355Smlaier#else
1238126353Smlaier	struct pfioc_altq pa;
1239126353Smlaier
1240126353Smlaier	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1241126353Smlaier		if (errno == ENODEV) {
1242126353Smlaier			if (!(opts & PF_OPT_QUIET))
1243126353Smlaier				fprintf(stderr, "No ALTQ support in kernel\n"
1244126353Smlaier				    "ALTQ related functions disabled\n");
1245126353Smlaier			return (0);
1246126353Smlaier		} else
1247126353Smlaier			err(1, "DIOCGETALTQS");
1248126353Smlaier	}
1249126353Smlaier	return (1);
1250126355Smlaier#endif
1251126353Smlaier}
1252126353Smlaier
1253126353Smlaierint
1254126353Smlaierpfctl_show_anchors(int dev, int opts, char *anchorname)
1255126353Smlaier{
1256126353Smlaier	u_int32_t nr, mnr;
1257126353Smlaier
1258126353Smlaier	if (!*anchorname) {
1259126353Smlaier		struct pfioc_anchor pa;
1260126353Smlaier
1261126353Smlaier		memset(&pa, 0, sizeof(pa));
1262126353Smlaier		if (ioctl(dev, DIOCGETANCHORS, &pa)) {
1263126353Smlaier			warn("DIOCGETANCHORS");
1264126353Smlaier			return (-1);
1265126353Smlaier		}
1266126353Smlaier		mnr = pa.nr;
1267126353Smlaier		if (!(opts & PF_OPT_QUIET))
1268126353Smlaier			printf("%u anchors:\n", mnr);
1269126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
1270126353Smlaier			pa.nr = nr;
1271126353Smlaier			if (ioctl(dev, DIOCGETANCHOR, &pa)) {
1272126353Smlaier				warn("DIOCGETANCHOR");
1273126353Smlaier				return (-1);
1274126353Smlaier			}
1275126353Smlaier			printf("  %s\n", pa.name);
1276126353Smlaier		}
1277126353Smlaier	} else {
1278126353Smlaier		struct pfioc_ruleset pr;
1279126353Smlaier
1280126353Smlaier		memset(&pr, 0, sizeof(pr));
1281126353Smlaier		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
1282126353Smlaier		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1283126353Smlaier			if (errno == EINVAL)
1284126353Smlaier				fprintf(stderr, "No rulesets in anchor '%s'.\n",
1285126353Smlaier				    anchorname);
1286126353Smlaier			else
1287126353Smlaier				err(1, "DIOCGETRULESETS");
1288126353Smlaier			return (-1);
1289126353Smlaier		}
1290126353Smlaier		mnr = pr.nr;
1291126353Smlaier		if (!(opts & PF_OPT_QUIET))
1292126353Smlaier			printf("%u rulesets in anchor %s:\n", mnr, anchorname);
1293126353Smlaier		for (nr = 0; nr < mnr; ++nr) {
1294126353Smlaier			pr.nr = nr;
1295126353Smlaier			if (ioctl(dev, DIOCGETRULESET, &pr))
1296126353Smlaier				err(1, "DIOCGETRULESET");
1297126353Smlaier			printf("  %s:%s\n", pr.anchor, pr.name);
1298126353Smlaier		}
1299126353Smlaier	}
1300126353Smlaier	return (0);
1301126353Smlaier}
1302126353Smlaier
1303126353Smlaierconst char *
1304126353Smlaierpfctl_lookup_option(char *cmd, const char **list)
1305126353Smlaier{
1306126353Smlaier	if (cmd != NULL && *cmd)
1307126353Smlaier		for (; *list; list++)
1308126353Smlaier			if (!strncmp(cmd, *list, strlen(cmd)))
1309126353Smlaier				return (*list);
1310126353Smlaier	return (NULL);
1311126353Smlaier}
1312126353Smlaier
1313126353Smlaierint
1314126353Smlaiermain(int argc, char *argv[])
1315126353Smlaier{
1316126353Smlaier	int	error = 0;
1317126353Smlaier	int	ch;
1318126353Smlaier	int	mode = O_RDONLY;
1319126353Smlaier	int	opts = 0;
1320126353Smlaier	char	anchorname[PF_ANCHOR_NAME_SIZE];
1321126353Smlaier	char	rulesetname[PF_RULESET_NAME_SIZE];
1322126353Smlaier
1323126353Smlaier	if (argc < 2)
1324126353Smlaier		usage();
1325126353Smlaier
1326126353Smlaier	while ((ch = getopt(argc, argv, "a:AdD:eqf:F:ghk:nNOrRs:t:T:vx:z")) !=
1327126353Smlaier		-1) {
1328126353Smlaier		switch (ch) {
1329126353Smlaier		case 'a':
1330126353Smlaier			anchoropt = optarg;
1331126353Smlaier			break;
1332126353Smlaier		case 'd':
1333126353Smlaier			opts |= PF_OPT_DISABLE;
1334126353Smlaier			mode = O_RDWR;
1335126353Smlaier			break;
1336126353Smlaier		case 'D':
1337126353Smlaier			if (pfctl_cmdline_symset(optarg) < 0)
1338126353Smlaier				warnx("could not parse macro definition %s",
1339126353Smlaier				    optarg);
1340126353Smlaier			break;
1341126353Smlaier		case 'e':
1342126353Smlaier			opts |= PF_OPT_ENABLE;
1343126353Smlaier			mode = O_RDWR;
1344126353Smlaier			break;
1345126353Smlaier		case 'q':
1346126353Smlaier			opts |= PF_OPT_QUIET;
1347126353Smlaier			break;
1348126353Smlaier		case 'F':
1349126353Smlaier			clearopt = pfctl_lookup_option(optarg, clearopt_list);
1350126353Smlaier			if (clearopt == NULL) {
1351126353Smlaier				warnx("Unknown flush modifier '%s'", optarg);
1352126353Smlaier				usage();
1353126353Smlaier			}
1354126353Smlaier			mode = O_RDWR;
1355126353Smlaier			break;
1356126353Smlaier		case 'k':
1357126353Smlaier			if (state_killers >= 2) {
1358126353Smlaier				warnx("can only specify -k twice");
1359126353Smlaier				usage();
1360126353Smlaier				/* NOTREACHED */
1361126353Smlaier			}
1362126353Smlaier			state_kill[state_killers++] = optarg;
1363126353Smlaier			mode = O_RDWR;
1364126353Smlaier			break;
1365126353Smlaier		case 'n':
1366126353Smlaier			opts |= PF_OPT_NOACTION;
1367126353Smlaier			break;
1368126353Smlaier		case 'N':
1369126353Smlaier			loadopt |= PFCTL_FLAG_NAT;
1370126353Smlaier			break;
1371126353Smlaier		case 'r':
1372126353Smlaier			opts |= PF_OPT_USEDNS;
1373126353Smlaier			break;
1374126353Smlaier		case 'f':
1375126353Smlaier			rulesopt = optarg;
1376126353Smlaier			mode = O_RDWR;
1377126353Smlaier			break;
1378126353Smlaier		case 'g':
1379126353Smlaier			opts |= PF_OPT_DEBUG;
1380126353Smlaier			break;
1381126353Smlaier		case 'A':
1382126353Smlaier			loadopt |= PFCTL_FLAG_ALTQ;
1383126353Smlaier			break;
1384126353Smlaier		case 'R':
1385126353Smlaier			loadopt |= PFCTL_FLAG_FILTER;
1386126353Smlaier			break;
1387126353Smlaier		case 'O':
1388126353Smlaier			loadopt |= PFCTL_FLAG_OPTION;
1389126353Smlaier			break;
1390126353Smlaier		case 's':
1391126353Smlaier			showopt = pfctl_lookup_option(optarg, showopt_list);
1392126353Smlaier			if (showopt == NULL) {
1393126353Smlaier				warnx("Unknown show modifier '%s'", optarg);
1394126353Smlaier				usage();
1395126353Smlaier			}
1396126353Smlaier			break;
1397126353Smlaier		case 't':
1398126353Smlaier			tableopt = optarg;
1399126353Smlaier			break;
1400126353Smlaier		case 'T':
1401126353Smlaier			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
1402126353Smlaier			if (tblcmdopt == NULL) {
1403126353Smlaier				warnx("Unknown table command '%s'", optarg);
1404126353Smlaier				usage();
1405126353Smlaier			}
1406126353Smlaier			break;
1407126353Smlaier		case 'v':
1408126353Smlaier			if (opts & PF_OPT_VERBOSE)
1409126353Smlaier				opts |= PF_OPT_VERBOSE2;
1410126353Smlaier			opts |= PF_OPT_VERBOSE;
1411126353Smlaier			break;
1412126353Smlaier		case 'x':
1413126353Smlaier			debugopt = pfctl_lookup_option(optarg, debugopt_list);
1414126353Smlaier			if (debugopt == NULL) {
1415126353Smlaier				warnx("Unknown debug level '%s'", optarg);
1416126353Smlaier				usage();
1417126353Smlaier			}
1418126353Smlaier			mode = O_RDWR;
1419126353Smlaier			break;
1420126353Smlaier		case 'z':
1421126353Smlaier			opts |= PF_OPT_CLRRULECTRS;
1422126353Smlaier			mode = O_RDWR;
1423126353Smlaier			break;
1424126353Smlaier		case 'h':
1425126353Smlaier			/* FALLTHROUGH */
1426126353Smlaier		default:
1427126353Smlaier			usage();
1428126353Smlaier			/* NOTREACHED */
1429126353Smlaier		}
1430126353Smlaier	}
1431126353Smlaier
1432126353Smlaier	if (tblcmdopt != NULL) {
1433126353Smlaier		argc -= optind;
1434126353Smlaier		argv += optind;
1435126353Smlaier		ch = *tblcmdopt;
1436126353Smlaier		if (ch == 'l') {
1437126353Smlaier			loadopt |= PFCTL_FLAG_TABLE;
1438126353Smlaier			tblcmdopt = NULL;
1439126353Smlaier		} else {
1440126353Smlaier			mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY;
1441126353Smlaier			if (opts & PF_OPT_NOACTION) {
1442126353Smlaier				dev = open("/dev/pf", mode);
1443126353Smlaier				if (dev >= 0)
1444126353Smlaier					opts |= PF_OPT_DUMMYACTION;
1445126353Smlaier			}
1446126353Smlaier		}
1447126353Smlaier	} else if (argc != optind) {
1448126353Smlaier		warnx("unknown command line argument: %s ...", argv[optind]);
1449126353Smlaier		usage();
1450126353Smlaier		/* NOTREACHED */
1451126353Smlaier	}
1452126353Smlaier	if (loadopt == 0)
1453126353Smlaier		loadopt = ~0;
1454126353Smlaier
1455126353Smlaier	memset(anchorname, 0, sizeof(anchorname));
1456126353Smlaier	memset(rulesetname, 0, sizeof(rulesetname));
1457126353Smlaier	if (anchoropt != NULL) {
1458126353Smlaier		char *t;
1459126353Smlaier
1460126353Smlaier		if ((t = strchr(anchoropt, ':')) == NULL) {
1461126353Smlaier			if (strlcpy(anchorname, anchoropt,
1462126353Smlaier			    sizeof(anchorname)) >= sizeof(anchorname))
1463126353Smlaier				errx(1, "anchor name '%s' too long",
1464126353Smlaier				    anchoropt);
1465126353Smlaier		} else {
1466126353Smlaier			char *p;
1467126353Smlaier
1468126353Smlaier			if ((p = strdup(anchoropt)) == NULL)
1469126353Smlaier				err(1, "anchoropt: strdup");
1470126353Smlaier			t = strsep(&p, ":");
1471126353Smlaier			if (*t == '\0' || *p == '\0')
1472126353Smlaier				errx(1, "anchor '%s' invalid", anchoropt);
1473126353Smlaier			if (strlcpy(anchorname, t, sizeof(anchorname)) >=
1474126353Smlaier			    sizeof(anchorname))
1475126353Smlaier				errx(1, "anchor name '%s' too long", t);
1476126353Smlaier			if (strlcpy(rulesetname, p, sizeof(rulesetname)) >=
1477126353Smlaier			    sizeof(rulesetname))
1478126353Smlaier				errx(1, "ruleset name '%s' too long", p);
1479126353Smlaier			free(t); /* not p */
1480126353Smlaier		}
1481126353Smlaier		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
1482126353Smlaier	}
1483126353Smlaier
1484126353Smlaier	if ((opts & PF_OPT_NOACTION) == 0) {
1485126353Smlaier		dev = open("/dev/pf", mode);
1486126353Smlaier		if (dev == -1)
1487126353Smlaier			err(1, "/dev/pf");
1488126353Smlaier		altqsupport = pfctl_test_altqsupport(dev, opts);
1489126353Smlaier	} else {
1490126353Smlaier		/* turn off options */
1491126353Smlaier		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
1492126353Smlaier		clearopt = showopt = debugopt = NULL;
1493126355Smlaier#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
1494126355Smlaier		altqsupport = 0;
1495126355Smlaier#else
1496126353Smlaier		altqsupport = 1;
1497126355Smlaier#endif
1498126353Smlaier	}
1499126353Smlaier
1500126353Smlaier	if (opts & PF_OPT_DISABLE)
1501126353Smlaier		if (pfctl_disable(dev, opts))
1502126353Smlaier			error = 1;
1503126353Smlaier
1504126353Smlaier	if (showopt != NULL) {
1505126353Smlaier		switch (*showopt) {
1506126353Smlaier		case 'A':
1507126353Smlaier			pfctl_show_anchors(dev, opts, anchorname);
1508126353Smlaier			break;
1509126353Smlaier		case 'r':
1510126353Smlaier			pfctl_load_fingerprints(dev, opts);
1511126353Smlaier			pfctl_show_rules(dev, opts, 0, anchorname,
1512126353Smlaier			    rulesetname);
1513126353Smlaier			break;
1514126353Smlaier		case 'l':
1515126353Smlaier			pfctl_load_fingerprints(dev, opts);
1516126353Smlaier			pfctl_show_rules(dev, opts, 1, anchorname,
1517126353Smlaier			    rulesetname);
1518126353Smlaier			break;
1519126353Smlaier		case 'n':
1520126353Smlaier			pfctl_load_fingerprints(dev, opts);
1521126353Smlaier			pfctl_show_nat(dev, opts, anchorname, rulesetname);
1522126353Smlaier			break;
1523126353Smlaier		case 'q':
1524126353Smlaier			pfctl_show_altq(dev, opts, opts & PF_OPT_VERBOSE2);
1525126353Smlaier			break;
1526126353Smlaier		case 's':
1527126353Smlaier			pfctl_show_states(dev, 0, opts);
1528126353Smlaier			break;
1529126353Smlaier		case 'i':
1530126353Smlaier			pfctl_show_status(dev);
1531126353Smlaier			break;
1532126353Smlaier		case 't':
1533126353Smlaier			pfctl_show_timeouts(dev);
1534126353Smlaier			break;
1535126353Smlaier		case 'm':
1536126353Smlaier			pfctl_show_limits(dev);
1537126353Smlaier			break;
1538126353Smlaier		case 'a':
1539126353Smlaier			pfctl_load_fingerprints(dev, opts);
1540126353Smlaier
1541126353Smlaier			pfctl_show_rules(dev, opts, 0, anchorname,
1542126353Smlaier			    rulesetname);
1543126353Smlaier			pfctl_show_nat(dev, opts, anchorname, rulesetname);
1544126353Smlaier			pfctl_show_altq(dev, opts, 0);
1545126353Smlaier			pfctl_show_states(dev, 0, opts);
1546126353Smlaier			pfctl_show_status(dev);
1547126353Smlaier			pfctl_show_rules(dev, opts, 1, anchorname, rulesetname);
1548126353Smlaier			pfctl_show_timeouts(dev);
1549126353Smlaier			pfctl_show_limits(dev);
1550126353Smlaier			pfctl_show_tables(anchorname, rulesetname, opts);
1551126353Smlaier			pfctl_show_fingerprints(opts);
1552126353Smlaier			break;
1553126353Smlaier		case 'T':
1554126353Smlaier			pfctl_show_tables(anchorname, rulesetname, opts);
1555126353Smlaier			break;
1556126353Smlaier		case 'o':
1557126353Smlaier			pfctl_load_fingerprints(dev, opts);
1558126353Smlaier			pfctl_show_fingerprints(opts);
1559126353Smlaier			break;
1560126353Smlaier		}
1561126353Smlaier	}
1562126353Smlaier
1563126353Smlaier	if (clearopt != NULL) {
1564126353Smlaier		switch (*clearopt) {
1565126353Smlaier		case 'r':
1566126353Smlaier			pfctl_clear_rules(dev, opts, anchorname, rulesetname);
1567126353Smlaier			break;
1568126353Smlaier		case 'n':
1569126353Smlaier			pfctl_clear_nat(dev, opts, anchorname, rulesetname);
1570126353Smlaier			break;
1571126353Smlaier		case 'q':
1572126353Smlaier			pfctl_clear_altq(dev, opts);
1573126353Smlaier			break;
1574126353Smlaier		case 's':
1575126353Smlaier			pfctl_clear_states(dev, opts);
1576126353Smlaier			break;
1577126353Smlaier		case 'i':
1578126353Smlaier			pfctl_clear_stats(dev, opts);
1579126353Smlaier			break;
1580126353Smlaier		case 'a':
1581126353Smlaier			pfctl_clear_rules(dev, opts, anchorname, rulesetname);
1582126353Smlaier			pfctl_clear_nat(dev, opts, anchorname, rulesetname);
1583126353Smlaier			pfctl_clear_altq(dev, opts);
1584126353Smlaier			pfctl_clear_states(dev, opts);
1585126353Smlaier			pfctl_clear_stats(dev, opts);
1586126353Smlaier			pfctl_clear_tables(anchorname, rulesetname, opts);
1587126353Smlaier			pfctl_clear_fingerprints(dev, opts);
1588126353Smlaier			break;
1589126353Smlaier		case 'o':
1590126353Smlaier			pfctl_clear_fingerprints(dev, opts);
1591126353Smlaier			break;
1592126353Smlaier		case 'T':
1593126353Smlaier			pfctl_clear_tables(anchorname, rulesetname, opts);
1594126353Smlaier			break;
1595126353Smlaier		}
1596126353Smlaier	}
1597126353Smlaier	if (state_killers)
1598126353Smlaier		pfctl_kill_states(dev, opts);
1599126353Smlaier
1600126353Smlaier	if (tblcmdopt != NULL) {
1601126353Smlaier		error = pfctl_command_tables(argc, argv, tableopt,
1602126353Smlaier		    tblcmdopt, rulesopt, anchorname, rulesetname, opts);
1603126353Smlaier		rulesopt = NULL;
1604126353Smlaier	}
1605126353Smlaier
1606126353Smlaier	if (rulesopt != NULL)
1607126353Smlaier		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
1608126353Smlaier			error = 1;
1609126353Smlaier
1610126353Smlaier	if (rulesopt != NULL) {
1611126353Smlaier		if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname))
1612126353Smlaier			error = 1;
1613126353Smlaier		else if (!(opts & PF_OPT_NOACTION) &&
1614126353Smlaier		    (loadopt & PFCTL_FLAG_TABLE))
1615126353Smlaier			warn_namespace_collision(NULL);
1616126353Smlaier	}
1617126353Smlaier
1618126353Smlaier	if (opts & PF_OPT_ENABLE)
1619126353Smlaier		if (pfctl_enable(dev, opts))
1620126353Smlaier			error = 1;
1621126353Smlaier
1622126353Smlaier	if (debugopt != NULL) {
1623126353Smlaier		switch (*debugopt) {
1624126353Smlaier		case 'n':
1625126353Smlaier			pfctl_debug(dev, PF_DEBUG_NONE, opts);
1626126353Smlaier			break;
1627126353Smlaier		case 'u':
1628126353Smlaier			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
1629126353Smlaier			break;
1630126353Smlaier		case 'm':
1631126353Smlaier			pfctl_debug(dev, PF_DEBUG_MISC, opts);
1632126353Smlaier			break;
1633126353Smlaier		case 'l':
1634126353Smlaier			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
1635126353Smlaier			break;
1636126353Smlaier		}
1637126353Smlaier	}
1638126353Smlaier
1639126353Smlaier	if (opts & PF_OPT_CLRRULECTRS) {
1640126353Smlaier		if (pfctl_clear_rule_counters(dev, opts))
1641126353Smlaier			error = 1;
1642126353Smlaier	}
1643126353Smlaier	exit(error);
1644126353Smlaier}
1645