1223637Sbz/*	$OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */
2126353Smlaier
3126353Smlaier/*
4126353Smlaier * Copyright (c) 2002 Cedric Berger
5126353Smlaier * All rights reserved.
6126353Smlaier *
7126353Smlaier * Redistribution and use in source and binary forms, with or without
8126353Smlaier * modification, are permitted provided that the following conditions
9126353Smlaier * are met:
10126353Smlaier *
11126353Smlaier *    - Redistributions of source code must retain the above copyright
12126353Smlaier *      notice, this list of conditions and the following disclaimer.
13126353Smlaier *    - Redistributions in binary form must reproduce the above
14126353Smlaier *      copyright notice, this list of conditions and the following
15126353Smlaier *      disclaimer in the documentation and/or other materials provided
16126353Smlaier *      with the distribution.
17126353Smlaier *
18126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19126353Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20126353Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21126353Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22126353Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23126353Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24126353Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25126353Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26126353Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28126353Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29126353Smlaier * POSSIBILITY OF SUCH DAMAGE.
30126353Smlaier *
31126353Smlaier */
32126353Smlaier
33127082Sobrien#include <sys/cdefs.h>
34127082Sobrien__FBSDID("$FreeBSD$");
35127082Sobrien
36126353Smlaier#include <sys/types.h>
37126353Smlaier#include <sys/ioctl.h>
38126353Smlaier#include <sys/socket.h>
39126353Smlaier
40126353Smlaier#include <net/if.h>
41126353Smlaier#include <net/pfvar.h>
42126353Smlaier#include <arpa/inet.h>
43126353Smlaier
44126353Smlaier#include <ctype.h>
45126353Smlaier#include <err.h>
46126353Smlaier#include <errno.h>
47126353Smlaier#include <netdb.h>
48126353Smlaier#include <stdarg.h>
49126353Smlaier#include <stdio.h>
50126353Smlaier#include <stdlib.h>
51126353Smlaier#include <string.h>
52126353Smlaier#include <time.h>
53126353Smlaier
54126353Smlaier#include "pfctl_parser.h"
55126353Smlaier#include "pfctl.h"
56126353Smlaier
57126353Smlaierextern void	usage(void);
58126353Smlaierstatic int	pfctl_table(int, char *[], char *, const char *, char *,
59145840Smlaier		    const char *, int);
60126353Smlaierstatic void	print_table(struct pfr_table *, int, int);
61126353Smlaierstatic void	print_tstats(struct pfr_tstats *, int);
62126353Smlaierstatic int	load_addr(struct pfr_buffer *, int, char *[], char *, int);
63126353Smlaierstatic void	print_addrx(struct pfr_addr *, struct pfr_addr *, int);
64126353Smlaierstatic void	print_astats(struct pfr_astats *, int);
65126353Smlaierstatic void	radix_perror(void);
66126353Smlaierstatic void	xprintf(int, const char *, ...);
67171172Smlaierstatic void	print_iface(struct pfi_kif *, int);
68126353Smlaier
69126353Smlaierstatic const char	*stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
70126353Smlaier	{ "In/Block:",	"In/Pass:",	"In/XPass:" },
71126353Smlaier	{ "Out/Block:",	"Out/Pass:",	"Out/XPass:" }
72126353Smlaier};
73126353Smlaier
74130617Smlaierstatic const char	*istats_text[2][2][2] = {
75130617Smlaier	{ { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } },
76130617Smlaier	{ { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } }
77130617Smlaier};
78130617Smlaier
79126353Smlaier#define RVTEST(fct) do {				\
80126353Smlaier		if ((!(opts & PF_OPT_NOACTION) ||	\
81126353Smlaier		    (opts & PF_OPT_DUMMYACTION)) &&	\
82126353Smlaier		    (fct)) {				\
83126353Smlaier			radix_perror();			\
84126353Smlaier			goto _error;			\
85126353Smlaier		}					\
86126353Smlaier	} while (0)
87126353Smlaier
88126353Smlaier#define CREATE_TABLE do {						\
89126353Smlaier		table.pfrt_flags |= PFR_TFLAG_PERSIST;			\
90134175Smlaier		if ((!(opts & PF_OPT_NOACTION) ||			\
91134175Smlaier		    (opts & PF_OPT_DUMMYACTION)) &&			\
92134175Smlaier		    (pfr_add_tables(&table, 1, &nadd, flags)) &&	\
93134175Smlaier		    (errno != EPERM)) {					\
94134175Smlaier			radix_perror();					\
95134175Smlaier			goto _error;					\
96134175Smlaier		}							\
97126353Smlaier		if (nadd) {						\
98126353Smlaier			warn_namespace_collision(table.pfrt_name);	\
99126353Smlaier			xprintf(opts, "%d table created", nadd);	\
100126353Smlaier			if (opts & PF_OPT_NOACTION)			\
101126353Smlaier				return (0);				\
102126353Smlaier		}							\
103126353Smlaier		table.pfrt_flags &= ~PFR_TFLAG_PERSIST;			\
104126353Smlaier	} while(0)
105126353Smlaier
106126353Smlaierint
107145840Smlaierpfctl_clear_tables(const char *anchor, int opts)
108126353Smlaier{
109145840Smlaier	return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts);
110126353Smlaier}
111126353Smlaier
112126353Smlaierint
113145840Smlaierpfctl_show_tables(const char *anchor, int opts)
114126353Smlaier{
115145840Smlaier	return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, opts);
116126353Smlaier}
117126353Smlaier
118126353Smlaierint
119126353Smlaierpfctl_command_tables(int argc, char *argv[], char *tname,
120145840Smlaier    const char *command, char *file, const char *anchor, int opts)
121126353Smlaier{
122126353Smlaier	if (tname == NULL || command == NULL)
123126353Smlaier		usage();
124145840Smlaier	return pfctl_table(argc, argv, tname, command, file, anchor, opts);
125126353Smlaier}
126126353Smlaier
127126353Smlaierint
128126353Smlaierpfctl_table(int argc, char *argv[], char *tname, const char *command,
129145840Smlaier    char *file, const char *anchor, int opts)
130126353Smlaier{
131130617Smlaier	struct pfr_table	 table;
132130617Smlaier	struct pfr_buffer	 b, b2;
133130617Smlaier	struct pfr_addr		*a, *a2;
134130617Smlaier	int			 nadd = 0, ndel = 0, nchange = 0, nzero = 0;
135130617Smlaier	int			 rv = 0, flags = 0, nmatch = 0;
136130617Smlaier	void			*p;
137126353Smlaier
138126353Smlaier	if (command == NULL)
139126353Smlaier		usage();
140126353Smlaier	if (opts & PF_OPT_NOACTION)
141126353Smlaier		flags |= PFR_FLAG_DUMMY;
142126353Smlaier
143126353Smlaier	bzero(&b, sizeof(b));
144126353Smlaier	bzero(&b2, sizeof(b2));
145126353Smlaier	bzero(&table, sizeof(table));
146126353Smlaier	if (tname != NULL) {
147126353Smlaier		if (strlen(tname) >= PF_TABLE_NAME_SIZE)
148126353Smlaier			usage();
149126353Smlaier		if (strlcpy(table.pfrt_name, tname,
150126353Smlaier		    sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
151126353Smlaier			errx(1, "pfctl_table: strlcpy");
152126353Smlaier	}
153126353Smlaier	if (strlcpy(table.pfrt_anchor, anchor,
154145840Smlaier	    sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor))
155126353Smlaier		errx(1, "pfctl_table: strlcpy");
156126353Smlaier
157126353Smlaier	if (!strcmp(command, "-F")) {
158126353Smlaier		if (argc || file != NULL)
159126353Smlaier			usage();
160126353Smlaier		RVTEST(pfr_clr_tables(&table, &ndel, flags));
161126353Smlaier		xprintf(opts, "%d tables deleted", ndel);
162126353Smlaier	} else if (!strcmp(command, "-s")) {
163126353Smlaier		b.pfrb_type = (opts & PF_OPT_VERBOSE2) ?
164126353Smlaier		    PFRB_TSTATS : PFRB_TABLES;
165126353Smlaier		if (argc || file != NULL)
166126353Smlaier			usage();
167126353Smlaier		for (;;) {
168126353Smlaier			pfr_buf_grow(&b, b.pfrb_size);
169126353Smlaier			b.pfrb_size = b.pfrb_msize;
170126353Smlaier			if (opts & PF_OPT_VERBOSE2)
171126353Smlaier				RVTEST(pfr_get_tstats(&table,
172126353Smlaier				    b.pfrb_caddr, &b.pfrb_size, flags));
173126353Smlaier			else
174126353Smlaier				RVTEST(pfr_get_tables(&table,
175126353Smlaier				    b.pfrb_caddr, &b.pfrb_size, flags));
176126353Smlaier			if (b.pfrb_size <= b.pfrb_msize)
177126353Smlaier				break;
178126353Smlaier		}
179130617Smlaier
180171172Smlaier		if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0)
181130617Smlaier			pfctl_print_title("TABLES:");
182130617Smlaier
183126353Smlaier		PFRB_FOREACH(p, &b)
184126353Smlaier			if (opts & PF_OPT_VERBOSE2)
185126353Smlaier				print_tstats(p, opts & PF_OPT_DEBUG);
186126353Smlaier			else
187126353Smlaier				print_table(p, opts & PF_OPT_VERBOSE,
188126353Smlaier				    opts & PF_OPT_DEBUG);
189126353Smlaier	} else if (!strcmp(command, "kill")) {
190126353Smlaier		if (argc || file != NULL)
191126353Smlaier			usage();
192126353Smlaier		RVTEST(pfr_del_tables(&table, 1, &ndel, flags));
193126353Smlaier		xprintf(opts, "%d table deleted", ndel);
194126353Smlaier	} else if (!strcmp(command, "flush")) {
195126353Smlaier		if (argc || file != NULL)
196126353Smlaier			usage();
197126353Smlaier		RVTEST(pfr_clr_addrs(&table, &ndel, flags));
198126353Smlaier		xprintf(opts, "%d addresses deleted", ndel);
199126353Smlaier	} else if (!strcmp(command, "add")) {
200126353Smlaier		b.pfrb_type = PFRB_ADDRS;
201126353Smlaier		if (load_addr(&b, argc, argv, file, 0))
202126353Smlaier			goto _error;
203126353Smlaier		CREATE_TABLE;
204126353Smlaier		if (opts & PF_OPT_VERBOSE)
205126353Smlaier			flags |= PFR_FLAG_FEEDBACK;
206126353Smlaier		RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size,
207126353Smlaier		    &nadd, flags));
208126353Smlaier		xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size);
209126353Smlaier		if (opts & PF_OPT_VERBOSE)
210126353Smlaier			PFRB_FOREACH(a, &b)
211126353Smlaier				if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
212126353Smlaier					print_addrx(a, NULL,
213126353Smlaier					    opts & PF_OPT_USEDNS);
214126353Smlaier	} else if (!strcmp(command, "delete")) {
215126353Smlaier		b.pfrb_type = PFRB_ADDRS;
216126353Smlaier		if (load_addr(&b, argc, argv, file, 0))
217126353Smlaier			goto _error;
218126353Smlaier		if (opts & PF_OPT_VERBOSE)
219126353Smlaier			flags |= PFR_FLAG_FEEDBACK;
220126353Smlaier		RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size,
221126353Smlaier		    &ndel, flags));
222126353Smlaier		xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size);
223126353Smlaier		if (opts & PF_OPT_VERBOSE)
224126353Smlaier			PFRB_FOREACH(a, &b)
225126353Smlaier				if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
226126353Smlaier					print_addrx(a, NULL,
227126353Smlaier					    opts & PF_OPT_USEDNS);
228126353Smlaier	} else if (!strcmp(command, "replace")) {
229126353Smlaier		b.pfrb_type = PFRB_ADDRS;
230126353Smlaier		if (load_addr(&b, argc, argv, file, 0))
231126353Smlaier			goto _error;
232126353Smlaier		CREATE_TABLE;
233126353Smlaier		if (opts & PF_OPT_VERBOSE)
234126353Smlaier			flags |= PFR_FLAG_FEEDBACK;
235126353Smlaier		for (;;) {
236126353Smlaier			int sz2 = b.pfrb_msize;
237126353Smlaier
238126353Smlaier			RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size,
239126353Smlaier			    &sz2, &nadd, &ndel, &nchange, flags));
240126353Smlaier			if (sz2 <= b.pfrb_msize) {
241126353Smlaier				b.pfrb_size = sz2;
242126353Smlaier				break;
243126353Smlaier			} else
244126353Smlaier				pfr_buf_grow(&b, sz2);
245126353Smlaier		}
246126353Smlaier		if (nadd)
247126353Smlaier			xprintf(opts, "%d addresses added", nadd);
248126353Smlaier		if (ndel)
249126353Smlaier			xprintf(opts, "%d addresses deleted", ndel);
250126353Smlaier		if (nchange)
251126353Smlaier			xprintf(opts, "%d addresses changed", nchange);
252126353Smlaier		if (!nadd && !ndel && !nchange)
253126353Smlaier			xprintf(opts, "no changes");
254126353Smlaier		if (opts & PF_OPT_VERBOSE)
255126353Smlaier			PFRB_FOREACH(a, &b)
256126353Smlaier				if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
257126353Smlaier					print_addrx(a, NULL,
258126353Smlaier					    opts & PF_OPT_USEDNS);
259171172Smlaier	} else if (!strcmp(command, "expire")) {
260171172Smlaier		const char		*errstr;
261171172Smlaier		u_int			 lifetime;
262171172Smlaier
263171172Smlaier		b.pfrb_type = PFRB_ASTATS;
264171172Smlaier		b2.pfrb_type = PFRB_ADDRS;
265171172Smlaier		if (argc != 1 || file != NULL)
266171172Smlaier			usage();
267171172Smlaier		lifetime = strtonum(*argv, 0, UINT_MAX, &errstr);
268171172Smlaier		if (errstr)
269171172Smlaier			errx(1, "expiry time: %s", errstr);
270171172Smlaier		for (;;) {
271171172Smlaier			pfr_buf_grow(&b, b.pfrb_size);
272171172Smlaier			b.pfrb_size = b.pfrb_msize;
273171172Smlaier			RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
274171172Smlaier			    &b.pfrb_size, flags));
275171172Smlaier			if (b.pfrb_size <= b.pfrb_msize)
276171172Smlaier				break;
277171172Smlaier		}
278223637Sbz		PFRB_FOREACH(p, &b) {
279223637Sbz			((struct pfr_astats *)p)->pfras_a.pfra_fback = 0;
280171172Smlaier			if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero >
281223637Sbz			    lifetime)
282171172Smlaier				if (pfr_buf_add(&b2,
283171172Smlaier				    &((struct pfr_astats *)p)->pfras_a))
284171172Smlaier					err(1, "duplicate buffer");
285223637Sbz		}
286171172Smlaier
287171172Smlaier		if (opts & PF_OPT_VERBOSE)
288171172Smlaier			flags |= PFR_FLAG_FEEDBACK;
289171172Smlaier		RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size,
290171172Smlaier		    &ndel, flags));
291171172Smlaier		xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size);
292171172Smlaier		if (opts & PF_OPT_VERBOSE)
293171172Smlaier			PFRB_FOREACH(a, &b2)
294171172Smlaier				if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
295171172Smlaier					print_addrx(a, NULL,
296171172Smlaier					    opts & PF_OPT_USEDNS);
297126353Smlaier	} else if (!strcmp(command, "show")) {
298126353Smlaier		b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
299130617Smlaier			PFRB_ASTATS : PFRB_ADDRS;
300126353Smlaier		if (argc || file != NULL)
301126353Smlaier			usage();
302126353Smlaier		for (;;) {
303126353Smlaier			pfr_buf_grow(&b, b.pfrb_size);
304126353Smlaier			b.pfrb_size = b.pfrb_msize;
305126353Smlaier			if (opts & PF_OPT_VERBOSE)
306126353Smlaier				RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
307126353Smlaier				    &b.pfrb_size, flags));
308126353Smlaier			else
309126353Smlaier				RVTEST(pfr_get_addrs(&table, b.pfrb_caddr,
310126353Smlaier				    &b.pfrb_size, flags));
311126353Smlaier			if (b.pfrb_size <= b.pfrb_msize)
312126353Smlaier				break;
313126353Smlaier		}
314126353Smlaier		PFRB_FOREACH(p, &b)
315126353Smlaier			if (opts & PF_OPT_VERBOSE)
316126353Smlaier				print_astats(p, opts & PF_OPT_USEDNS);
317126353Smlaier			else
318126353Smlaier				print_addrx(p, NULL, opts & PF_OPT_USEDNS);
319126353Smlaier	} else if (!strcmp(command, "test")) {
320126353Smlaier		b.pfrb_type = PFRB_ADDRS;
321126353Smlaier		b2.pfrb_type = PFRB_ADDRS;
322126353Smlaier
323126353Smlaier		if (load_addr(&b, argc, argv, file, 1))
324126353Smlaier			goto _error;
325126353Smlaier		if (opts & PF_OPT_VERBOSE2) {
326126353Smlaier			flags |= PFR_FLAG_REPLACE;
327126353Smlaier			PFRB_FOREACH(a, &b)
328126353Smlaier				if (pfr_buf_add(&b2, a))
329126353Smlaier					err(1, "duplicate buffer");
330126353Smlaier		}
331126353Smlaier		RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size,
332126353Smlaier		    &nmatch, flags));
333126353Smlaier		xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size);
334171172Smlaier		if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2))
335126353Smlaier			PFRB_FOREACH(a, &b)
336126353Smlaier				if (a->pfra_fback == PFR_FB_MATCH)
337126353Smlaier					print_addrx(a, NULL,
338126353Smlaier					    opts & PF_OPT_USEDNS);
339126353Smlaier		if (opts & PF_OPT_VERBOSE2) {
340126353Smlaier			a2 = NULL;
341126353Smlaier			PFRB_FOREACH(a, &b) {
342126353Smlaier				a2 = pfr_buf_next(&b2, a2);
343126353Smlaier				print_addrx(a2, a, opts & PF_OPT_USEDNS);
344126353Smlaier			}
345126353Smlaier		}
346126353Smlaier		if (nmatch < b.pfrb_size)
347126353Smlaier			rv = 2;
348126353Smlaier	} else if (!strcmp(command, "zero")) {
349126353Smlaier		if (argc || file != NULL)
350126353Smlaier			usage();
351126353Smlaier		flags |= PFR_FLAG_ADDRSTOO;
352126353Smlaier		RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
353126353Smlaier		xprintf(opts, "%d table/stats cleared", nzero);
354126353Smlaier	} else
355126353Smlaier		warnx("pfctl_table: unknown command '%s'", command);
356126353Smlaier	goto _cleanup;
357126353Smlaier
358126353Smlaier_error:
359126353Smlaier	rv = -1;
360126353Smlaier_cleanup:
361126353Smlaier	pfr_buf_clear(&b);
362126353Smlaier	pfr_buf_clear(&b2);
363126353Smlaier	return (rv);
364126353Smlaier}
365126353Smlaier
366126353Smlaiervoid
367126353Smlaierprint_table(struct pfr_table *ta, int verbose, int debug)
368126353Smlaier{
369126353Smlaier	if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE))
370126353Smlaier		return;
371126353Smlaier	if (verbose) {
372223637Sbz		printf("%c%c%c%c%c%c%c\t%s",
373126353Smlaier		    (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-',
374126353Smlaier		    (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-',
375126353Smlaier		    (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-',
376126353Smlaier		    (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-',
377126353Smlaier		    (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-',
378126353Smlaier		    (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-',
379223637Sbz		    (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-',
380126353Smlaier		    ta->pfrt_name);
381126353Smlaier		if (ta->pfrt_anchor[0])
382130617Smlaier			printf("\t%s", ta->pfrt_anchor);
383126353Smlaier		puts("");
384126353Smlaier	} else
385126353Smlaier		puts(ta->pfrt_name);
386126353Smlaier}
387126353Smlaier
388126353Smlaiervoid
389126353Smlaierprint_tstats(struct pfr_tstats *ts, int debug)
390126353Smlaier{
391126353Smlaier	time_t	time = ts->pfrts_tzero;
392126353Smlaier	int	dir, op;
393126353Smlaier
394126353Smlaier	if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
395126353Smlaier		return;
396126353Smlaier	print_table(&ts->pfrts_t, 1, debug);
397126353Smlaier	printf("\tAddresses:   %d\n", ts->pfrts_cnt);
398126353Smlaier	printf("\tCleared:     %s", ctime(&time));
399126353Smlaier	printf("\tReferences:  [ Anchors: %-18d Rules: %-18d ]\n",
400126353Smlaier	    ts->pfrts_refcnt[PFR_REFCNT_ANCHOR],
401126353Smlaier	    ts->pfrts_refcnt[PFR_REFCNT_RULE]);
402127024Smlaier	printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n",
403127024Smlaier	    (unsigned long long)ts->pfrts_nomatch,
404127024Smlaier	    (unsigned long long)ts->pfrts_match);
405126353Smlaier	for (dir = 0; dir < PFR_DIR_MAX; dir++)
406126353Smlaier		for (op = 0; op < PFR_OP_TABLE_MAX; op++)
407127024Smlaier			printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
408126353Smlaier			    stats_text[dir][op],
409127024Smlaier			    (unsigned long long)ts->pfrts_packets[dir][op],
410127024Smlaier			    (unsigned long long)ts->pfrts_bytes[dir][op]);
411126353Smlaier}
412126353Smlaier
413126353Smlaierint
414126353Smlaierload_addr(struct pfr_buffer *b, int argc, char *argv[], char *file,
415126353Smlaier    int nonetwork)
416126353Smlaier{
417126353Smlaier	while (argc--)
418126353Smlaier		if (append_addr(b, *argv++, nonetwork)) {
419126353Smlaier			if (errno)
420126353Smlaier				warn("cannot decode %s", argv[-1]);
421126353Smlaier			return (-1);
422126353Smlaier		}
423126353Smlaier	if (pfr_buf_load(b, file, nonetwork, append_addr)) {
424126353Smlaier		warn("cannot load %s", file);
425126353Smlaier		return (-1);
426126353Smlaier	}
427126353Smlaier	return (0);
428126353Smlaier}
429126353Smlaier
430126353Smlaiervoid
431126353Smlaierprint_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
432126353Smlaier{
433126353Smlaier	char		ch, buf[256] = "{error}";
434223637Sbz	char		fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' };
435126353Smlaier	unsigned int	fback, hostnet;
436126353Smlaier
437126353Smlaier	fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback;
438126353Smlaier	ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?';
439126353Smlaier	hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32;
440126353Smlaier	inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf));
441126353Smlaier	printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf);
442126353Smlaier	if (ad->pfra_net < hostnet)
443126353Smlaier		printf("/%d", ad->pfra_net);
444126353Smlaier	if (rad != NULL && fback != PFR_FB_NONE) {
445126353Smlaier		if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf))
446126353Smlaier			errx(1, "print_addrx: strlcpy");
447126353Smlaier		inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf));
448126353Smlaier		printf("\t%c%s", (rad->pfra_not?'!':' '), buf);
449126353Smlaier		if (rad->pfra_net < hostnet)
450126353Smlaier			printf("/%d", rad->pfra_net);
451126353Smlaier	}
452126353Smlaier	if (rad != NULL && fback == PFR_FB_NONE)
453126353Smlaier		printf("\t nomatch");
454126353Smlaier	if (dns && ad->pfra_net == hostnet) {
455126353Smlaier		char host[NI_MAXHOST];
456126353Smlaier		union sockaddr_union sa;
457126353Smlaier
458126353Smlaier		strlcpy(host, "?", sizeof(host));
459126353Smlaier		bzero(&sa, sizeof(sa));
460126353Smlaier		sa.sa.sa_family = ad->pfra_af;
461126353Smlaier		if (sa.sa.sa_family == AF_INET) {
462126353Smlaier			sa.sa.sa_len = sizeof(sa.sin);
463126353Smlaier			sa.sin.sin_addr = ad->pfra_ip4addr;
464126353Smlaier		} else {
465126353Smlaier			sa.sa.sa_len = sizeof(sa.sin6);
466126353Smlaier			sa.sin6.sin6_addr = ad->pfra_ip6addr;
467126353Smlaier		}
468126353Smlaier		if (getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host),
469126353Smlaier		    NULL, 0, NI_NAMEREQD) == 0)
470126353Smlaier			printf("\t(%s)", host);
471126353Smlaier	}
472126353Smlaier	printf("\n");
473126353Smlaier}
474126353Smlaier
475126353Smlaiervoid
476126353Smlaierprint_astats(struct pfr_astats *as, int dns)
477126353Smlaier{
478126353Smlaier	time_t	time = as->pfras_tzero;
479126353Smlaier	int	dir, op;
480126353Smlaier
481126353Smlaier	print_addrx(&as->pfras_a, NULL, dns);
482126353Smlaier	printf("\tCleared:     %s", ctime(&time));
483223637Sbz 	if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT)
484223637Sbz		return;
485126353Smlaier	for (dir = 0; dir < PFR_DIR_MAX; dir++)
486126353Smlaier		for (op = 0; op < PFR_OP_ADDR_MAX; op++)
487127024Smlaier			printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
488126353Smlaier			    stats_text[dir][op],
489127024Smlaier			    (unsigned long long)as->pfras_packets[dir][op],
490127024Smlaier			    (unsigned long long)as->pfras_bytes[dir][op]);
491126353Smlaier}
492126353Smlaier
493126353Smlaiervoid
494126353Smlaierradix_perror(void)
495126353Smlaier{
496126353Smlaier	extern char *__progname;
497126353Smlaier	fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno));
498126353Smlaier}
499126353Smlaier
500126353Smlaierint
501126353Smlaierpfctl_define_table(char *name, int flags, int addrs, const char *anchor,
502145840Smlaier    struct pfr_buffer *ab, u_int32_t ticket)
503126353Smlaier{
504126353Smlaier	struct pfr_table tbl;
505126353Smlaier
506126353Smlaier	bzero(&tbl, sizeof(tbl));
507130617Smlaier	if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >=
508130617Smlaier	    sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor,
509145840Smlaier	    sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor))
510126353Smlaier		errx(1, "pfctl_define_table: strlcpy");
511126353Smlaier	tbl.pfrt_flags = flags;
512126353Smlaier
513126353Smlaier	return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL,
514126353Smlaier	    NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0);
515126353Smlaier}
516126353Smlaier
517126353Smlaiervoid
518126353Smlaierwarn_namespace_collision(const char *filter)
519126353Smlaier{
520126353Smlaier	struct pfr_buffer b;
521126353Smlaier	struct pfr_table *t;
522126353Smlaier	const char *name = NULL, *lastcoll;
523126353Smlaier	int coll = 0;
524126353Smlaier
525126353Smlaier	bzero(&b, sizeof(b));
526126353Smlaier	b.pfrb_type = PFRB_TABLES;
527126353Smlaier	for (;;) {
528126353Smlaier		pfr_buf_grow(&b, b.pfrb_size);
529126353Smlaier		b.pfrb_size = b.pfrb_msize;
530126353Smlaier		if (pfr_get_tables(NULL, b.pfrb_caddr,
531126353Smlaier		    &b.pfrb_size, PFR_FLAG_ALLRSETS))
532130617Smlaier			err(1, "pfr_get_tables");
533126353Smlaier		if (b.pfrb_size <= b.pfrb_msize)
534126353Smlaier			break;
535126353Smlaier	}
536126353Smlaier	PFRB_FOREACH(t, &b) {
537126353Smlaier		if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE))
538126353Smlaier			continue;
539126353Smlaier		if (filter != NULL && strcmp(filter, t->pfrt_name))
540126353Smlaier			continue;
541126353Smlaier		if (!t->pfrt_anchor[0])
542126353Smlaier			name = t->pfrt_name;
543126353Smlaier		else if (name != NULL && !strcmp(name, t->pfrt_name)) {
544126353Smlaier			coll++;
545126353Smlaier			lastcoll = name;
546126353Smlaier			name = NULL;
547126353Smlaier		}
548126353Smlaier	}
549126353Smlaier	if (coll == 1)
550126353Smlaier		warnx("warning: namespace collision with <%s> global table.",
551126353Smlaier		    lastcoll);
552126353Smlaier	else if (coll > 1)
553126353Smlaier		warnx("warning: namespace collisions with %d global tables.",
554126353Smlaier		    coll);
555126353Smlaier	pfr_buf_clear(&b);
556126353Smlaier}
557126353Smlaier
558126353Smlaiervoid
559126353Smlaierxprintf(int opts, const char *fmt, ...)
560126353Smlaier{
561126353Smlaier	va_list args;
562126353Smlaier
563126353Smlaier	if (opts & PF_OPT_QUIET)
564126353Smlaier		return;
565126353Smlaier
566126353Smlaier	va_start(args, fmt);
567126353Smlaier	vfprintf(stderr, fmt, args);
568126353Smlaier	va_end(args);
569126353Smlaier
570126353Smlaier	if (opts & PF_OPT_DUMMYACTION)
571126353Smlaier		fprintf(stderr, " (dummy).\n");
572126353Smlaier	else if (opts & PF_OPT_NOACTION)
573126353Smlaier		fprintf(stderr, " (syntax only).\n");
574126353Smlaier	else
575126353Smlaier		fprintf(stderr, ".\n");
576126353Smlaier}
577130617Smlaier
578130617Smlaier
579130617Smlaier/* interface stuff */
580130617Smlaier
581130617Smlaierint
582130617Smlaierpfctl_show_ifaces(const char *filter, int opts)
583130617Smlaier{
584130617Smlaier	struct pfr_buffer	 b;
585171172Smlaier	struct pfi_kif		*p;
586171172Smlaier	int			 i = 0;
587130617Smlaier
588130617Smlaier	bzero(&b, sizeof(b));
589130617Smlaier	b.pfrb_type = PFRB_IFACES;
590130617Smlaier	for (;;) {
591130617Smlaier		pfr_buf_grow(&b, b.pfrb_size);
592130617Smlaier		b.pfrb_size = b.pfrb_msize;
593171172Smlaier		if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) {
594130617Smlaier			radix_perror();
595130617Smlaier			return (1);
596130617Smlaier		}
597130617Smlaier		if (b.pfrb_size <= b.pfrb_msize)
598130617Smlaier			break;
599130617Smlaier		i++;
600130617Smlaier	}
601130617Smlaier	if (opts & PF_OPT_SHOWALL)
602130617Smlaier		pfctl_print_title("INTERFACES:");
603130617Smlaier	PFRB_FOREACH(p, &b)
604130617Smlaier		print_iface(p, opts);
605130617Smlaier	return (0);
606130617Smlaier}
607130617Smlaier
608130617Smlaiervoid
609171172Smlaierprint_iface(struct pfi_kif *p, int opts)
610130617Smlaier{
611171172Smlaier	time_t	tzero = p->pfik_tzero;
612130617Smlaier	int	i, af, dir, act;
613130617Smlaier
614171172Smlaier	printf("%s", p->pfik_name);
615171172Smlaier	if (opts & PF_OPT_VERBOSE) {
616171172Smlaier		if (p->pfik_flags & PFI_IFLAG_SKIP)
617171172Smlaier			printf(" (skip)");
618171172Smlaier	}
619130617Smlaier	printf("\n");
620130617Smlaier
621130617Smlaier	if (!(opts & PF_OPT_VERBOSE2))
622130617Smlaier		return;
623130617Smlaier	printf("\tCleared:     %s", ctime(&tzero));
624240233Sglebius	printf("\tReferences:  %-18d\n", p->pfik_rulerefs);
625130617Smlaier	for (i = 0; i < 8; i++) {
626130617Smlaier		af = (i>>2) & 1;
627130617Smlaier		dir = (i>>1) &1;
628130617Smlaier		act = i & 1;
629130617Smlaier		printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
630130617Smlaier		    istats_text[af][dir][act],
631171172Smlaier		    (unsigned long long)p->pfik_packets[af][dir][act],
632171172Smlaier		    (unsigned long long)p->pfik_bytes[af][dir][act]);
633130617Smlaier	}
634130617Smlaier}
635