pfctl.c revision 127024
11539Srgrimes/*	$FreeBSD: head/contrib/pf/pfctl/pfctl.c 127024 2004-03-15 13:41:17Z mlaier $	*/
21539Srgrimes/*	$OpenBSD: pfctl.c,v 1.188 2003/08/29 21:47:36 cedric Exp $ */
31539Srgrimes
41539Srgrimes/*
51539Srgrimes * Copyright (c) 2001 Daniel Hartmeier
61539Srgrimes * All rights reserved.
71539Srgrimes *
81539Srgrimes * Redistribution and use in source and binary forms, with or without
91539Srgrimes * modification, are permitted provided that the following conditions
101539Srgrimes * are met:
111539Srgrimes *
121539Srgrimes *    - Redistributions of source code must retain the above copyright
131539Srgrimes *      notice, this list of conditions and the following disclaimer.
141539Srgrimes *    - Redistributions in binary form must reproduce the above
151539Srgrimes *      copyright notice, this list of conditions and the following
161539Srgrimes *      disclaimer in the documentation and/or other materials provided
171539Srgrimes *      with the distribution.
181539Srgrimes *
191539Srgrimes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
201539Srgrimes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
211539Srgrimes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
221539Srgrimes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
231539Srgrimes * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
241539Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
251539Srgrimes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
261539Srgrimes * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
271539Srgrimes * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281539Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
291539Srgrimes * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
301539Srgrimes * POSSIBILITY OF SUCH DAMAGE.
311539Srgrimes *
321539Srgrimes */
331539Srgrimes
341539Srgrimes#include <sys/types.h>
351539Srgrimes#include <sys/ioctl.h>
361539Srgrimes#include <sys/socket.h>
371539Srgrimes
381539Srgrimes#include <net/if.h>
391539Srgrimes#include <netinet/in.h>
401539Srgrimes#include <net/pfvar.h>
411539Srgrimes#include <arpa/inet.h>
421539Srgrimes#include <altq/altq.h>
431539Srgrimes
4422734Sdavidn#include <err.h>
451539Srgrimes#include <errno.h>
4621189Sdavidn#include <fcntl.h>
4724923Sbde#include <limits.h>
4824891Sdavidn#include <netdb.h>
4924891Sdavidn#include <stdio.h>
501539Srgrimes#include <stdlib.h>
511539Srgrimes#include <string.h>
521539Srgrimes#include <unistd.h>
531539Srgrimes
541539Srgrimes#include "pfctl_parser.h"
551539Srgrimes#include "pfctl.h"
561539Srgrimes
5724891Sdavidnvoid	 usage(void);
5824891Sdavidnint	 pfctl_enable(int, int);
591539Srgrimesint	 pfctl_disable(int, int);
601539Srgrimesint	 pfctl_clear_stats(int, int);
611539Srgrimesint	 pfctl_clear_rules(int, int, char *, char *);
6221189Sdavidnint	 pfctl_clear_nat(int, int, char *, char *);
631539Srgrimesint	 pfctl_clear_altq(int, int);
641539Srgrimesint	 pfctl_clear_states(int, int);
651539Srgrimesint	 pfctl_kill_states(int, int);
661539Srgrimesint	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
671539Srgrimes	     char *, char *);
681539Srgrimesvoid	 pfctl_print_rule_counters(struct pf_rule *, int);
691539Srgrimesint	 pfctl_show_rules(int, int, int, char *, char *);
701539Srgrimesint	 pfctl_show_nat(int, int, char *, char *);
711539Srgrimesint	 pfctl_show_states(int, u_int8_t, int);
7224891Sdavidnint	 pfctl_show_status(int);
7324923Sbdeint	 pfctl_show_timeouts(int);
741539Srgrimesint	 pfctl_show_limits(int);
751539Srgrimesint	 pfctl_debug(int, u_int32_t, int);
761539Srgrimesint	 pfctl_clear_rule_counters(int, int);
77int	 pfctl_test_altqsupport(int, int);
78int	 pfctl_show_anchors(int, int, char *);
79const char	*pfctl_lookup_option(char *, const char **);
80
81const char	*clearopt;
82char		*rulesopt;
83const char	*showopt;
84const char	*debugopt;
85char		*anchoropt;
86char		*tableopt;
87const char	*tblcmdopt;
88int		 state_killers;
89char		*state_kill[2];
90int		 loadopt;
91int		 altqsupport;
92
93int		 dev = -1;
94
95const char	*infile;
96
97static const struct {
98	const char	*name;
99	int		index;
100} pf_limits[] = {
101	{ "states",	PF_LIMIT_STATES },
102	{ "frags",	PF_LIMIT_FRAGS },
103	{ NULL,		0 }
104};
105
106struct pf_hint {
107	const char	*name;
108	int		timeout;
109};
110static const struct pf_hint pf_hint_normal[] = {
111	{ "tcp.first",		2 * 60 },
112	{ "tcp.opening",	30 },
113	{ "tcp.established",	24 * 60 * 60 },
114	{ "tcp.closing",	15 * 60 },
115	{ "tcp.finwait",	45 },
116	{ "tcp.closed",		90 },
117	{ NULL,			0 }
118};
119static const struct pf_hint pf_hint_satellite[] = {
120	{ "tcp.first",		3 * 60 },
121	{ "tcp.opening",	30 + 5 },
122	{ "tcp.established",	24 * 60 * 60 },
123	{ "tcp.closing",	15 * 60 + 5 },
124	{ "tcp.finwait",	45 + 5 },
125	{ "tcp.closed",		90 + 5 },
126	{ NULL,			0 }
127};
128static const struct pf_hint pf_hint_conservative[] = {
129	{ "tcp.first",		60 * 60 },
130	{ "tcp.opening",	15 * 60 },
131	{ "tcp.established",	5 * 24 * 60 * 60 },
132	{ "tcp.closing",	60 * 60 },
133	{ "tcp.finwait",	10 * 60 },
134	{ "tcp.closed",		3 * 60 },
135	{ NULL,			0 }
136};
137static const struct pf_hint pf_hint_aggressive[] = {
138	{ "tcp.first",		30 },
139	{ "tcp.opening",	5 },
140	{ "tcp.established",	5 * 60 * 60 },
141	{ "tcp.closing",	60 },
142	{ "tcp.finwait",	30 },
143	{ "tcp.closed",		30 },
144	{ NULL,			0 }
145};
146
147static const struct {
148	const char *name;
149	const struct pf_hint *hint;
150} pf_hints[] = {
151	{ "normal",		pf_hint_normal },
152	{ "satellite",		pf_hint_satellite },
153	{ "high-latency",	pf_hint_satellite },
154	{ "conservative",	pf_hint_conservative },
155	{ "aggressive",		pf_hint_aggressive },
156	{ NULL,			NULL }
157};
158
159static const char *clearopt_list[] = {
160	"nat", "queue", "rules", "state", "info", "Tables", "osfp", "all", NULL
161};
162
163static const char *showopt_list[] = {
164	"nat", "queue", "rules", "Anchors", "state", "info", "labels",
165	"timeouts", "memory", "Tables", "osfp", "all", NULL
166};
167
168static const char *tblcmdopt_list[] = {
169	"kill", "flush", "add", "delete", "load", "replace", "show",
170	"test", "zero", NULL
171};
172
173static const char *debugopt_list[] = {
174	"none", "urgent", "misc", "loud", NULL
175};
176
177
178void
179usage(void)
180{
181	extern char *__progname;
182
183	fprintf(stderr, "usage: %s [-AdeghnNqrROvz] ", __progname);
184	fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n");
185	fprintf(stderr, "             ");
186	fprintf(stderr, "[-f file] [-F modifier] [-k host] [-s modifier]\n");
187	fprintf(stderr, "             ");
188	fprintf(stderr, "[-t table] [-T command [address ...]] [-x level]\n");
189	exit(1);
190}
191
192int
193pfctl_enable(int dev, int opts)
194{
195	if (ioctl(dev, DIOCSTART)) {
196		if (errno == EEXIST)
197			errx(1, "pf already enabled");
198#ifdef __FreeBSD__
199		else if (errno == ESRCH)
200			errx(1, "pfil registeration failed");
201#endif
202		else
203			err(1, "DIOCSTART");
204	}
205	if ((opts & PF_OPT_QUIET) == 0)
206		fprintf(stderr, "pf enabled\n");
207
208	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
209		if (errno != EEXIST)
210			err(1, "DIOCSTARTALTQ");
211
212	return (0);
213}
214
215int
216pfctl_disable(int dev, int opts)
217{
218	if (ioctl(dev, DIOCSTOP)) {
219		if (errno == ENOENT)
220			errx(1, "pf not enabled");
221		else
222			err(1, "DIOCSTOP");
223	}
224	if ((opts & PF_OPT_QUIET) == 0)
225		fprintf(stderr, "pf disabled\n");
226
227	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
228			if (errno != ENOENT)
229				err(1, "DIOCSTOPALTQ");
230
231	return (0);
232}
233
234int
235pfctl_clear_stats(int dev, int opts)
236{
237	if (ioctl(dev, DIOCCLRSTATUS))
238		err(1, "DIOCCLRSTATUS");
239	if ((opts & PF_OPT_QUIET) == 0)
240		fprintf(stderr, "pf: statistics cleared\n");
241	return (0);
242}
243
244int
245pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
246{
247	struct pfioc_rule pr;
248
249	if (*anchorname && !*rulesetname) {
250		struct pfioc_ruleset pr;
251		int mnr, nr, r;
252
253		memset(&pr, 0, sizeof(pr));
254		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
255		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
256			if (errno == EINVAL)
257				fprintf(stderr, "No rulesets in anchor '%s'.\n",
258				    anchorname);
259			else
260				err(1, "DIOCGETRULESETS");
261			return (-1);
262		}
263		mnr = pr.nr;
264		for (nr = mnr - 1; nr >= 0; --nr) {
265			pr.nr = nr;
266			if (ioctl(dev, DIOCGETRULESET, &pr))
267				err(1, "DIOCGETRULESET");
268			r = pfctl_clear_rules(dev, opts | PF_OPT_QUIET,
269			    anchorname, pr.name);
270			if (r)
271				return (r);
272		}
273		if ((opts & PF_OPT_QUIET) == 0)
274			fprintf(stderr, "rules cleared\n");
275		return (0);
276	}
277	memset(&pr, 0, sizeof(pr));
278	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
279	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
280	pr.rule.action = PF_SCRUB;
281	if (ioctl(dev, DIOCBEGINRULES, &pr))
282		err(1, "DIOCBEGINRULES");
283	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
284		err(1, "DIOCCOMMITRULES");
285	pr.rule.action = PF_PASS;
286	if (ioctl(dev, DIOCBEGINRULES, &pr))
287		err(1, "DIOCBEGINRULES");
288	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
289		err(1, "DIOCCOMMITRULES");
290	if ((opts & PF_OPT_QUIET) == 0)
291		fprintf(stderr, "rules cleared\n");
292	return (0);
293}
294
295int
296pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
297{
298	struct pfioc_rule pr;
299
300	if (*anchorname && !*rulesetname) {
301		struct pfioc_ruleset pr;
302		int mnr, nr, r;
303
304		memset(&pr, 0, sizeof(pr));
305		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
306		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
307			if (errno == EINVAL)
308				fprintf(stderr, "No rulesets in anchor '%s'.\n",
309				    anchorname);
310			else
311				err(1, "DIOCGETRULESETS");
312			return (-1);
313		}
314		mnr = pr.nr;
315		for (nr = mnr - 1; nr >= 0; --nr) {
316			pr.nr = nr;
317			if (ioctl(dev, DIOCGETRULESET, &pr))
318				err(1, "DIOCGETRULESET");
319			r = pfctl_clear_nat(dev, opts | PF_OPT_QUIET,
320			    anchorname, pr.name);
321			if (r)
322				return (r);
323		}
324		if ((opts & PF_OPT_QUIET) == 0)
325			fprintf(stderr, "nat cleared\n");
326		return (0);
327	}
328	memset(&pr, 0, sizeof(pr));
329	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
330	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
331	pr.rule.action = PF_NAT;
332	if (ioctl(dev, DIOCBEGINRULES, &pr))
333		err(1, "DIOCBEGINRULES");
334	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
335		err(1, "DIOCCOMMITRULES");
336	pr.rule.action = PF_BINAT;
337	if (ioctl(dev, DIOCBEGINRULES, &pr))
338		err(1, "DIOCBEGINRULES");
339	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
340		err(1, "DIOCCOMMITRULES");
341	pr.rule.action = PF_RDR;
342	if (ioctl(dev, DIOCBEGINRULES, &pr))
343		err(1, "DIOCBEGINRULES");
344	else if (ioctl(dev, DIOCCOMMITRULES, &pr))
345		err(1, "DIOCCOMMITRULES");
346	if ((opts & PF_OPT_QUIET) == 0)
347		fprintf(stderr, "nat cleared\n");
348	return (0);
349}
350
351int
352pfctl_clear_altq(int dev, int opts)
353{
354	struct pfioc_altq pa;
355
356	if (!altqsupport)
357		return (-1);
358	memset(&pa, 0, sizeof(pa));
359	if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket))
360		err(1, "DIOCBEGINALTQS");
361	else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
362		err(1, "DIOCCOMMITALTQS");
363	if ((opts & PF_OPT_QUIET) == 0)
364		fprintf(stderr, "altq cleared\n");
365	return (0);
366}
367
368int
369pfctl_clear_states(int dev, int opts)
370{
371	if (ioctl(dev, DIOCCLRSTATES))
372		err(1, "DIOCCLRSTATES");
373	if ((opts & PF_OPT_QUIET) == 0)
374		fprintf(stderr, "states cleared\n");
375	return (0);
376}
377
378int
379pfctl_kill_states(int dev, int opts)
380{
381	struct pfioc_state_kill psk;
382	struct addrinfo *res[2], *resp[2];
383	struct sockaddr last_src, last_dst;
384	int killed, sources, dests;
385	int ret_ga;
386
387	killed = sources = dests = 0;
388
389	memset(&psk, 0, sizeof(psk));
390	memset(&psk.psk_src.addr.v.a.mask, 0xff,
391	    sizeof(psk.psk_src.addr.v.a.mask));
392	memset(&last_src, 0xff, sizeof(last_src));
393	memset(&last_dst, 0xff, sizeof(last_dst));
394
395	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
396		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
397		/* NOTREACHED */
398	}
399	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
400		if (resp[0]->ai_addr == NULL)
401			continue;
402		/* We get lots of duplicates.  Catch the easy ones */
403		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
404			continue;
405		last_src = *(struct sockaddr *)resp[0]->ai_addr;
406
407		psk.psk_af = resp[0]->ai_family;
408		sources++;
409
410		if (psk.psk_af == AF_INET)
411			psk.psk_src.addr.v.a.addr.v4 =
412			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
413		else if (psk.psk_af == AF_INET6)
414			psk.psk_src.addr.v.a.addr.v6 =
415			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
416			    sin6_addr;
417		else
418			errx(1, "Unknown address family %d", psk.psk_af);
419
420		if (state_killers > 1) {
421			dests = 0;
422			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
423			    sizeof(psk.psk_dst.addr.v.a.mask));
424			memset(&last_dst, 0xff, sizeof(last_dst));
425			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
426			    &res[1]))) {
427				errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
428				/* NOTREACHED */
429			}
430			for (resp[1] = res[1]; resp[1];
431			    resp[1] = resp[1]->ai_next) {
432				if (resp[1]->ai_addr == NULL)
433					continue;
434				if (psk.psk_af != resp[1]->ai_family)
435					continue;
436
437				if (memcmp(&last_dst, resp[1]->ai_addr,
438				    sizeof(last_dst)) == 0)
439					continue;
440				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
441
442				dests++;
443
444				if (psk.psk_af == AF_INET)
445					psk.psk_dst.addr.v.a.addr.v4 =
446					    ((struct sockaddr_in *)resp[1]->
447					    ai_addr)->sin_addr;
448				else if (psk.psk_af == AF_INET6)
449					psk.psk_dst.addr.v.a.addr.v6 =
450					    ((struct sockaddr_in6 *)resp[1]->
451					    ai_addr)->sin6_addr;
452				else
453					errx(1, "Unknown address family %d",
454					    psk.psk_af);
455
456				if (ioctl(dev, DIOCKILLSTATES, &psk))
457					err(1, "DIOCKILLSTATES");
458				killed += psk.psk_af;
459				/* fixup psk.psk_af */
460				psk.psk_af = resp[1]->ai_family;
461			}
462			freeaddrinfo(res[1]);
463		} else {
464			if (ioctl(dev, DIOCKILLSTATES, &psk))
465				err(1, "DIOCKILLSTATES");
466			killed += psk.psk_af;
467			/* fixup psk.psk_af */
468			psk.psk_af = res[0]->ai_family;
469		}
470	}
471
472	freeaddrinfo(res[0]);
473
474	if ((opts & PF_OPT_QUIET) == 0)
475		fprintf(stderr, "killed %d states from %d sources and %d "
476		    "destinations\n", killed, sources, dests);
477	return (0);
478}
479
480int
481pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
482    u_int32_t ticket, int r_action, char *anchorname, char *rulesetname)
483{
484	struct pfioc_pooladdr pp;
485	struct pf_pooladdr *pa;
486	u_int32_t pnr, mpnr;
487
488	memset(&pp, 0, sizeof(pp));
489	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
490	memcpy(pp.ruleset, rulesetname, sizeof(pp.ruleset));
491	pp.r_action = r_action;
492	pp.r_num = nr;
493	pp.ticket = ticket;
494	if (ioctl(dev, DIOCGETADDRS, &pp)) {
495		warn("DIOCGETADDRS");
496		return (-1);
497	}
498	mpnr = pp.nr;
499	TAILQ_INIT(&pool->list);
500	for (pnr = 0; pnr < mpnr; ++pnr) {
501		pp.nr = pnr;
502		if (ioctl(dev, DIOCGETADDR, &pp)) {
503			warn("DIOCGETADDR");
504			return (-1);
505		}
506		pa = calloc(1, sizeof(struct pf_pooladdr));
507		if (pa == NULL)
508			err(1, "calloc");
509		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
510		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
511	}
512
513	return (0);
514}
515
516void
517pfctl_clear_pool(struct pf_pool *pool)
518{
519	struct pf_pooladdr *pa;
520
521	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
522		TAILQ_REMOVE(&pool->list, pa, entries);
523		free(pa);
524	}
525}
526
527void
528pfctl_print_rule_counters(struct pf_rule *rule, int opts)
529{
530	if (opts & PF_OPT_DEBUG) {
531		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
532		    "p", "sa", "sp", "da", "dp" };
533		int i;
534
535		printf("  [ Skip steps: ");
536		for (i = 0; i < PF_SKIP_COUNT; ++i) {
537			if (rule->skip[i].nr == rule->nr + 1)
538				continue;
539			printf("%s=", t[i]);
540			if (rule->skip[i].nr == -1)
541				printf("end ");
542			else
543				printf("%u ", rule->skip[i].nr);
544		}
545		printf("]\n");
546
547		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
548		    rule->qname, rule->qid, rule->pqname, rule->pqid);
549	}
550	if (opts & PF_OPT_VERBOSE)
551		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
552			    "Bytes: %-10llu  States: %-6u]\n",
553			    (unsigned long long)rule->evaluations,
554			    (unsigned long long)rule->packets,
555			    (unsigned long long)rule->bytes, rule->states);
556}
557
558int
559pfctl_show_rules(int dev, int opts, int format, char *anchorname,
560    char *rulesetname)
561{
562	struct pfioc_rule pr;
563	u_int32_t nr, mnr;
564	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
565
566	if (*anchorname && !*rulesetname) {
567		struct pfioc_ruleset pr;
568		int r;
569
570		memset(&pr, 0, sizeof(pr));
571		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
572		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
573			if (errno == EINVAL)
574				fprintf(stderr, "No rulesets in anchor '%s'.\n",
575				    anchorname);
576			else
577				err(1, "DIOCGETRULESETS");
578			return (-1);
579		}
580		mnr = pr.nr;
581		for (nr = 0; nr < mnr; ++nr) {
582			pr.nr = nr;
583			if (ioctl(dev, DIOCGETRULESET, &pr))
584				err(1, "DIOCGETRULESET");
585			r = pfctl_show_rules(dev, opts, format, anchorname,
586			    pr.name);
587			if (r)
588				return (r);
589		}
590		return (0);
591	}
592
593	memset(&pr, 0, sizeof(pr));
594	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
595	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
596	pr.rule.action = PF_SCRUB;
597	if (ioctl(dev, DIOCGETRULES, &pr)) {
598		warn("DIOCGETRULES");
599		return (-1);
600	}
601	mnr = pr.nr;
602	for (nr = 0; nr < mnr; ++nr) {
603		pr.nr = nr;
604		if (ioctl(dev, DIOCGETRULE, &pr)) {
605			warn("DIOCGETRULE");
606			return (-1);
607		}
608
609		if (pfctl_get_pool(dev, &pr.rule.rpool,
610		    nr, pr.ticket, PF_SCRUB, anchorname, rulesetname) != 0)
611			return (-1);
612
613		switch (format) {
614		case 1:
615			if (pr.rule.label[0]) {
616				printf("%s ", pr.rule.label);
617				printf("%llu %llu %llu\n",
618				    (unsigned long long)pr.rule.evaluations,
619				    (unsigned long long)pr.rule.packets,
620				    (unsigned long long)pr.rule.bytes);
621			}
622			break;
623		default:
624			print_rule(&pr.rule, rule_numbers);
625			pfctl_print_rule_counters(&pr.rule, opts);
626		}
627		pfctl_clear_pool(&pr.rule.rpool);
628	}
629	pr.rule.action = PF_PASS;
630	if (ioctl(dev, DIOCGETRULES, &pr)) {
631		warn("DIOCGETRULES");
632		return (-1);
633	}
634	mnr = pr.nr;
635	for (nr = 0; nr < mnr; ++nr) {
636		pr.nr = nr;
637		if (ioctl(dev, DIOCGETRULE, &pr)) {
638			warn("DIOCGETRULE");
639			return (-1);
640		}
641
642		if (pfctl_get_pool(dev, &pr.rule.rpool,
643		    nr, pr.ticket, PF_PASS, anchorname, rulesetname) != 0)
644			return (-1);
645
646		switch (format) {
647		case 1:
648			if (pr.rule.label[0]) {
649				printf("%s ", pr.rule.label);
650				printf("%llu %llu %llu\n",
651				    (unsigned long long)pr.rule.evaluations,
652				    (unsigned long long)pr.rule.packets,
653				    (unsigned long long)pr.rule.bytes);
654			}
655			break;
656		default:
657			print_rule(&pr.rule, rule_numbers);
658			pfctl_print_rule_counters(&pr.rule, opts);
659		}
660		pfctl_clear_pool(&pr.rule.rpool);
661	}
662	return (0);
663}
664
665int
666pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname)
667{
668	struct pfioc_rule pr;
669	u_int32_t mnr, nr;
670	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
671	int i;
672
673	if (*anchorname && !*rulesetname) {
674		struct pfioc_ruleset pr;
675		int r;
676
677		memset(&pr, 0, sizeof(pr));
678		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
679		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
680			if (errno == EINVAL)
681				fprintf(stderr, "No rulesets in anchor '%s'.\n",
682				    anchorname);
683			else
684				err(1, "DIOCGETRULESETS");
685			return (-1);
686		}
687		mnr = pr.nr;
688		for (nr = 0; nr < mnr; ++nr) {
689			pr.nr = nr;
690			if (ioctl(dev, DIOCGETRULESET, &pr))
691				err(1, "DIOCGETRULESET");
692			r = pfctl_show_nat(dev, opts, anchorname, pr.name);
693			if (r)
694				return (r);
695		}
696		return (0);
697	}
698
699	memset(&pr, 0, sizeof(pr));
700	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
701	memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
702	for (i = 0; i < 3; i++) {
703		pr.rule.action = nattype[i];
704		if (ioctl(dev, DIOCGETRULES, &pr)) {
705			warn("DIOCGETRULES");
706			return (-1);
707		}
708		mnr = pr.nr;
709		for (nr = 0; nr < mnr; ++nr) {
710			pr.nr = nr;
711			if (ioctl(dev, DIOCGETRULE, &pr)) {
712				warn("DIOCGETRULE");
713				return (-1);
714			}
715			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
716			    pr.ticket, nattype[i], anchorname,
717			    rulesetname) != 0)
718				return (-1);
719			print_rule(&pr.rule, opts & PF_OPT_VERBOSE2);
720			pfctl_print_rule_counters(&pr.rule, opts);
721			pfctl_clear_pool(&pr.rule.rpool);
722		}
723	}
724	return (0);
725}
726
727int
728pfctl_show_states(int dev, u_int8_t proto, int opts)
729{
730	struct pfioc_states ps;
731	struct pf_state *p;
732	char *inbuf = NULL;
733	unsigned len = 0;
734	int i;
735
736	memset(&ps, 0, sizeof(ps));
737	for (;;) {
738		ps.ps_len = len;
739		if (len) {
740			ps.ps_buf = inbuf = realloc(inbuf, len);
741			if (inbuf == NULL)
742				err(1, "realloc");
743		}
744		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
745			warn("DIOCGETSTATES");
746			return (-1);
747		}
748		if (ps.ps_len + sizeof(struct pfioc_states) < len)
749			break;
750		if (len == 0 && ps.ps_len == 0)
751			return (0);
752		if (len == 0 && ps.ps_len != 0)
753			len = ps.ps_len;
754		if (ps.ps_len == 0)
755			return (0);	/* no states */
756		len *= 2;
757	}
758	p = ps.ps_states;
759	for (i = 0; i < ps.ps_len; i += sizeof(*p)) {
760		if (!proto || (p->proto == proto))
761			print_state(p, opts);
762		p++;
763	}
764	return (0);
765}
766
767int
768pfctl_show_status(int dev)
769{
770	struct pf_status status;
771
772	if (ioctl(dev, DIOCGETSTATUS, &status)) {
773		warn("DIOCGETSTATUS");
774		return (-1);
775	}
776	print_status(&status);
777	return (0);
778}
779
780int
781pfctl_show_timeouts(int dev)
782{
783	struct pfioc_tm pt;
784	int i;
785
786	memset(&pt, 0, sizeof(pt));
787	for (i = 0; pf_timeouts[i].name; i++) {
788		pt.timeout = pf_timeouts[i].timeout;
789		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
790			err(1, "DIOCGETTIMEOUT");
791		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
792		if (i >= PFTM_ADAPTIVE_START && i <= PFTM_ADAPTIVE_END)
793			printf(" states");
794		else
795			printf("s");
796		printf("\n");
797	}
798	return (0);
799
800}
801
802int
803pfctl_show_limits(int dev)
804{
805	struct pfioc_limit pl;
806	int i;
807
808	memset(&pl, 0, sizeof(pl));
809	for (i = 0; pf_limits[i].name; i++) {
810		pl.index = i;
811		if (ioctl(dev, DIOCGETLIMIT, &pl))
812			err(1, "DIOCGETLIMIT");
813		printf("%-10s ", pf_limits[i].name);
814		if (pl.limit == UINT_MAX)
815			printf("unlimited\n");
816		else
817			printf("hard limit %6u\n", pl.limit);
818	}
819	return (0);
820}
821
822/* callbacks for rule/nat/rdr/addr */
823int
824pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
825{
826	struct pf_pooladdr *pa;
827
828	if ((pf->opts & PF_OPT_NOACTION) == 0) {
829		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
830			err(1, "DIOCBEGINADDRS");
831	}
832
833	pf->paddr.af = af;
834	TAILQ_FOREACH(pa, &p->list, entries) {
835		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
836		if ((pf->opts & PF_OPT_NOACTION) == 0) {
837			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
838				err(1, "DIOCADDADDR");
839		}
840	}
841	return (0);
842}
843
844int
845pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
846{
847	u_int8_t rs_num;
848
849	switch (r->action) {
850	case PF_SCRUB:
851		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
852			return (0);
853		rs_num = PF_RULESET_SCRUB;
854		break;
855	case PF_DROP:
856	case PF_PASS:
857		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
858			return (0);
859		rs_num = PF_RULESET_FILTER;
860		break;
861	case PF_NAT:
862	case PF_NONAT:
863		if ((loadopt & PFCTL_FLAG_NAT) == 0)
864			return (0);
865		rs_num = PF_RULESET_NAT;
866		break;
867	case PF_RDR:
868	case PF_NORDR:
869		if ((loadopt & PFCTL_FLAG_NAT) == 0)
870			return (0);
871		rs_num = PF_RULESET_RDR;
872		break;
873	case PF_BINAT:
874	case PF_NOBINAT:
875		if ((loadopt & PFCTL_FLAG_NAT) == 0)
876			return (0);
877		rs_num = PF_RULESET_BINAT;
878		break;
879	default:
880		errx(1, "Invalid rule type");
881		break;
882	}
883
884	if ((pf->opts & PF_OPT_NOACTION) == 0) {
885		if (pfctl_add_pool(pf, &r->rpool, r->af))
886			return (1);
887		memcpy(&pf->prule[rs_num]->rule, r,
888		    sizeof(pf->prule[rs_num]->rule));
889		pf->prule[rs_num]->pool_ticket = pf->paddr.ticket;
890		if (ioctl(pf->dev, DIOCADDRULE, pf->prule[rs_num]))
891			err(1, "DIOCADDRULE");
892	}
893	if (pf->opts & PF_OPT_VERBOSE)
894		print_rule(r, pf->opts & PF_OPT_VERBOSE2);
895	pfctl_clear_pool(&r->rpool);
896	return (0);
897}
898
899int
900pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
901{
902	if (altqsupport &&
903	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
904		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
905		if ((pf->opts & PF_OPT_NOACTION) == 0) {
906			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
907				if (errno == ENXIO)
908					errx(1, "qtype not configured");
909				else if (errno == ENODEV)
910					errx(1, "%s: driver does not support "
911					    "altq", a->ifname);
912				else
913					err(1, "DIOCADDALTQ");
914			}
915		}
916		pfaltq_store(&pf->paltq->altq);
917	}
918	return (0);
919}
920
921int
922pfctl_rules(int dev, char *filename, int opts, char *anchorname,
923    char *rulesetname)
924{
925#define ERR(x) do { warn(x); goto _error; } while(0)
926#define ERRX(x) do { warnx(x); goto _error; } while(0)
927
928	FILE *fin;
929	struct pfioc_rule	pr[PF_RULESET_MAX];
930	struct pfioc_altq	pa;
931	struct pfctl		pf;
932	struct pfr_table	trs;
933	int			i;
934
935	memset(&pa, 0, sizeof(pa));
936	memset(&pf, 0, sizeof(pf));
937	memset(&trs, 0, sizeof(trs));
938	for (i = 0; i < PF_RULESET_MAX; i++) {
939		memset(&pr[i], 0, sizeof(pr[i]));
940		memcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
941		memcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
942	}
943	if (strlcpy(trs.pfrt_anchor, anchorname,
944	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) ||
945	    strlcpy(trs.pfrt_ruleset, rulesetname,
946	    sizeof(trs.pfrt_ruleset)) >= sizeof(trs.pfrt_ruleset))
947		ERRX("pfctl_rules: strlcpy");
948	if (strcmp(filename, "-") == 0) {
949		fin = stdin;
950		infile = "stdin";
951	} else {
952		if ((fin = fopen(filename, "r")) == NULL) {
953			warn("%s", filename);
954			return (1);
955		}
956		infile = filename;
957	}
958	if ((opts & PF_OPT_NOACTION) == 0) {
959		if ((loadopt & PFCTL_FLAG_NAT) != 0) {
960			pr[PF_RULESET_NAT].rule.action = PF_NAT;
961			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_NAT]))
962				ERR("DIOCBEGINRULES");
963			pr[PF_RULESET_RDR].rule.action = PF_RDR;
964			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_RDR]))
965				ERR("DIOCBEGINRULES");
966			pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
967			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_BINAT]))
968				ERR("DIOCBEGINRULES");
969		}
970		if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
971		    ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) {
972			ERR("DIOCBEGINALTQS");
973		}
974		if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
975			pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
976			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_SCRUB]))
977				ERR("DIOCBEGINRULES");
978			pr[PF_RULESET_FILTER].rule.action = PF_PASS;
979			if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER]))
980				ERR("DIOCBEGINRULES");
981		}
982		if (loadopt & PFCTL_FLAG_TABLE) {
983			if (pfr_ina_begin(&trs, &pf.tticket, NULL, 0) != 0)
984				ERR("begin table");
985		}
986	}
987	/* fill in callback data */
988	pf.dev = dev;
989	pf.opts = opts;
990	pf.loadopt = loadopt;
991	pf.paltq = &pa;
992	for (i = 0; i < PF_RULESET_MAX; i++) {
993		pf.prule[i] = &pr[i];
994	}
995	pf.rule_nr = 0;
996	pf.anchor = anchorname;
997	pf.ruleset = rulesetname;
998	if (parse_rules(fin, &pf) < 0) {
999		if ((opts & PF_OPT_NOACTION) == 0)
1000			ERRX("Syntax error in config file: "
1001			    "pf rules not loaded");
1002		else
1003			goto _error;
1004	}
1005	if ((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0))
1006		if (check_commit_altq(dev, opts) != 0)
1007			ERRX("errors in altq config");
1008	if ((opts & PF_OPT_NOACTION) == 0) {
1009		if ((loadopt & PFCTL_FLAG_NAT) != 0) {
1010			pr[PF_RULESET_NAT].rule.action = PF_NAT;
1011			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_NAT]) &&
1012			    (errno != EINVAL || pf.rule_nr))
1013				ERR("DIOCCOMMITRULES NAT");
1014			pr[PF_RULESET_RDR].rule.action = PF_RDR;
1015			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_RDR]) &&
1016			    (errno != EINVAL || pf.rule_nr))
1017				ERR("DIOCCOMMITRULES RDR");
1018			pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
1019			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_BINAT]) &&
1020			    (errno != EINVAL || pf.rule_nr))
1021				ERR("DIOCCOMMITRULES BINAT");
1022		}
1023		if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
1024		    ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
1025			ERR("DIOCCOMMITALTQS");
1026		if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
1027			pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
1028			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_SCRUB]) &&
1029			    (errno != EINVAL || pf.rule_nr))
1030				ERR("DIOCCOMMITRULES SCRUB");
1031			pr[PF_RULESET_FILTER].rule.action = PF_PASS;
1032			if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]) &&
1033			    (errno != EINVAL || pf.rule_nr))
1034				ERR("DIOCCOMMITRULES FILTER");
1035		}
1036		if (loadopt & PFCTL_FLAG_TABLE) {
1037			if (pfr_ina_commit(&trs, pf.tticket, NULL, NULL, 0))
1038				ERR("commit table");
1039			pf.tdirty = 0;
1040		}
1041	}
1042	if (fin != stdin)
1043		fclose(fin);
1044
1045	/* process "load anchor" directives */
1046	if (!anchorname[0] && !rulesetname[0])
1047		if (pfctl_load_anchors(dev, opts) == -1)
1048			ERRX("load anchors");
1049
1050	return (0);
1051
1052_error:
1053	if (pf.tdirty) /* cleanup kernel leftover */
1054		pfr_ina_begin(&trs, NULL, NULL, 0);
1055	exit(1);
1056
1057#undef ERR
1058#undef ERRX
1059}
1060
1061int
1062pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1063{
1064	struct pfioc_limit pl;
1065	int i;
1066
1067	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1068		return (0);
1069
1070	memset(&pl, 0, sizeof(pl));
1071	for (i = 0; pf_limits[i].name; i++) {
1072		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1073			pl.index = i;
1074			pl.limit = limit;
1075			if ((pf->opts & PF_OPT_NOACTION) == 0) {
1076				if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1077					if (errno == EBUSY) {
1078						warnx("Current pool "
1079						    "size exceeds requested "
1080						    "hard limit");
1081						return (1);
1082					} else
1083						err(1, "DIOCSETLIMIT");
1084				}
1085			}
1086			break;
1087		}
1088	}
1089	if (pf_limits[i].name == NULL) {
1090		warnx("Bad pool name.");
1091		return (1);
1092	}
1093
1094	if (pf->opts & PF_OPT_VERBOSE)
1095		printf("set limit %s %d\n", opt, limit);
1096
1097	return (0);
1098}
1099
1100int
1101pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1102{
1103	struct pfioc_tm pt;
1104	int i;
1105
1106	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1107		return (0);
1108
1109	memset(&pt, 0, sizeof(pt));
1110	for (i = 0; pf_timeouts[i].name; i++) {
1111		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1112			pt.timeout = pf_timeouts[i].timeout;
1113			break;
1114		}
1115	}
1116
1117	if (pf_timeouts[i].name == NULL) {
1118		warnx("Bad timeout name.");
1119		return (1);
1120	}
1121
1122	pt.seconds = seconds;
1123	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1124		if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt))
1125			err(1, "DIOCSETTIMEOUT");
1126	}
1127
1128	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1129		printf("set timeout %s %d\n", opt, seconds);
1130
1131	return (0);
1132}
1133
1134int
1135pfctl_set_optimization(struct pfctl *pf, const char *opt)
1136{
1137	const struct pf_hint *hint;
1138	int i, r;
1139
1140	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1141		return (0);
1142
1143	for (i = 0; pf_hints[i].name; i++)
1144		if (strcasecmp(opt, pf_hints[i].name) == 0)
1145			break;
1146
1147	hint = pf_hints[i].hint;
1148	if (hint == NULL) {
1149		warnx("Bad hint name.");
1150		return (1);
1151	}
1152
1153	for (i = 0; hint[i].name; i++)
1154		if ((r = pfctl_set_timeout(pf, hint[i].name,
1155		    hint[i].timeout, 1)))
1156			return (r);
1157
1158	if (pf->opts & PF_OPT_VERBOSE)
1159		printf("set optimization %s\n", opt);
1160
1161	return (0);
1162}
1163
1164int
1165pfctl_set_logif(struct pfctl *pf, char *ifname)
1166{
1167	struct pfioc_if pi;
1168
1169	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1170		return (0);
1171
1172	memset(&pi, 0, sizeof(pi));
1173	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1174		if (!strcmp(ifname, "none"))
1175			bzero(pi.ifname, sizeof(pi.ifname));
1176		else {
1177			if (strlcpy(pi.ifname, ifname,
1178			    sizeof(pi.ifname)) >= sizeof(pi.ifname))
1179				errx(1, "pfctl_set_logif: strlcpy");
1180		}
1181		if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi))
1182			err(1, "DIOCSETSTATUSIF");
1183	}
1184
1185	if (pf->opts & PF_OPT_VERBOSE)
1186		printf("set loginterface %s\n", ifname);
1187
1188	return (0);
1189}
1190
1191int
1192pfctl_debug(int dev, u_int32_t level, int opts)
1193{
1194	if (ioctl(dev, DIOCSETDEBUG, &level))
1195		err(1, "DIOCSETDEBUG");
1196	if ((opts & PF_OPT_QUIET) == 0) {
1197		fprintf(stderr, "debug level set to '");
1198		switch (level) {
1199		case PF_DEBUG_NONE:
1200			fprintf(stderr, "none");
1201			break;
1202		case PF_DEBUG_URGENT:
1203			fprintf(stderr, "urgent");
1204			break;
1205		case PF_DEBUG_MISC:
1206			fprintf(stderr, "misc");
1207			break;
1208		case PF_DEBUG_NOISY:
1209			fprintf(stderr, "loud");
1210			break;
1211		default:
1212			fprintf(stderr, "<invalid>");
1213			break;
1214		}
1215		fprintf(stderr, "'\n");
1216	}
1217	return (0);
1218}
1219
1220int
1221pfctl_clear_rule_counters(int dev, int opts)
1222{
1223	if (ioctl(dev, DIOCCLRRULECTRS))
1224		err(1, "DIOCCLRRULECTRS");
1225	if ((opts & PF_OPT_QUIET) == 0)
1226		fprintf(stderr, "pf: rule counters cleared\n");
1227	return (0);
1228}
1229
1230int
1231pfctl_test_altqsupport(int dev, int opts)
1232{
1233#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
1234	return (0);
1235#else
1236	struct pfioc_altq pa;
1237
1238	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1239		if (errno == ENODEV) {
1240			if (!(opts & PF_OPT_QUIET))
1241				fprintf(stderr, "No ALTQ support in kernel\n"
1242				    "ALTQ related functions disabled\n");
1243			return (0);
1244		} else
1245			err(1, "DIOCGETALTQS");
1246	}
1247	return (1);
1248#endif
1249}
1250
1251int
1252pfctl_show_anchors(int dev, int opts, char *anchorname)
1253{
1254	u_int32_t nr, mnr;
1255
1256	if (!*anchorname) {
1257		struct pfioc_anchor pa;
1258
1259		memset(&pa, 0, sizeof(pa));
1260		if (ioctl(dev, DIOCGETANCHORS, &pa)) {
1261			warn("DIOCGETANCHORS");
1262			return (-1);
1263		}
1264		mnr = pa.nr;
1265		if (!(opts & PF_OPT_QUIET))
1266			printf("%u anchors:\n", mnr);
1267		for (nr = 0; nr < mnr; ++nr) {
1268			pa.nr = nr;
1269			if (ioctl(dev, DIOCGETANCHOR, &pa)) {
1270				warn("DIOCGETANCHOR");
1271				return (-1);
1272			}
1273			printf("  %s\n", pa.name);
1274		}
1275	} else {
1276		struct pfioc_ruleset pr;
1277
1278		memset(&pr, 0, sizeof(pr));
1279		memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
1280		if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1281			if (errno == EINVAL)
1282				fprintf(stderr, "No rulesets in anchor '%s'.\n",
1283				    anchorname);
1284			else
1285				err(1, "DIOCGETRULESETS");
1286			return (-1);
1287		}
1288		mnr = pr.nr;
1289		if (!(opts & PF_OPT_QUIET))
1290			printf("%u rulesets in anchor %s:\n", mnr, anchorname);
1291		for (nr = 0; nr < mnr; ++nr) {
1292			pr.nr = nr;
1293			if (ioctl(dev, DIOCGETRULESET, &pr))
1294				err(1, "DIOCGETRULESET");
1295			printf("  %s:%s\n", pr.anchor, pr.name);
1296		}
1297	}
1298	return (0);
1299}
1300
1301const char *
1302pfctl_lookup_option(char *cmd, const char **list)
1303{
1304	if (cmd != NULL && *cmd)
1305		for (; *list; list++)
1306			if (!strncmp(cmd, *list, strlen(cmd)))
1307				return (*list);
1308	return (NULL);
1309}
1310
1311int
1312main(int argc, char *argv[])
1313{
1314	int	error = 0;
1315	int	ch;
1316	int	mode = O_RDONLY;
1317	int	opts = 0;
1318	char	anchorname[PF_ANCHOR_NAME_SIZE];
1319	char	rulesetname[PF_RULESET_NAME_SIZE];
1320
1321	if (argc < 2)
1322		usage();
1323
1324	while ((ch = getopt(argc, argv, "a:AdD:eqf:F:ghk:nNOrRs:t:T:vx:z")) !=
1325		-1) {
1326		switch (ch) {
1327		case 'a':
1328			anchoropt = optarg;
1329			break;
1330		case 'd':
1331			opts |= PF_OPT_DISABLE;
1332			mode = O_RDWR;
1333			break;
1334		case 'D':
1335			if (pfctl_cmdline_symset(optarg) < 0)
1336				warnx("could not parse macro definition %s",
1337				    optarg);
1338			break;
1339		case 'e':
1340			opts |= PF_OPT_ENABLE;
1341			mode = O_RDWR;
1342			break;
1343		case 'q':
1344			opts |= PF_OPT_QUIET;
1345			break;
1346		case 'F':
1347			clearopt = pfctl_lookup_option(optarg, clearopt_list);
1348			if (clearopt == NULL) {
1349				warnx("Unknown flush modifier '%s'", optarg);
1350				usage();
1351			}
1352			mode = O_RDWR;
1353			break;
1354		case 'k':
1355			if (state_killers >= 2) {
1356				warnx("can only specify -k twice");
1357				usage();
1358				/* NOTREACHED */
1359			}
1360			state_kill[state_killers++] = optarg;
1361			mode = O_RDWR;
1362			break;
1363		case 'n':
1364			opts |= PF_OPT_NOACTION;
1365			break;
1366		case 'N':
1367			loadopt |= PFCTL_FLAG_NAT;
1368			break;
1369		case 'r':
1370			opts |= PF_OPT_USEDNS;
1371			break;
1372		case 'f':
1373			rulesopt = optarg;
1374			mode = O_RDWR;
1375			break;
1376		case 'g':
1377			opts |= PF_OPT_DEBUG;
1378			break;
1379		case 'A':
1380			loadopt |= PFCTL_FLAG_ALTQ;
1381			break;
1382		case 'R':
1383			loadopt |= PFCTL_FLAG_FILTER;
1384			break;
1385		case 'O':
1386			loadopt |= PFCTL_FLAG_OPTION;
1387			break;
1388		case 's':
1389			showopt = pfctl_lookup_option(optarg, showopt_list);
1390			if (showopt == NULL) {
1391				warnx("Unknown show modifier '%s'", optarg);
1392				usage();
1393			}
1394			break;
1395		case 't':
1396			tableopt = optarg;
1397			break;
1398		case 'T':
1399			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
1400			if (tblcmdopt == NULL) {
1401				warnx("Unknown table command '%s'", optarg);
1402				usage();
1403			}
1404			break;
1405		case 'v':
1406			if (opts & PF_OPT_VERBOSE)
1407				opts |= PF_OPT_VERBOSE2;
1408			opts |= PF_OPT_VERBOSE;
1409			break;
1410		case 'x':
1411			debugopt = pfctl_lookup_option(optarg, debugopt_list);
1412			if (debugopt == NULL) {
1413				warnx("Unknown debug level '%s'", optarg);
1414				usage();
1415			}
1416			mode = O_RDWR;
1417			break;
1418		case 'z':
1419			opts |= PF_OPT_CLRRULECTRS;
1420			mode = O_RDWR;
1421			break;
1422		case 'h':
1423			/* FALLTHROUGH */
1424		default:
1425			usage();
1426			/* NOTREACHED */
1427		}
1428	}
1429
1430	if (tblcmdopt != NULL) {
1431		argc -= optind;
1432		argv += optind;
1433		ch = *tblcmdopt;
1434		if (ch == 'l') {
1435			loadopt |= PFCTL_FLAG_TABLE;
1436			tblcmdopt = NULL;
1437		} else {
1438			mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY;
1439			if (opts & PF_OPT_NOACTION) {
1440				dev = open("/dev/pf", mode);
1441				if (dev >= 0)
1442					opts |= PF_OPT_DUMMYACTION;
1443			}
1444		}
1445	} else if (argc != optind) {
1446		warnx("unknown command line argument: %s ...", argv[optind]);
1447		usage();
1448		/* NOTREACHED */
1449	}
1450	if (loadopt == 0)
1451		loadopt = ~0;
1452
1453	memset(anchorname, 0, sizeof(anchorname));
1454	memset(rulesetname, 0, sizeof(rulesetname));
1455	if (anchoropt != NULL) {
1456		char *t;
1457
1458		if ((t = strchr(anchoropt, ':')) == NULL) {
1459			if (strlcpy(anchorname, anchoropt,
1460			    sizeof(anchorname)) >= sizeof(anchorname))
1461				errx(1, "anchor name '%s' too long",
1462				    anchoropt);
1463		} else {
1464			char *p;
1465
1466			if ((p = strdup(anchoropt)) == NULL)
1467				err(1, "anchoropt: strdup");
1468			t = strsep(&p, ":");
1469			if (*t == '\0' || *p == '\0')
1470				errx(1, "anchor '%s' invalid", anchoropt);
1471			if (strlcpy(anchorname, t, sizeof(anchorname)) >=
1472			    sizeof(anchorname))
1473				errx(1, "anchor name '%s' too long", t);
1474			if (strlcpy(rulesetname, p, sizeof(rulesetname)) >=
1475			    sizeof(rulesetname))
1476				errx(1, "ruleset name '%s' too long", p);
1477			free(t); /* not p */
1478		}
1479		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
1480	}
1481
1482	if ((opts & PF_OPT_NOACTION) == 0) {
1483		dev = open("/dev/pf", mode);
1484		if (dev == -1)
1485			err(1, "/dev/pf");
1486		altqsupport = pfctl_test_altqsupport(dev, opts);
1487	} else {
1488		/* turn off options */
1489		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
1490		clearopt = showopt = debugopt = NULL;
1491#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
1492		altqsupport = 0;
1493#else
1494		altqsupport = 1;
1495#endif
1496	}
1497
1498	if (opts & PF_OPT_DISABLE)
1499		if (pfctl_disable(dev, opts))
1500			error = 1;
1501
1502	if (showopt != NULL) {
1503		switch (*showopt) {
1504		case 'A':
1505			pfctl_show_anchors(dev, opts, anchorname);
1506			break;
1507		case 'r':
1508			pfctl_load_fingerprints(dev, opts);
1509			pfctl_show_rules(dev, opts, 0, anchorname,
1510			    rulesetname);
1511			break;
1512		case 'l':
1513			pfctl_load_fingerprints(dev, opts);
1514			pfctl_show_rules(dev, opts, 1, anchorname,
1515			    rulesetname);
1516			break;
1517		case 'n':
1518			pfctl_load_fingerprints(dev, opts);
1519			pfctl_show_nat(dev, opts, anchorname, rulesetname);
1520			break;
1521		case 'q':
1522			pfctl_show_altq(dev, opts, opts & PF_OPT_VERBOSE2);
1523			break;
1524		case 's':
1525			pfctl_show_states(dev, 0, opts);
1526			break;
1527		case 'i':
1528			pfctl_show_status(dev);
1529			break;
1530		case 't':
1531			pfctl_show_timeouts(dev);
1532			break;
1533		case 'm':
1534			pfctl_show_limits(dev);
1535			break;
1536		case 'a':
1537			pfctl_load_fingerprints(dev, opts);
1538
1539			pfctl_show_rules(dev, opts, 0, anchorname,
1540			    rulesetname);
1541			pfctl_show_nat(dev, opts, anchorname, rulesetname);
1542			pfctl_show_altq(dev, opts, 0);
1543			pfctl_show_states(dev, 0, opts);
1544			pfctl_show_status(dev);
1545			pfctl_show_rules(dev, opts, 1, anchorname, rulesetname);
1546			pfctl_show_timeouts(dev);
1547			pfctl_show_limits(dev);
1548			pfctl_show_tables(anchorname, rulesetname, opts);
1549			pfctl_show_fingerprints(opts);
1550			break;
1551		case 'T':
1552			pfctl_show_tables(anchorname, rulesetname, opts);
1553			break;
1554		case 'o':
1555			pfctl_load_fingerprints(dev, opts);
1556			pfctl_show_fingerprints(opts);
1557			break;
1558		}
1559	}
1560
1561	if (clearopt != NULL) {
1562		switch (*clearopt) {
1563		case 'r':
1564			pfctl_clear_rules(dev, opts, anchorname, rulesetname);
1565			break;
1566		case 'n':
1567			pfctl_clear_nat(dev, opts, anchorname, rulesetname);
1568			break;
1569		case 'q':
1570			pfctl_clear_altq(dev, opts);
1571			break;
1572		case 's':
1573			pfctl_clear_states(dev, opts);
1574			break;
1575		case 'i':
1576			pfctl_clear_stats(dev, opts);
1577			break;
1578		case 'a':
1579			pfctl_clear_rules(dev, opts, anchorname, rulesetname);
1580			pfctl_clear_nat(dev, opts, anchorname, rulesetname);
1581			pfctl_clear_altq(dev, opts);
1582			pfctl_clear_states(dev, opts);
1583			pfctl_clear_stats(dev, opts);
1584			pfctl_clear_tables(anchorname, rulesetname, opts);
1585			pfctl_clear_fingerprints(dev, opts);
1586			break;
1587		case 'o':
1588			pfctl_clear_fingerprints(dev, opts);
1589			break;
1590		case 'T':
1591			pfctl_clear_tables(anchorname, rulesetname, opts);
1592			break;
1593		}
1594	}
1595	if (state_killers)
1596		pfctl_kill_states(dev, opts);
1597
1598	if (tblcmdopt != NULL) {
1599		error = pfctl_command_tables(argc, argv, tableopt,
1600		    tblcmdopt, rulesopt, anchorname, rulesetname, opts);
1601		rulesopt = NULL;
1602	}
1603
1604	if (rulesopt != NULL)
1605		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
1606			error = 1;
1607
1608	if (rulesopt != NULL) {
1609		if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname))
1610			error = 1;
1611		else if (!(opts & PF_OPT_NOACTION) &&
1612		    (loadopt & PFCTL_FLAG_TABLE))
1613			warn_namespace_collision(NULL);
1614	}
1615
1616	if (opts & PF_OPT_ENABLE)
1617		if (pfctl_enable(dev, opts))
1618			error = 1;
1619
1620	if (debugopt != NULL) {
1621		switch (*debugopt) {
1622		case 'n':
1623			pfctl_debug(dev, PF_DEBUG_NONE, opts);
1624			break;
1625		case 'u':
1626			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
1627			break;
1628		case 'm':
1629			pfctl_debug(dev, PF_DEBUG_MISC, opts);
1630			break;
1631		case 'l':
1632			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
1633			break;
1634		}
1635	}
1636
1637	if (opts & PF_OPT_CLRRULECTRS) {
1638		if (pfctl_clear_rule_counters(dev, opts))
1639			error = 1;
1640	}
1641	exit(error);
1642}
1643