pfctl.c revision 145840
1/*	$OpenBSD: pfctl.c,v 1.234 2005/03/07 13:52:50 henning Exp $ */
2
3/*
4 * Copyright (c) 2001 Daniel Hartmeier
5 * Copyright (c) 2002,2003 Henning Brauer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 *    - Redistributions of source code must retain the above copyright
13 *      notice, this list of conditions and the following disclaimer.
14 *    - Redistributions in binary form must reproduce the above
15 *      copyright notice, this list of conditions and the following
16 *      disclaimer in the documentation and/or other materials provided
17 *      with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/contrib/pf/pfctl/pfctl.c 145840 2005-05-03 16:55:20Z mlaier $");
36
37#include <sys/types.h>
38#include <sys/ioctl.h>
39#include <sys/socket.h>
40#include <sys/stat.h>
41
42#include <net/if.h>
43#include <netinet/in.h>
44#include <net/pfvar.h>
45#include <arpa/inet.h>
46#include <altq/altq.h>
47
48#include <err.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <limits.h>
52#include <netdb.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58#include "pfctl_parser.h"
59#include "pfctl.h"
60
61#ifdef __FreeBSD__
62#define HTONL(x)	(x) = htonl((__uint32_t)(x))
63#endif
64
65void	 usage(void);
66int	 pfctl_enable(int, int);
67int	 pfctl_disable(int, int);
68int	 pfctl_clear_stats(int, int);
69int	 pfctl_clear_interface_flags(int, int);
70int	 pfctl_clear_rules(int, int, char *);
71int	 pfctl_clear_nat(int, int, char *);
72int	 pfctl_clear_altq(int, int);
73int	 pfctl_clear_src_nodes(int, int);
74int	 pfctl_clear_states(int, const char *, int);
75int	 pfctl_kill_states(int, const char *, int);
76void	 pfctl_init_options(struct pfctl *);
77int	 pfctl_load_options(struct pfctl *);
78int	 pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
79int	 pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
80int	 pfctl_load_debug(struct pfctl *, unsigned int);
81int	 pfctl_load_logif(struct pfctl *, char *);
82int	 pfctl_load_hostid(struct pfctl *, unsigned int);
83int	 pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
84	    char *);
85void	 pfctl_print_rule_counters(struct pf_rule *, int);
86int	 pfctl_show_rules(int, int, int, char *);
87int	 pfctl_show_nat(int, int, char *);
88int	 pfctl_show_src_nodes(int, int);
89int	 pfctl_show_states(int, const char *, int);
90int	 pfctl_show_status(int, int);
91int	 pfctl_show_timeouts(int, int);
92int	 pfctl_show_limits(int, int);
93void	 pfctl_debug(int, u_int32_t, int);
94int	 pfctl_clear_rule_counters(int, int);
95int	 pfctl_test_altqsupport(int, int);
96int	 pfctl_show_anchors(int, int, char *);
97const char	*pfctl_lookup_option(char *, const char **);
98
99const char	*clearopt;
100char		*rulesopt;
101const char	*showopt;
102const char	*debugopt;
103char		*anchoropt;
104char		*pf_device = "/dev/pf";
105char		*ifaceopt;
106char		*tableopt;
107const char	*tblcmdopt;
108int		 state_killers;
109char		*state_kill[2];
110int		 loadopt;
111int		 altqsupport;
112
113int		 dev = -1;
114int		 first_title = 1;
115int		 labels = 0;
116
117const char	*infile;
118
119static const struct {
120	const char	*name;
121	int		index;
122} pf_limits[] = {
123	{ "states",	PF_LIMIT_STATES },
124	{ "src-nodes",	PF_LIMIT_SRC_NODES },
125	{ "frags",	PF_LIMIT_FRAGS },
126	{ NULL,		0 }
127};
128
129struct pf_hint {
130	const char	*name;
131	int		timeout;
132};
133static const struct pf_hint pf_hint_normal[] = {
134	{ "tcp.first",		2 * 60 },
135	{ "tcp.opening",	30 },
136	{ "tcp.established",	24 * 60 * 60 },
137	{ "tcp.closing",	15 * 60 },
138	{ "tcp.finwait",	45 },
139	{ "tcp.closed",		90 },
140	{ "tcp.tsdiff",		30 },
141	{ NULL,			0 }
142};
143static const struct pf_hint pf_hint_satellite[] = {
144	{ "tcp.first",		3 * 60 },
145	{ "tcp.opening",	30 + 5 },
146	{ "tcp.established",	24 * 60 * 60 },
147	{ "tcp.closing",	15 * 60 + 5 },
148	{ "tcp.finwait",	45 + 5 },
149	{ "tcp.closed",		90 + 5 },
150	{ "tcp.tsdiff",		60 },
151	{ NULL,			0 }
152};
153static const struct pf_hint pf_hint_conservative[] = {
154	{ "tcp.first",		60 * 60 },
155	{ "tcp.opening",	15 * 60 },
156	{ "tcp.established",	5 * 24 * 60 * 60 },
157	{ "tcp.closing",	60 * 60 },
158	{ "tcp.finwait",	10 * 60 },
159	{ "tcp.closed",		3 * 60 },
160	{ "tcp.tsdiff",		60 },
161	{ NULL,			0 }
162};
163static const struct pf_hint pf_hint_aggressive[] = {
164	{ "tcp.first",		30 },
165	{ "tcp.opening",	5 },
166	{ "tcp.established",	5 * 60 * 60 },
167	{ "tcp.closing",	60 },
168	{ "tcp.finwait",	30 },
169	{ "tcp.closed",		30 },
170	{ "tcp.tsdiff",		10 },
171	{ NULL,			0 }
172};
173
174static const struct {
175	const char *name;
176	const struct pf_hint *hint;
177} pf_hints[] = {
178	{ "normal",		pf_hint_normal },
179	{ "satellite",		pf_hint_satellite },
180	{ "high-latency",	pf_hint_satellite },
181	{ "conservative",	pf_hint_conservative },
182	{ "aggressive",		pf_hint_aggressive },
183	{ NULL,			NULL }
184};
185
186static const char *clearopt_list[] = {
187	"nat", "queue", "rules", "Sources",
188	"state", "info", "Tables", "osfp", "all", NULL
189};
190
191static const char *showopt_list[] = {
192	"nat", "queue", "rules", "Anchors", "Sources", "state", "info",
193	"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
194	"all", NULL
195};
196
197static const char *tblcmdopt_list[] = {
198	"kill", "flush", "add", "delete", "load", "replace", "show",
199	"test", "zero", NULL
200};
201
202static const char *debugopt_list[] = {
203	"none", "urgent", "misc", "loud", NULL
204};
205
206
207void
208usage(void)
209{
210	extern char *__progname;
211
212	fprintf(stderr, "usage: %s [-AdeghmNnOoqRrvz] ", __progname);
213	fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
214	fprintf(stderr, "             ");
215	fprintf(stderr, "[-f file] [-i interface] [-k host] ");
216	fprintf(stderr, "[-p device] [-s modifier]\n");
217	fprintf(stderr, "             ");
218	fprintf(stderr, "[-t table -T command [address ...]] ");
219	fprintf(stderr, "[-x level]\n");
220	exit(1);
221}
222
223int
224pfctl_enable(int dev, int opts)
225{
226	if (ioctl(dev, DIOCSTART)) {
227		if (errno == EEXIST)
228			errx(1, "pf already enabled");
229#ifdef __FreeBSD__
230		else if (errno == ESRCH)
231			errx(1, "pfil registeration failed");
232#endif
233		else
234			err(1, "DIOCSTART");
235	}
236	if ((opts & PF_OPT_QUIET) == 0)
237		fprintf(stderr, "pf enabled\n");
238
239	if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
240		if (errno != EEXIST)
241			err(1, "DIOCSTARTALTQ");
242
243	return (0);
244}
245
246int
247pfctl_disable(int dev, int opts)
248{
249	if (ioctl(dev, DIOCSTOP)) {
250		if (errno == ENOENT)
251			errx(1, "pf not enabled");
252		else
253			err(1, "DIOCSTOP");
254	}
255	if ((opts & PF_OPT_QUIET) == 0)
256		fprintf(stderr, "pf disabled\n");
257
258	if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
259			if (errno != ENOENT)
260				err(1, "DIOCSTOPALTQ");
261
262	return (0);
263}
264
265int
266pfctl_clear_stats(int dev, int opts)
267{
268	if (ioctl(dev, DIOCCLRSTATUS))
269		err(1, "DIOCCLRSTATUS");
270	if ((opts & PF_OPT_QUIET) == 0)
271		fprintf(stderr, "pf: statistics cleared\n");
272	return (0);
273}
274
275int
276pfctl_clear_interface_flags(int dev, int opts)
277{
278	struct pfioc_iface	pi;
279
280	if ((opts & PF_OPT_NOACTION) == 0) {
281		bzero(&pi, sizeof(pi));
282		pi.pfiio_flags = PFI_IFLAG_SETABLE_MASK;
283
284		if (ioctl(dev, DIOCCLRIFFLAG, &pi))
285			err(1, "DIOCCLRIFFLAG");
286		if ((opts & PF_OPT_QUIET) == 0)
287			fprintf(stderr, "pf: interface flags reset\n");
288	}
289	return (0);
290}
291
292int
293pfctl_clear_rules(int dev, int opts, char *anchorname)
294{
295	struct pfr_buffer t;
296
297	memset(&t, 0, sizeof(t));
298	t.pfrb_type = PFRB_TRANS;
299	if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
300	    pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
301	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
302	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
303		err(1, "pfctl_clear_rules");
304	if ((opts & PF_OPT_QUIET) == 0)
305		fprintf(stderr, "rules cleared\n");
306	return (0);
307}
308
309int
310pfctl_clear_nat(int dev, int opts, char *anchorname)
311{
312	struct pfr_buffer t;
313
314	memset(&t, 0, sizeof(t));
315	t.pfrb_type = PFRB_TRANS;
316	if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
317	    pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
318	    pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
319	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
320	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
321		err(1, "pfctl_clear_nat");
322	if ((opts & PF_OPT_QUIET) == 0)
323		fprintf(stderr, "nat cleared\n");
324	return (0);
325}
326
327int
328pfctl_clear_altq(int dev, int opts)
329{
330	struct pfr_buffer t;
331
332	if (!altqsupport)
333		return (-1);
334	memset(&t, 0, sizeof(t));
335	t.pfrb_type = PFRB_TRANS;
336	if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
337	    pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
338	    pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
339		err(1, "pfctl_clear_altq");
340	if ((opts & PF_OPT_QUIET) == 0)
341		fprintf(stderr, "altq cleared\n");
342	return (0);
343}
344
345int
346pfctl_clear_src_nodes(int dev, int opts)
347{
348	if (ioctl(dev, DIOCCLRSRCNODES))
349		err(1, "DIOCCLRSRCNODES");
350	if ((opts & PF_OPT_QUIET) == 0)
351		fprintf(stderr, "source tracking entries cleared\n");
352	return (0);
353}
354
355int
356pfctl_clear_states(int dev, const char *iface, int opts)
357{
358	struct pfioc_state_kill psk;
359
360	memset(&psk, 0, sizeof(psk));
361	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
362	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
363		errx(1, "invalid interface: %s", iface);
364
365	if (ioctl(dev, DIOCCLRSTATES, &psk))
366		err(1, "DIOCCLRSTATES");
367	if ((opts & PF_OPT_QUIET) == 0)
368		fprintf(stderr, "%d states cleared\n", psk.psk_af);
369	return (0);
370}
371
372int
373pfctl_kill_states(int dev, const char *iface, int opts)
374{
375	struct pfioc_state_kill psk;
376	struct addrinfo *res[2], *resp[2];
377	struct sockaddr last_src, last_dst;
378	int killed, sources, dests;
379	int ret_ga;
380
381	killed = sources = dests = 0;
382
383	memset(&psk, 0, sizeof(psk));
384	memset(&psk.psk_src.addr.v.a.mask, 0xff,
385	    sizeof(psk.psk_src.addr.v.a.mask));
386	memset(&last_src, 0xff, sizeof(last_src));
387	memset(&last_dst, 0xff, sizeof(last_dst));
388	if (iface != NULL && strlcpy(psk.psk_ifname, iface,
389	    sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
390		errx(1, "invalid interface: %s", iface);
391
392	if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
393		errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
394		/* NOTREACHED */
395	}
396	for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
397		if (resp[0]->ai_addr == NULL)
398			continue;
399		/* We get lots of duplicates.  Catch the easy ones */
400		if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
401			continue;
402		last_src = *(struct sockaddr *)resp[0]->ai_addr;
403
404		psk.psk_af = resp[0]->ai_family;
405		sources++;
406
407		if (psk.psk_af == AF_INET)
408			psk.psk_src.addr.v.a.addr.v4 =
409			    ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
410		else if (psk.psk_af == AF_INET6)
411			psk.psk_src.addr.v.a.addr.v6 =
412			    ((struct sockaddr_in6 *)resp[0]->ai_addr)->
413			    sin6_addr;
414		else
415			errx(1, "Unknown address family %d", psk.psk_af);
416
417		if (state_killers > 1) {
418			dests = 0;
419			memset(&psk.psk_dst.addr.v.a.mask, 0xff,
420			    sizeof(psk.psk_dst.addr.v.a.mask));
421			memset(&last_dst, 0xff, sizeof(last_dst));
422			if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
423			    &res[1]))) {
424				errx(1, "getaddrinfo: %s",
425				    gai_strerror(ret_ga));
426				/* NOTREACHED */
427			}
428			for (resp[1] = res[1]; resp[1];
429			    resp[1] = resp[1]->ai_next) {
430				if (resp[1]->ai_addr == NULL)
431					continue;
432				if (psk.psk_af != resp[1]->ai_family)
433					continue;
434
435				if (memcmp(&last_dst, resp[1]->ai_addr,
436				    sizeof(last_dst)) == 0)
437					continue;
438				last_dst = *(struct sockaddr *)resp[1]->ai_addr;
439
440				dests++;
441
442				if (psk.psk_af == AF_INET)
443					psk.psk_dst.addr.v.a.addr.v4 =
444					    ((struct sockaddr_in *)resp[1]->
445					    ai_addr)->sin_addr;
446				else if (psk.psk_af == AF_INET6)
447					psk.psk_dst.addr.v.a.addr.v6 =
448					    ((struct sockaddr_in6 *)resp[1]->
449					    ai_addr)->sin6_addr;
450				else
451					errx(1, "Unknown address family %d",
452					    psk.psk_af);
453
454				if (ioctl(dev, DIOCKILLSTATES, &psk))
455					err(1, "DIOCKILLSTATES");
456				killed += psk.psk_af;
457				/* fixup psk.psk_af */
458				psk.psk_af = resp[1]->ai_family;
459			}
460			freeaddrinfo(res[1]);
461		} else {
462			if (ioctl(dev, DIOCKILLSTATES, &psk))
463				err(1, "DIOCKILLSTATES");
464			killed += psk.psk_af;
465			/* fixup psk.psk_af */
466			psk.psk_af = res[0]->ai_family;
467		}
468	}
469
470	freeaddrinfo(res[0]);
471
472	if ((opts & PF_OPT_QUIET) == 0)
473		fprintf(stderr, "killed %d states from %d sources and %d "
474		    "destinations\n", killed, sources, dests);
475	return (0);
476}
477
478int
479pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
480    u_int32_t ticket, int r_action, char *anchorname)
481{
482	struct pfioc_pooladdr pp;
483	struct pf_pooladdr *pa;
484	u_int32_t pnr, mpnr;
485
486	memset(&pp, 0, sizeof(pp));
487	memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
488	pp.r_action = r_action;
489	pp.r_num = nr;
490	pp.ticket = ticket;
491	if (ioctl(dev, DIOCGETADDRS, &pp)) {
492		warn("DIOCGETADDRS");
493		return (-1);
494	}
495	mpnr = pp.nr;
496	TAILQ_INIT(&pool->list);
497	for (pnr = 0; pnr < mpnr; ++pnr) {
498		pp.nr = pnr;
499		if (ioctl(dev, DIOCGETADDR, &pp)) {
500			warn("DIOCGETADDR");
501			return (-1);
502		}
503		pa = calloc(1, sizeof(struct pf_pooladdr));
504		if (pa == NULL)
505			err(1, "calloc");
506		bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
507		TAILQ_INSERT_TAIL(&pool->list, pa, entries);
508	}
509
510	return (0);
511}
512
513void
514pfctl_clear_pool(struct pf_pool *pool)
515{
516	struct pf_pooladdr *pa;
517
518	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
519		TAILQ_REMOVE(&pool->list, pa, entries);
520		free(pa);
521	}
522}
523
524void
525pfctl_print_rule_counters(struct pf_rule *rule, int opts)
526{
527	if (opts & PF_OPT_DEBUG) {
528		const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
529		    "p", "sa", "sp", "da", "dp" };
530		int i;
531
532		printf("  [ Skip steps: ");
533		for (i = 0; i < PF_SKIP_COUNT; ++i) {
534			if (rule->skip[i].nr == rule->nr + 1)
535				continue;
536			printf("%s=", t[i]);
537			if (rule->skip[i].nr == -1)
538				printf("end ");
539			else
540				printf("%u ", rule->skip[i].nr);
541		}
542		printf("]\n");
543
544		printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
545		    rule->qname, rule->qid, rule->pqname, rule->pqid);
546	}
547	if (opts & PF_OPT_VERBOSE)
548		printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
549			    "Bytes: %-10llu  States: %-6u]\n",
550			    (unsigned long long)rule->evaluations,
551			    (unsigned long long)rule->packets,
552			    (unsigned long long)rule->bytes, rule->states);
553}
554
555void
556pfctl_print_title(char *title)
557{
558	if (!first_title)
559		printf("\n");
560	first_title = 0;
561	printf("%s\n", title);
562}
563
564int
565pfctl_show_rules(int dev, int opts, int format, char *anchorname)
566{
567	struct pfioc_rule pr;
568	u_int32_t nr, mnr, header = 0;
569	int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
570
571	memset(&pr, 0, sizeof(pr));
572	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
573	if (opts & PF_OPT_SHOWALL) {
574		pr.rule.action = PF_PASS;
575		if (ioctl(dev, DIOCGETRULES, &pr)) {
576			warn("DIOCGETRULES");
577			return (-1);
578		}
579		header++;
580	}
581	pr.rule.action = PF_SCRUB;
582	if (ioctl(dev, DIOCGETRULES, &pr)) {
583		warn("DIOCGETRULES");
584		return (-1);
585	}
586	if (opts & PF_OPT_SHOWALL) {
587		if (format == 0 && (pr.nr > 0 || header))
588			pfctl_print_title("FILTER RULES:");
589		else if (format == 1 && labels)
590			pfctl_print_title("LABEL COUNTERS:");
591	}
592	mnr = pr.nr;
593	for (nr = 0; nr < mnr; ++nr) {
594		pr.nr = nr;
595		if (ioctl(dev, DIOCGETRULE, &pr)) {
596			warn("DIOCGETRULE");
597			return (-1);
598		}
599
600		if (pfctl_get_pool(dev, &pr.rule.rpool,
601		    nr, pr.ticket, PF_SCRUB, anchorname) != 0)
602			return (-1);
603
604		switch (format) {
605		case 1:
606			if (pr.rule.label[0]) {
607				printf("%s ", pr.rule.label);
608				printf("%llu %llu %llu\n",
609				    (unsigned long long)pr.rule.evaluations,
610				    (unsigned long long)pr.rule.packets,
611				    (unsigned long long)pr.rule.bytes);
612			}
613			break;
614		default:
615			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
616				labels = 1;
617			print_rule(&pr.rule, pr.anchor_call, rule_numbers);
618			pfctl_print_rule_counters(&pr.rule, opts);
619		}
620		pfctl_clear_pool(&pr.rule.rpool);
621	}
622	pr.rule.action = PF_PASS;
623	if (ioctl(dev, DIOCGETRULES, &pr)) {
624		warn("DIOCGETRULES");
625		return (-1);
626	}
627	mnr = pr.nr;
628	for (nr = 0; nr < mnr; ++nr) {
629		pr.nr = nr;
630		if (ioctl(dev, DIOCGETRULE, &pr)) {
631			warn("DIOCGETRULE");
632			return (-1);
633		}
634
635		if (pfctl_get_pool(dev, &pr.rule.rpool,
636		    nr, pr.ticket, PF_PASS, anchorname) != 0)
637			return (-1);
638
639		switch (format) {
640		case 1:
641			if (pr.rule.label[0]) {
642				printf("%s ", pr.rule.label);
643				printf("%llu %llu %llu\n",
644				    (unsigned long long)pr.rule.evaluations,
645				    (unsigned long long)pr.rule.packets,
646				    (unsigned long long)pr.rule.bytes);
647			}
648			break;
649		default:
650			if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
651				labels = 1;
652			print_rule(&pr.rule, pr.anchor_call, rule_numbers);
653			pfctl_print_rule_counters(&pr.rule, opts);
654		}
655		pfctl_clear_pool(&pr.rule.rpool);
656	}
657	return (0);
658}
659
660int
661pfctl_show_nat(int dev, int opts, char *anchorname)
662{
663	struct pfioc_rule pr;
664	u_int32_t mnr, nr;
665	static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
666	int i, dotitle = opts & PF_OPT_SHOWALL;
667
668	memset(&pr, 0, sizeof(pr));
669	memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
670	for (i = 0; i < 3; i++) {
671		pr.rule.action = nattype[i];
672		if (ioctl(dev, DIOCGETRULES, &pr)) {
673			warn("DIOCGETRULES");
674			return (-1);
675		}
676		mnr = pr.nr;
677		for (nr = 0; nr < mnr; ++nr) {
678			pr.nr = nr;
679			if (ioctl(dev, DIOCGETRULE, &pr)) {
680				warn("DIOCGETRULE");
681				return (-1);
682			}
683			if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
684			    pr.ticket, nattype[i], anchorname) != 0)
685				return (-1);
686			if (dotitle) {
687				pfctl_print_title("TRANSLATION RULES:");
688				dotitle = 0;
689			}
690			print_rule(&pr.rule, pr.anchor_call,
691			    opts & PF_OPT_VERBOSE2);
692			pfctl_print_rule_counters(&pr.rule, opts);
693			pfctl_clear_pool(&pr.rule.rpool);
694		}
695	}
696	return (0);
697}
698
699int
700pfctl_show_src_nodes(int dev, int opts)
701{
702	struct pfioc_src_nodes psn;
703	struct pf_src_node *p;
704	char *inbuf = NULL, *newinbuf = NULL;
705	unsigned len = 0;
706	int i;
707
708	memset(&psn, 0, sizeof(psn));
709	for (;;) {
710		psn.psn_len = len;
711		if (len) {
712			newinbuf = realloc(inbuf, len);
713			if (newinbuf == NULL)
714				err(1, "realloc");
715			psn.psn_buf = inbuf = newinbuf;
716		}
717		if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
718			warn("DIOCGETSRCNODES");
719			return (-1);
720		}
721		if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
722			break;
723		if (len == 0 && psn.psn_len == 0)
724			return (0);
725		if (len == 0 && psn.psn_len != 0)
726			len = psn.psn_len;
727		if (psn.psn_len == 0)
728			return (0);	/* no src_nodes */
729		len *= 2;
730	}
731	p = psn.psn_src_nodes;
732	if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
733		pfctl_print_title("SOURCE TRACKING NODES:");
734	for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
735		print_src_node(p, opts);
736		p++;
737	}
738	return (0);
739}
740
741int
742pfctl_show_states(int dev, const char *iface, int opts)
743{
744	struct pfioc_states ps;
745	struct pf_state *p;
746	char *inbuf = NULL, *newinbuf = NULL;
747	unsigned len = 0;
748	int i, dotitle = (opts & PF_OPT_SHOWALL);
749
750	memset(&ps, 0, sizeof(ps));
751	for (;;) {
752		ps.ps_len = len;
753		if (len) {
754			newinbuf = realloc(inbuf, len);
755			if (newinbuf == NULL)
756				err(1, "realloc");
757			ps.ps_buf = inbuf = newinbuf;
758		}
759		if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
760			warn("DIOCGETSTATES");
761			return (-1);
762		}
763		if (ps.ps_len + sizeof(struct pfioc_states) < len)
764			break;
765		if (len == 0 && ps.ps_len == 0)
766			return (0);
767		if (len == 0 && ps.ps_len != 0)
768			len = ps.ps_len;
769		if (ps.ps_len == 0)
770			return (0);	/* no states */
771		len *= 2;
772	}
773	p = ps.ps_states;
774	for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
775		if (iface != NULL && strcmp(p->u.ifname, iface))
776			continue;
777		if (dotitle) {
778			pfctl_print_title("STATES:");
779			dotitle = 0;
780		}
781		print_state(p, opts);
782	}
783	return (0);
784}
785
786int
787pfctl_show_status(int dev, int opts)
788{
789	struct pf_status status;
790
791	if (ioctl(dev, DIOCGETSTATUS, &status)) {
792		warn("DIOCGETSTATUS");
793		return (-1);
794	}
795	if (opts & PF_OPT_SHOWALL)
796		pfctl_print_title("INFO:");
797	print_status(&status, opts);
798	return (0);
799}
800
801int
802pfctl_show_timeouts(int dev, int opts)
803{
804	struct pfioc_tm pt;
805	int i;
806
807	if (opts & PF_OPT_SHOWALL)
808		pfctl_print_title("TIMEOUTS:");
809	memset(&pt, 0, sizeof(pt));
810	for (i = 0; pf_timeouts[i].name; i++) {
811		pt.timeout = pf_timeouts[i].timeout;
812		if (ioctl(dev, DIOCGETTIMEOUT, &pt))
813			err(1, "DIOCGETTIMEOUT");
814		printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
815		if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
816		    pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
817			printf(" states");
818		else
819			printf("s");
820		printf("\n");
821	}
822	return (0);
823
824}
825
826int
827pfctl_show_limits(int dev, int opts)
828{
829	struct pfioc_limit pl;
830	int i;
831
832	if (opts & PF_OPT_SHOWALL)
833		pfctl_print_title("LIMITS:");
834	memset(&pl, 0, sizeof(pl));
835	for (i = 0; pf_limits[i].name; i++) {
836		pl.index = pf_limits[i].index;
837		if (ioctl(dev, DIOCGETLIMIT, &pl))
838			err(1, "DIOCGETLIMIT");
839		printf("%-10s ", pf_limits[i].name);
840		if (pl.limit == UINT_MAX)
841			printf("unlimited\n");
842		else
843			printf("hard limit %6u\n", pl.limit);
844	}
845	return (0);
846}
847
848/* callbacks for rule/nat/rdr/addr */
849int
850pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
851{
852	struct pf_pooladdr *pa;
853
854	if ((pf->opts & PF_OPT_NOACTION) == 0) {
855		if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
856			err(1, "DIOCBEGINADDRS");
857	}
858
859	pf->paddr.af = af;
860	TAILQ_FOREACH(pa, &p->list, entries) {
861		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
862		if ((pf->opts & PF_OPT_NOACTION) == 0) {
863			if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
864				err(1, "DIOCADDADDR");
865		}
866	}
867	return (0);
868}
869
870int
871pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
872{
873	u_int8_t		rs_num;
874	struct pfioc_rule	pr;
875
876	switch (r->action) {
877	case PF_SCRUB:
878	case PF_NOSCRUB:
879		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
880			return (0);
881		rs_num = PF_RULESET_SCRUB;
882		break;
883	case PF_DROP:
884	case PF_PASS:
885		if ((loadopt & PFCTL_FLAG_FILTER) == 0)
886			return (0);
887		rs_num = PF_RULESET_FILTER;
888		break;
889	case PF_NAT:
890	case PF_NONAT:
891		if ((loadopt & PFCTL_FLAG_NAT) == 0)
892			return (0);
893		rs_num = PF_RULESET_NAT;
894		break;
895	case PF_RDR:
896	case PF_NORDR:
897		if ((loadopt & PFCTL_FLAG_NAT) == 0)
898			return (0);
899		rs_num = PF_RULESET_RDR;
900		break;
901	case PF_BINAT:
902	case PF_NOBINAT:
903		if ((loadopt & PFCTL_FLAG_NAT) == 0)
904			return (0);
905		rs_num = PF_RULESET_BINAT;
906		break;
907	default:
908		errx(1, "Invalid rule type %d", r->action);
909		break;
910	}
911
912
913	if ((pf->opts & PF_OPT_OPTIMIZE) && rs_num == PF_RULESET_FILTER) {
914		/*
915		 * We'll do an optimization post-pass before finally adding the
916		 * rules.  Then we'll disable the optimization flag and feed
917		 * the rules right back into this function.
918		 */
919		struct pf_opt_rule *pfr;
920		struct pf_pooladdr *pa;
921
922		if ((pfr = calloc(1, sizeof(*pfr))) == NULL)
923			err(1, "calloc");
924		memcpy(&pfr->por_rule, r, sizeof(*r));
925		if (strlcpy(pfr->por_anchor, anchor_call,
926		    sizeof(pfr->por_anchor)) >= sizeof(pfr->por_anchor))
927			errx(1, "pfctl_add_rule: strlcpy");
928		TAILQ_INSERT_TAIL(&pf->opt_queue, pfr, por_entry);
929
930		if (TAILQ_FIRST(&r->rpool.list) != NULL)  {
931			TAILQ_INIT(&pfr->por_rule.rpool.list);
932			while ((pa = TAILQ_FIRST(&r->rpool.list)) != NULL) {
933				TAILQ_REMOVE(&r->rpool.list, pa, entries);
934				TAILQ_INSERT_TAIL(&pfr->por_rule.rpool.list, pa,
935			    	entries);
936			}
937		} else {
938			memset(&pfr->por_rule.rpool, 0,
939			    sizeof(pfr->por_rule.rpool));
940
941		}
942		return (0);
943	}
944
945	if ((pf->opts & PF_OPT_NOACTION) == 0) {
946		bzero(&pr, sizeof(pr));
947		if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >=
948		    sizeof(pr.anchor))
949			errx(1, "pfctl_add_rule: strlcpy");
950		if (pfctl_add_pool(pf, &r->rpool, r->af))
951			return (1);
952		pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor);
953		pr.pool_ticket = pf->paddr.ticket;
954		memcpy(&pr.rule, r, sizeof(pr.rule));
955		strlcpy(pr.anchor_call, anchor_call, sizeof(pr.anchor_call));
956		if (ioctl(pf->dev, DIOCADDRULE, &pr))
957			err(1, "DIOCADDRULE");
958	}
959	if (pf->opts & PF_OPT_VERBOSE)
960		print_rule(r, anchor_call, pf->opts & PF_OPT_VERBOSE2);
961	pfctl_clear_pool(&r->rpool);
962	return (0);
963}
964
965int
966pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
967{
968	if (altqsupport &&
969	    (loadopt & PFCTL_FLAG_ALTQ) != 0) {
970		memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
971		if ((pf->opts & PF_OPT_NOACTION) == 0) {
972			if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
973				if (errno == ENXIO)
974					errx(1, "qtype not configured");
975				else if (errno == ENODEV)
976					errx(1, "%s: driver does not support "
977					    "altq", a->ifname);
978				else
979					err(1, "DIOCADDALTQ");
980			}
981		}
982		pfaltq_store(&pf->paltq->altq);
983	}
984	return (0);
985}
986
987int
988pfctl_rules(int dev, char *filename, int opts, char *anchorname,
989    struct pfr_buffer *trans)
990{
991#define ERR(x) do { warn(x); goto _error; } while(0)
992#define ERRX(x) do { warnx(x); goto _error; } while(0)
993
994	FILE			*fin;
995	struct pfr_buffer	*t, buf;
996	struct pfioc_altq	 pa;
997	struct pfctl		 pf;
998	struct pfr_table	 trs;
999	int			 osize;
1000
1001	if (trans == NULL) {
1002	    bzero(&buf, sizeof(buf));
1003	    buf.pfrb_type = PFRB_TRANS;
1004	    t = &buf;
1005	    osize = 0;
1006	} else {
1007	    t = trans;
1008	    osize = t->pfrb_size;
1009	}
1010
1011	memset(&pa, 0, sizeof(pa));
1012	memset(&pf, 0, sizeof(pf));
1013	memset(&trs, 0, sizeof(trs));
1014	if (strlcpy(trs.pfrt_anchor, anchorname,
1015	    sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1016		ERRX("pfctl_rules: strlcpy");
1017	if (strcmp(filename, "-") == 0) {
1018		fin = stdin;
1019		infile = "stdin";
1020	} else {
1021		if ((fin = pfctl_fopen(filename, "r")) == NULL) {
1022			warn("%s", filename);
1023			return (1);
1024		}
1025		infile = filename;
1026	}
1027	pf.dev = dev;
1028	pf.opts = opts;
1029	pf.loadopt = loadopt;
1030	if (anchorname[0])
1031		pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1032	pf.paltq = &pa;
1033	pf.trans = t;
1034	pf.rule_nr = 0;
1035	pf.anchor = anchorname;
1036	TAILQ_INIT(&pf.opt_queue);
1037	pfctl_init_options(&pf);
1038
1039	if ((opts & PF_OPT_NOACTION) == 0) {
1040		if ((pf.loadopt & PFCTL_FLAG_NAT) != 0) {
1041			if (pfctl_add_trans(t, PF_RULESET_NAT, anchorname) ||
1042			    pfctl_add_trans(t, PF_RULESET_BINAT, anchorname) ||
1043			    pfctl_add_trans(t, PF_RULESET_RDR, anchorname))
1044				ERR("pfctl_rules");
1045		}
1046		if (((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1047			if (pfctl_add_trans(t, PF_RULESET_ALTQ, anchorname))
1048				ERR("pfctl_rules");
1049		}
1050		if ((pf.loadopt & PFCTL_FLAG_FILTER) != 0) {
1051			if (pfctl_add_trans(t, PF_RULESET_SCRUB, anchorname) ||
1052			    pfctl_add_trans(t, PF_RULESET_FILTER, anchorname))
1053				ERR("pfctl_rules");
1054		}
1055		if (pf.loadopt & PFCTL_FLAG_TABLE) {
1056			if (pfctl_add_trans(t, PF_RULESET_TABLE, anchorname))
1057				ERR("pfctl_rules");
1058		}
1059		if (pfctl_trans(dev, t, DIOCXBEGIN, osize))
1060			ERR("DIOCXBEGIN");
1061		if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1062			pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ,
1063			    anchorname);
1064		if (pf.loadopt & PFCTL_FLAG_TABLE)
1065			pf.tticket = pfctl_get_ticket(t, PF_RULESET_TABLE,
1066			    anchorname);
1067	}
1068	if (parse_rules(fin, &pf) < 0) {
1069		if ((opts & PF_OPT_NOACTION) == 0)
1070			ERRX("Syntax error in config file: "
1071			    "pf rules not loaded");
1072		else
1073			goto _error;
1074	}
1075	if (pf.opts & PF_OPT_OPTIMIZE) {
1076		if (pfctl_optimize_rules(&pf))
1077			ERRX("Failed to optimize ruleset: pf rules not loaded");
1078	}
1079
1080	if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1081		if (check_commit_altq(dev, opts) != 0)
1082			ERRX("errors in altq config");
1083
1084	if (fin != stdin) {
1085		fclose(fin);
1086		fin = NULL;
1087	}
1088
1089	/* process "load anchor" directives */
1090	if (!anchorname[0])
1091		if (pfctl_load_anchors(dev, opts, t) == -1)
1092			ERRX("load anchors");
1093
1094	if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1095		if (!anchorname[0])
1096			if (pfctl_load_options(&pf))
1097				goto _error;
1098		if (pfctl_trans(dev, t, DIOCXCOMMIT, 0))
1099			ERR("DIOCXCOMMIT");
1100	}
1101	return (0);
1102
1103_error:
1104	if (trans == NULL) {	/* main ruleset */
1105		if ((opts & PF_OPT_NOACTION) == 0)
1106			if (pfctl_trans(dev, t, DIOCXROLLBACK, 0))
1107				err(1, "DIOCXROLLBACK");
1108		exit(1);
1109	} else {		/* sub ruleset */
1110		if (fin != NULL && fin != stdin)
1111			fclose(fin);
1112		return (-1);
1113	}
1114
1115#undef ERR
1116#undef ERRX
1117}
1118
1119FILE *
1120pfctl_fopen(const char *name, const char *mode)
1121{
1122	struct stat	 st;
1123	FILE		*fp;
1124
1125	fp = fopen(name, mode);
1126	if (fp == NULL)
1127		return (NULL);
1128	if (fstat(fileno(fp), &st)) {
1129		fclose(fp);
1130		return (NULL);
1131	}
1132	if (S_ISDIR(st.st_mode)) {
1133		fclose(fp);
1134		errno = EISDIR;
1135		return (NULL);
1136	}
1137	return (fp);
1138}
1139
1140void
1141pfctl_init_options(struct pfctl *pf)
1142{
1143	pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1144	pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1145	pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1146	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1147	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1148	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1149	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1150	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1151	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1152	pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1153	pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1154	pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1155	pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1156	pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1157	pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1158	pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1159	pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1160	pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1161
1162	pf->limit[PF_LIMIT_STATES]	= PFSTATE_HIWAT;
1163	pf->limit[PF_LIMIT_FRAGS]	= PFFRAG_FRENT_HIWAT;
1164	pf->limit[PF_LIMIT_SRC_NODES]	= PFSNODE_HIWAT;
1165
1166	pf->debug = PF_DEBUG_URGENT;
1167}
1168
1169int
1170pfctl_load_options(struct pfctl *pf)
1171{
1172	int i, error = 0;
1173
1174	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1175		return (0);
1176
1177	/* load limits */
1178	for (i = 0; i < PF_LIMIT_MAX; i++) {
1179		if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1180			continue;
1181		if (pfctl_load_limit(pf, i, pf->limit[i]))
1182			error = 1;
1183	}
1184
1185	/* load timeouts */
1186	for (i = 0; i < PFTM_MAX; i++) {
1187		if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1188			continue;
1189		if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1190			error = 1;
1191	}
1192
1193	/* load debug */
1194	if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1195		if (pfctl_load_debug(pf, pf->debug))
1196			error = 1;
1197
1198	/* load logif */
1199	if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1200		if (pfctl_load_logif(pf, pf->ifname))
1201			error = 1;
1202
1203	/* load hostid */
1204	if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1205		if (pfctl_load_hostid(pf, pf->hostid))
1206			error = 1;
1207
1208	return (error);
1209}
1210
1211int
1212pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1213{
1214	int i;
1215
1216
1217	for (i = 0; pf_limits[i].name; i++) {
1218		if (strcasecmp(opt, pf_limits[i].name) == 0) {
1219			pf->limit[pf_limits[i].index] = limit;
1220			pf->limit_set[pf_limits[i].index] = 1;
1221			break;
1222		}
1223	}
1224	if (pf_limits[i].name == NULL) {
1225		warnx("Bad pool name.");
1226		return (1);
1227	}
1228
1229	if (pf->opts & PF_OPT_VERBOSE)
1230		printf("set limit %s %d\n", opt, limit);
1231
1232	return (0);
1233}
1234
1235int
1236pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1237{
1238	struct pfioc_limit pl;
1239
1240	memset(&pl, 0, sizeof(pl));
1241	pl.index = index;
1242	pl.limit = limit;
1243	if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1244		if (errno == EBUSY)
1245			warnx("Current pool size exceeds requested hard limit");
1246		else
1247			warnx("DIOCSETLIMIT");
1248		return (1);
1249	}
1250	return (0);
1251}
1252
1253int
1254pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1255{
1256	int i;
1257
1258	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1259		return (0);
1260
1261	for (i = 0; pf_timeouts[i].name; i++) {
1262		if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1263			pf->timeout[pf_timeouts[i].timeout] = seconds;
1264			pf->timeout_set[pf_timeouts[i].timeout] = 1;
1265			break;
1266		}
1267	}
1268
1269	if (pf_timeouts[i].name == NULL) {
1270		warnx("Bad timeout name.");
1271		return (1);
1272	}
1273
1274
1275	if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1276		printf("set timeout %s %d\n", opt, seconds);
1277
1278	return (0);
1279}
1280
1281int
1282pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1283{
1284	struct pfioc_tm pt;
1285
1286	memset(&pt, 0, sizeof(pt));
1287	pt.timeout = timeout;
1288	pt.seconds = seconds;
1289	if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1290		warnx("DIOCSETTIMEOUT");
1291		return (1);
1292	}
1293	return (0);
1294}
1295
1296int
1297pfctl_set_optimization(struct pfctl *pf, const char *opt)
1298{
1299	const struct pf_hint *hint;
1300	int i, r;
1301
1302	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1303		return (0);
1304
1305	for (i = 0; pf_hints[i].name; i++)
1306		if (strcasecmp(opt, pf_hints[i].name) == 0)
1307			break;
1308
1309	hint = pf_hints[i].hint;
1310	if (hint == NULL) {
1311		warnx("Bad hint name.");
1312		return (1);
1313	}
1314
1315	for (i = 0; hint[i].name; i++)
1316		if ((r = pfctl_set_timeout(pf, hint[i].name,
1317		    hint[i].timeout, 1)))
1318			return (r);
1319
1320	if (pf->opts & PF_OPT_VERBOSE)
1321		printf("set optimization %s\n", opt);
1322
1323	return (0);
1324}
1325
1326int
1327pfctl_set_logif(struct pfctl *pf, char *ifname)
1328{
1329
1330	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1331		return (0);
1332
1333	if (!strcmp(ifname, "none")) {
1334		free(pf->ifname);
1335		pf->ifname = NULL;
1336	} else {
1337		pf->ifname = strdup(ifname);
1338		if (!pf->ifname)
1339			errx(1, "pfctl_set_logif: strdup");
1340	}
1341	pf->ifname_set = 1;
1342
1343	if (pf->opts & PF_OPT_VERBOSE)
1344		printf("set loginterface %s\n", ifname);
1345
1346	return (0);
1347}
1348
1349int
1350pfctl_load_logif(struct pfctl *pf, char *ifname)
1351{
1352	struct pfioc_if pi;
1353
1354	memset(&pi, 0, sizeof(pi));
1355	if (ifname && strlcpy(pi.ifname, ifname,
1356	    sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1357		warnx("pfctl_set_logif: strlcpy");
1358		return (1);
1359	}
1360	if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1361		warnx("DIOCSETSTATUSIF");
1362		return (1);
1363	}
1364	return (0);
1365}
1366
1367int
1368pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1369{
1370	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1371		return (0);
1372
1373	HTONL(hostid);
1374
1375	pf->hostid = hostid;
1376	pf->hostid_set = 1;
1377
1378	if (pf->opts & PF_OPT_VERBOSE)
1379		printf("set hostid 0x%08x\n", ntohl(hostid));
1380
1381	return (0);
1382}
1383
1384int
1385pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1386{
1387	if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1388		warnx("DIOCSETHOSTID");
1389		return (1);
1390	}
1391	return (0);
1392}
1393
1394int
1395pfctl_set_debug(struct pfctl *pf, char *d)
1396{
1397	u_int32_t	level;
1398
1399	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1400		return (0);
1401
1402	if (!strcmp(d, "none"))
1403		pf->debug = PF_DEBUG_NONE;
1404	else if (!strcmp(d, "urgent"))
1405		pf->debug = PF_DEBUG_URGENT;
1406	else if (!strcmp(d, "misc"))
1407		pf->debug = PF_DEBUG_MISC;
1408	else if (!strcmp(d, "loud"))
1409		pf->debug = PF_DEBUG_NOISY;
1410	else {
1411		warnx("unknown debug level \"%s\"", d);
1412		return (-1);
1413	}
1414
1415	pf->debug_set = 1;
1416
1417	if ((pf->opts & PF_OPT_NOACTION) == 0)
1418		if (ioctl(dev, DIOCSETDEBUG, &level))
1419			err(1, "DIOCSETDEBUG");
1420
1421	if (pf->opts & PF_OPT_VERBOSE)
1422		printf("set debug %s\n", d);
1423
1424	return (0);
1425}
1426
1427int
1428pfctl_load_debug(struct pfctl *pf, unsigned int level)
1429{
1430	if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1431		warnx("DIOCSETDEBUG");
1432		return (1);
1433	}
1434	return (0);
1435}
1436
1437int
1438pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1439{
1440	struct pfioc_iface	pi;
1441
1442	if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1443		return (0);
1444
1445	bzero(&pi, sizeof(pi));
1446
1447	pi.pfiio_flags = flags;
1448
1449	if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
1450	    sizeof(pi.pfiio_name))
1451		errx(1, "pfctl_set_interface_flags: strlcpy");
1452
1453	if ((pf->opts & PF_OPT_NOACTION) == 0) {
1454		if (how == 0) {
1455			if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
1456				err(1, "DIOCCLRIFFLAG");
1457		} else {
1458			if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
1459				err(1, "DIOCSETIFFLAG");
1460		}
1461	}
1462	return (0);
1463}
1464
1465void
1466pfctl_debug(int dev, u_int32_t level, int opts)
1467{
1468	if (ioctl(dev, DIOCSETDEBUG, &level))
1469		err(1, "DIOCSETDEBUG");
1470	if ((opts & PF_OPT_QUIET) == 0) {
1471		fprintf(stderr, "debug level set to '");
1472		switch (level) {
1473		case PF_DEBUG_NONE:
1474			fprintf(stderr, "none");
1475			break;
1476		case PF_DEBUG_URGENT:
1477			fprintf(stderr, "urgent");
1478			break;
1479		case PF_DEBUG_MISC:
1480			fprintf(stderr, "misc");
1481			break;
1482		case PF_DEBUG_NOISY:
1483			fprintf(stderr, "loud");
1484			break;
1485		default:
1486			fprintf(stderr, "<invalid>");
1487			break;
1488		}
1489		fprintf(stderr, "'\n");
1490	}
1491}
1492
1493int
1494pfctl_clear_rule_counters(int dev, int opts)
1495{
1496	if (ioctl(dev, DIOCCLRRULECTRS))
1497		err(1, "DIOCCLRRULECTRS");
1498	if ((opts & PF_OPT_QUIET) == 0)
1499		fprintf(stderr, "pf: rule counters cleared\n");
1500	return (0);
1501}
1502
1503int
1504pfctl_test_altqsupport(int dev, int opts)
1505{
1506#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
1507	return (0);
1508#else
1509	struct pfioc_altq pa;
1510
1511	if (ioctl(dev, DIOCGETALTQS, &pa)) {
1512		if (errno == ENODEV) {
1513			if (!(opts & PF_OPT_QUIET))
1514				fprintf(stderr, "No ALTQ support in kernel\n"
1515				    "ALTQ related functions disabled\n");
1516			return (0);
1517		} else
1518			err(1, "DIOCGETALTQS");
1519	}
1520	return (1);
1521#endif
1522}
1523
1524int
1525pfctl_show_anchors(int dev, int opts, char *anchorname)
1526{
1527	struct pfioc_ruleset	 pr;
1528	u_int32_t		 mnr, nr;
1529
1530	memset(&pr, 0, sizeof(pr));
1531	memcpy(pr.path, anchorname, sizeof(pr.path));
1532	if (ioctl(dev, DIOCGETRULESETS, &pr)) {
1533		if (errno == EINVAL)
1534			fprintf(stderr, "Anchor '%s' not found.\n",
1535			    anchorname);
1536		else
1537			err(1, "DIOCGETRULESETS");
1538		return (-1);
1539	}
1540	mnr = pr.nr;
1541	for (nr = 0; nr < mnr; ++nr) {
1542		char sub[MAXPATHLEN];
1543
1544		pr.nr = nr;
1545		if (ioctl(dev, DIOCGETRULESET, &pr))
1546			err(1, "DIOCGETRULESET");
1547		if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
1548			continue;
1549		sub[0] = 0;
1550		if (pr.path[0]) {
1551			strlcat(sub, pr.path, sizeof(sub));
1552			strlcat(sub, "/", sizeof(sub));
1553		}
1554		strlcat(sub, pr.name, sizeof(sub));
1555		printf("  %s\n", sub);
1556		if (opts & PF_OPT_VERBOSE && pfctl_show_anchors(dev, opts, sub))
1557			return (-1);
1558	}
1559	return (0);
1560}
1561
1562const char *
1563pfctl_lookup_option(char *cmd, const char **list)
1564{
1565	if (cmd != NULL && *cmd)
1566		for (; *list; list++)
1567			if (!strncmp(cmd, *list, strlen(cmd)))
1568				return (*list);
1569	return (NULL);
1570}
1571
1572int
1573main(int argc, char *argv[])
1574{
1575	int	error = 0;
1576	int	ch;
1577	int	mode = O_RDONLY;
1578	int	opts = 0;
1579	char	anchorname[MAXPATHLEN];
1580
1581	if (argc < 2)
1582		usage();
1583
1584	while ((ch = getopt(argc, argv,
1585	    "a:AdD:eqf:F:ghi:k:mnNOop:rRs:t:T:vx:z")) != -1) {
1586		switch (ch) {
1587		case 'a':
1588			anchoropt = optarg;
1589			break;
1590		case 'd':
1591			opts |= PF_OPT_DISABLE;
1592			mode = O_RDWR;
1593			break;
1594		case 'D':
1595			if (pfctl_cmdline_symset(optarg) < 0)
1596				warnx("could not parse macro definition %s",
1597				    optarg);
1598			break;
1599		case 'e':
1600			opts |= PF_OPT_ENABLE;
1601			mode = O_RDWR;
1602			break;
1603		case 'q':
1604			opts |= PF_OPT_QUIET;
1605			break;
1606		case 'F':
1607			clearopt = pfctl_lookup_option(optarg, clearopt_list);
1608			if (clearopt == NULL) {
1609				warnx("Unknown flush modifier '%s'", optarg);
1610				usage();
1611			}
1612			mode = O_RDWR;
1613			break;
1614		case 'i':
1615			ifaceopt = optarg;
1616			break;
1617		case 'k':
1618			if (state_killers >= 2) {
1619				warnx("can only specify -k twice");
1620				usage();
1621				/* NOTREACHED */
1622			}
1623			state_kill[state_killers++] = optarg;
1624			mode = O_RDWR;
1625			break;
1626		case 'm':
1627			opts |= PF_OPT_MERGE;
1628			break;
1629		case 'n':
1630			opts |= PF_OPT_NOACTION;
1631			break;
1632		case 'N':
1633			loadopt |= PFCTL_FLAG_NAT;
1634			break;
1635		case 'r':
1636			opts |= PF_OPT_USEDNS;
1637			break;
1638		case 'f':
1639			rulesopt = optarg;
1640			mode = O_RDWR;
1641			break;
1642		case 'g':
1643			opts |= PF_OPT_DEBUG;
1644			break;
1645		case 'A':
1646			loadopt |= PFCTL_FLAG_ALTQ;
1647			break;
1648		case 'R':
1649			loadopt |= PFCTL_FLAG_FILTER;
1650			break;
1651		case 'o':
1652			if (opts & PF_OPT_OPTIMIZE)
1653				opts |= PF_OPT_OPTIMIZE_PROFILE;
1654			else
1655				opts |= PF_OPT_OPTIMIZE;
1656			break;
1657		case 'O':
1658			loadopt |= PFCTL_FLAG_OPTION;
1659			break;
1660		case 'p':
1661			pf_device = optarg;
1662			break;
1663		case 's':
1664			showopt = pfctl_lookup_option(optarg, showopt_list);
1665			if (showopt == NULL) {
1666				warnx("Unknown show modifier '%s'", optarg);
1667				usage();
1668			}
1669			break;
1670		case 't':
1671			tableopt = optarg;
1672			break;
1673		case 'T':
1674			tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
1675			if (tblcmdopt == NULL) {
1676				warnx("Unknown table command '%s'", optarg);
1677				usage();
1678			}
1679			break;
1680		case 'v':
1681			if (opts & PF_OPT_VERBOSE)
1682				opts |= PF_OPT_VERBOSE2;
1683			opts |= PF_OPT_VERBOSE;
1684			break;
1685		case 'x':
1686			debugopt = pfctl_lookup_option(optarg, debugopt_list);
1687			if (debugopt == NULL) {
1688				warnx("Unknown debug level '%s'", optarg);
1689				usage();
1690			}
1691			mode = O_RDWR;
1692			break;
1693		case 'z':
1694			opts |= PF_OPT_CLRRULECTRS;
1695			mode = O_RDWR;
1696			break;
1697		case 'h':
1698			/* FALLTHROUGH */
1699		default:
1700			usage();
1701			/* NOTREACHED */
1702		}
1703	}
1704
1705	if (tblcmdopt != NULL) {
1706		argc -= optind;
1707		argv += optind;
1708		ch = *tblcmdopt;
1709		if (ch == 'l') {
1710			loadopt |= PFCTL_FLAG_TABLE;
1711			tblcmdopt = NULL;
1712		} else
1713			mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY;
1714	} else if (argc != optind) {
1715		warnx("unknown command line argument: %s ...", argv[optind]);
1716		usage();
1717		/* NOTREACHED */
1718	}
1719	if (loadopt == 0)
1720		loadopt = ~0;
1721
1722	memset(anchorname, 0, sizeof(anchorname));
1723	if (anchoropt != NULL) {
1724		if (strlcpy(anchorname, anchoropt,
1725		    sizeof(anchorname)) >= sizeof(anchorname))
1726			errx(1, "anchor name '%s' too long",
1727			    anchoropt);
1728		loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
1729	}
1730
1731	if ((opts & PF_OPT_NOACTION) == 0) {
1732		dev = open(pf_device, mode);
1733		if (dev == -1)
1734			err(1, "%s", pf_device);
1735		altqsupport = pfctl_test_altqsupport(dev, opts);
1736	} else {
1737		dev = open(pf_device, O_RDONLY);
1738		if (dev >= 0)
1739			opts |= PF_OPT_DUMMYACTION;
1740		/* turn off options */
1741		opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
1742		clearopt = showopt = debugopt = NULL;
1743#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
1744		altqsupport = 0;
1745#else
1746		altqsupport = 1;
1747#endif
1748	}
1749
1750	if (opts & PF_OPT_DISABLE)
1751		if (pfctl_disable(dev, opts))
1752			error = 1;
1753
1754	if (showopt != NULL) {
1755		switch (*showopt) {
1756		case 'A':
1757			pfctl_show_anchors(dev, opts, anchorname);
1758			break;
1759		case 'r':
1760			pfctl_load_fingerprints(dev, opts);
1761			pfctl_show_rules(dev, opts, 0, anchorname);
1762			break;
1763		case 'l':
1764			pfctl_load_fingerprints(dev, opts);
1765			pfctl_show_rules(dev, opts, 1, anchorname);
1766			break;
1767		case 'n':
1768			pfctl_load_fingerprints(dev, opts);
1769			pfctl_show_nat(dev, opts, anchorname);
1770			break;
1771		case 'q':
1772			pfctl_show_altq(dev, ifaceopt, opts,
1773			    opts & PF_OPT_VERBOSE2);
1774			break;
1775		case 's':
1776			pfctl_show_states(dev, ifaceopt, opts);
1777			break;
1778		case 'S':
1779			pfctl_show_src_nodes(dev, opts);
1780			break;
1781		case 'i':
1782			pfctl_show_status(dev, opts);
1783			break;
1784		case 't':
1785			pfctl_show_timeouts(dev, opts);
1786			break;
1787		case 'm':
1788			pfctl_show_limits(dev, opts);
1789			break;
1790		case 'a':
1791			opts |= PF_OPT_SHOWALL;
1792			pfctl_load_fingerprints(dev, opts);
1793
1794			pfctl_show_nat(dev, opts, anchorname);
1795			pfctl_show_rules(dev, opts, 0, anchorname);
1796			pfctl_show_altq(dev, ifaceopt, opts, 0);
1797			pfctl_show_states(dev, ifaceopt, opts);
1798			pfctl_show_src_nodes(dev, opts);
1799			pfctl_show_status(dev, opts);
1800			pfctl_show_rules(dev, opts, 1, anchorname);
1801			pfctl_show_timeouts(dev, opts);
1802			pfctl_show_limits(dev, opts);
1803			pfctl_show_tables(anchorname, opts);
1804			pfctl_show_fingerprints(opts);
1805			break;
1806		case 'T':
1807			pfctl_show_tables(anchorname, opts);
1808			break;
1809		case 'o':
1810			pfctl_load_fingerprints(dev, opts);
1811			pfctl_show_fingerprints(opts);
1812			break;
1813		case 'I':
1814			pfctl_show_ifaces(ifaceopt, opts);
1815			break;
1816		}
1817	}
1818
1819	if (clearopt != NULL) {
1820		switch (*clearopt) {
1821		case 'r':
1822			pfctl_clear_rules(dev, opts, anchorname);
1823			break;
1824		case 'n':
1825			pfctl_clear_nat(dev, opts, anchorname);
1826			break;
1827		case 'q':
1828			pfctl_clear_altq(dev, opts);
1829			break;
1830		case 's':
1831			pfctl_clear_states(dev, ifaceopt, opts);
1832			break;
1833		case 'S':
1834			pfctl_clear_src_nodes(dev, opts);
1835			break;
1836		case 'i':
1837			pfctl_clear_stats(dev, opts);
1838			break;
1839		case 'a':
1840			pfctl_clear_rules(dev, opts, anchorname);
1841			pfctl_clear_nat(dev, opts, anchorname);
1842			pfctl_clear_tables(anchorname, opts);
1843			if (!*anchorname) {
1844				pfctl_clear_altq(dev, opts);
1845				pfctl_clear_states(dev, ifaceopt, opts);
1846				pfctl_clear_src_nodes(dev, opts);
1847				pfctl_clear_stats(dev, opts);
1848				pfctl_clear_fingerprints(dev, opts);
1849				pfctl_clear_interface_flags(dev, opts);
1850			}
1851			break;
1852		case 'o':
1853			pfctl_clear_fingerprints(dev, opts);
1854			break;
1855		case 'T':
1856			pfctl_clear_tables(anchorname, opts);
1857			break;
1858		}
1859	}
1860	if (state_killers)
1861		pfctl_kill_states(dev, ifaceopt, opts);
1862
1863	if (tblcmdopt != NULL) {
1864		error = pfctl_command_tables(argc, argv, tableopt,
1865		    tblcmdopt, rulesopt, anchorname, opts);
1866		rulesopt = NULL;
1867	}
1868
1869	if ((rulesopt != NULL) && (!*anchorname))
1870		if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
1871			error = 1;
1872
1873	if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
1874	    !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
1875		if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
1876			error = 1;
1877
1878	if (rulesopt != NULL) {
1879		if (pfctl_rules(dev, rulesopt, opts, anchorname, NULL))
1880			error = 1;
1881		else if (!(opts & PF_OPT_NOACTION) &&
1882		    (loadopt & PFCTL_FLAG_TABLE))
1883			warn_namespace_collision(NULL);
1884	}
1885
1886	if (opts & PF_OPT_ENABLE)
1887		if (pfctl_enable(dev, opts))
1888			error = 1;
1889
1890	if (debugopt != NULL) {
1891		switch (*debugopt) {
1892		case 'n':
1893			pfctl_debug(dev, PF_DEBUG_NONE, opts);
1894			break;
1895		case 'u':
1896			pfctl_debug(dev, PF_DEBUG_URGENT, opts);
1897			break;
1898		case 'm':
1899			pfctl_debug(dev, PF_DEBUG_MISC, opts);
1900			break;
1901		case 'l':
1902			pfctl_debug(dev, PF_DEBUG_NOISY, opts);
1903			break;
1904		}
1905	}
1906
1907	if (opts & PF_OPT_CLRRULECTRS) {
1908		if (pfctl_clear_rule_counters(dev, opts))
1909			error = 1;
1910	}
1911	exit(error);
1912}
1913