]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/pfctl/pfctl.c
pfctl: Improve set skip handling for groups
[FreeBSD/FreeBSD.git] / sbin / pfctl / pfctl.c
1 /*      $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */
2
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2001 Daniel Hartmeier
7  * Copyright (c) 2002,2003 Henning Brauer
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  *    - Redistributions of source code must retain the above copyright
15  *      notice, this list of conditions and the following disclaimer.
16  *    - Redistributions in binary form must reproduce the above
17  *      copyright notice, this list of conditions and the following
18  *      disclaimer in the documentation and/or other materials provided
19  *      with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/types.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <sys/endian.h>
44
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <net/pfvar.h>
48 #include <arpa/inet.h>
49 #include <net/altq/altq.h>
50 #include <sys/sysctl.h>
51
52 #include <err.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <limits.h>
56 #include <netdb.h>
57 #include <stdint.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62
63 #include "pfctl_parser.h"
64 #include "pfctl.h"
65
66 void     usage(void);
67 int      pfctl_enable(int, int);
68 int      pfctl_disable(int, int);
69 int      pfctl_clear_stats(int, int);
70 int      pfctl_get_skip_ifaces(void);
71 int      pfctl_check_skip_ifaces(char *);
72 int      pfctl_adjust_skip_ifaces(struct pfctl *);
73 int      pfctl_clear_interface_flags(int, int);
74 int      pfctl_clear_rules(int, int, char *);
75 int      pfctl_clear_nat(int, int, char *);
76 int      pfctl_clear_altq(int, int);
77 int      pfctl_clear_src_nodes(int, int);
78 int      pfctl_clear_states(int, const char *, int);
79 void     pfctl_addrprefix(char *, struct pf_addr *);
80 int      pfctl_kill_src_nodes(int, const char *, int);
81 int      pfctl_net_kill_states(int, const char *, int);
82 int      pfctl_label_kill_states(int, const char *, int);
83 int      pfctl_id_kill_states(int, const char *, int);
84 void     pfctl_init_options(struct pfctl *);
85 int      pfctl_load_options(struct pfctl *);
86 int      pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
87 int      pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
88 int      pfctl_load_debug(struct pfctl *, unsigned int);
89 int      pfctl_load_logif(struct pfctl *, char *);
90 int      pfctl_load_hostid(struct pfctl *, u_int32_t);
91 int      pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
92             char *);
93 void     pfctl_print_rule_counters(struct pf_rule *, int);
94 int      pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
95 int      pfctl_show_nat(int, int, char *);
96 int      pfctl_show_src_nodes(int, int);
97 int      pfctl_show_states(int, const char *, int);
98 int      pfctl_show_status(int, int);
99 int      pfctl_show_running(int);
100 int      pfctl_show_timeouts(int, int);
101 int      pfctl_show_limits(int, int);
102 void     pfctl_debug(int, u_int32_t, int);
103 int      pfctl_test_altqsupport(int, int);
104 int      pfctl_show_anchors(int, int, char *);
105 int      pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
106 int      pfctl_load_ruleset(struct pfctl *, char *,
107                 struct pf_ruleset *, int, int);
108 int      pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
109 const char      *pfctl_lookup_option(char *, const char * const *);
110
111 static struct pf_anchor_global   pf_anchors;
112 static struct pf_anchor  pf_main_anchor;
113 static struct pfr_buffer skip_b;
114
115 static const char       *clearopt;
116 static char             *rulesopt;
117 static const char       *showopt;
118 static const char       *debugopt;
119 static char             *anchoropt;
120 static const char       *optiopt = NULL;
121 static const char       *pf_device = "/dev/pf";
122 static char             *ifaceopt;
123 static char             *tableopt;
124 static const char       *tblcmdopt;
125 static int               src_node_killers;
126 static char             *src_node_kill[2];
127 static int               state_killers;
128 static char             *state_kill[2];
129 int                      loadopt;
130 int                      altqsupport;
131
132 int                      dev = -1;
133 static int               first_title = 1;
134 static int               labels = 0;
135
136 #define INDENT(d, o)    do {                                            \
137                                 if (o) {                                \
138                                         int i;                          \
139                                         for (i=0; i < d; i++)           \
140                                                 printf("  ");           \
141                                 }                                       \
142                         } while (0);                                    \
143
144
145 static const struct {
146         const char      *name;
147         int             index;
148 } pf_limits[] = {
149         { "states",             PF_LIMIT_STATES },
150         { "src-nodes",          PF_LIMIT_SRC_NODES },
151         { "frags",              PF_LIMIT_FRAGS },
152         { "table-entries",      PF_LIMIT_TABLE_ENTRIES },
153         { NULL,                 0 }
154 };
155
156 struct pf_hint {
157         const char      *name;
158         int             timeout;
159 };
160 static const struct pf_hint pf_hint_normal[] = {
161         { "tcp.first",          2 * 60 },
162         { "tcp.opening",        30 },
163         { "tcp.established",    24 * 60 * 60 },
164         { "tcp.closing",        15 * 60 },
165         { "tcp.finwait",        45 },
166         { "tcp.closed",         90 },
167         { "tcp.tsdiff",         30 },
168         { NULL,                 0 }
169 };
170 static const struct pf_hint pf_hint_satellite[] = {
171         { "tcp.first",          3 * 60 },
172         { "tcp.opening",        30 + 5 },
173         { "tcp.established",    24 * 60 * 60 },
174         { "tcp.closing",        15 * 60 + 5 },
175         { "tcp.finwait",        45 + 5 },
176         { "tcp.closed",         90 + 5 },
177         { "tcp.tsdiff",         60 },
178         { NULL,                 0 }
179 };
180 static const struct pf_hint pf_hint_conservative[] = {
181         { "tcp.first",          60 * 60 },
182         { "tcp.opening",        15 * 60 },
183         { "tcp.established",    5 * 24 * 60 * 60 },
184         { "tcp.closing",        60 * 60 },
185         { "tcp.finwait",        10 * 60 },
186         { "tcp.closed",         3 * 60 },
187         { "tcp.tsdiff",         60 },
188         { NULL,                 0 }
189 };
190 static const struct pf_hint pf_hint_aggressive[] = {
191         { "tcp.first",          30 },
192         { "tcp.opening",        5 },
193         { "tcp.established",    5 * 60 * 60 },
194         { "tcp.closing",        60 },
195         { "tcp.finwait",        30 },
196         { "tcp.closed",         30 },
197         { "tcp.tsdiff",         10 },
198         { NULL,                 0 }
199 };
200
201 static const struct {
202         const char *name;
203         const struct pf_hint *hint;
204 } pf_hints[] = {
205         { "normal",             pf_hint_normal },
206         { "satellite",          pf_hint_satellite },
207         { "high-latency",       pf_hint_satellite },
208         { "conservative",       pf_hint_conservative },
209         { "aggressive",         pf_hint_aggressive },
210         { NULL,                 NULL }
211 };
212
213 static const char * const clearopt_list[] = {
214         "nat", "queue", "rules", "Sources",
215         "states", "info", "Tables", "osfp", "all", NULL
216 };
217
218 static const char * const showopt_list[] = {
219         "nat", "queue", "rules", "Anchors", "Sources", "states", "info",
220         "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
221         "Running", "all", NULL
222 };
223
224 static const char * const tblcmdopt_list[] = {
225         "kill", "flush", "add", "delete", "load", "replace", "show",
226         "test", "zero", "expire", NULL
227 };
228
229 static const char * const debugopt_list[] = {
230         "none", "urgent", "misc", "loud", NULL
231 };
232
233 static const char * const optiopt_list[] = {
234         "none", "basic", "profile", NULL
235 };
236
237 void
238 usage(void)
239 {
240         extern char *__progname;
241
242         fprintf(stderr,
243 "usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
244         "\t[-f file] [-i interface] [-K host | network]\n"
245         "\t[-k host | network | label | id] [-o level] [-p device]\n"
246         "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
247             __progname);
248
249         exit(1);
250 }
251
252 int
253 pfctl_enable(int dev, int opts)
254 {
255         if (ioctl(dev, DIOCSTART)) {
256                 if (errno == EEXIST)
257                         errx(1, "pf already enabled");
258                 else if (errno == ESRCH)
259                         errx(1, "pfil registeration failed");
260                 else
261                         err(1, "DIOCSTART");
262         }
263         if ((opts & PF_OPT_QUIET) == 0)
264                 fprintf(stderr, "pf enabled\n");
265
266         if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
267                 if (errno != EEXIST)
268                         err(1, "DIOCSTARTALTQ");
269
270         return (0);
271 }
272
273 int
274 pfctl_disable(int dev, int opts)
275 {
276         if (ioctl(dev, DIOCSTOP)) {
277                 if (errno == ENOENT)
278                         errx(1, "pf not enabled");
279                 else
280                         err(1, "DIOCSTOP");
281         }
282         if ((opts & PF_OPT_QUIET) == 0)
283                 fprintf(stderr, "pf disabled\n");
284
285         if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
286                         if (errno != ENOENT)
287                                 err(1, "DIOCSTOPALTQ");
288
289         return (0);
290 }
291
292 int
293 pfctl_clear_stats(int dev, int opts)
294 {
295         if (ioctl(dev, DIOCCLRSTATUS))
296                 err(1, "DIOCCLRSTATUS");
297         if ((opts & PF_OPT_QUIET) == 0)
298                 fprintf(stderr, "pf: statistics cleared\n");
299         return (0);
300 }
301
302 int
303 pfctl_get_skip_ifaces(void)
304 {
305         bzero(&skip_b, sizeof(skip_b));
306         skip_b.pfrb_type = PFRB_IFACES;
307         for (;;) {
308                 pfr_buf_grow(&skip_b, skip_b.pfrb_size);
309                 skip_b.pfrb_size = skip_b.pfrb_msize;
310                 if (pfi_get_ifaces(NULL, skip_b.pfrb_caddr, &skip_b.pfrb_size))
311                         err(1, "pfi_get_ifaces");
312                 if (skip_b.pfrb_size <= skip_b.pfrb_msize)
313                         break;
314         }
315         return (0);
316 }
317
318 int
319 pfctl_check_skip_ifaces(char *ifname)
320 {
321         struct pfi_kif          *p;
322         struct node_host        *h = NULL, *n = NULL;
323
324         PFRB_FOREACH(p, &skip_b) {
325                 if (!strcmp(ifname, p->pfik_name) &&
326                     (p->pfik_flags & PFI_IFLAG_SKIP))
327                         p->pfik_flags &= ~PFI_IFLAG_SKIP;
328                 if (!strcmp(ifname, p->pfik_name) && p->pfik_group != NULL) {
329                         if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL)
330                                 continue;
331
332                         for (n = h; n != NULL; n = n->next) {
333                                 if (p->pfik_ifp == NULL)
334                                         continue;
335                                 if (strncmp(p->pfik_name, ifname, IFNAMSIZ))
336                                         continue;
337
338                                 p->pfik_flags &= ~PFI_IFLAG_SKIP;
339                         }
340                 }
341         }
342         return (0);
343 }
344
345 static void
346 pfctl_adjust_skip_ifaces_group_member(struct pfctl *pf, char *ifname)
347 {
348         struct pfi_kif *p;
349
350         PFRB_FOREACH(p, &skip_b) {
351                 if (p->pfik_ifp == NULL)
352                         continue;
353
354                 if (strncmp(p->pfik_name, ifname, IFNAMSIZ))
355                         continue;
356
357                 if (!(p->pfik_flags & PFI_IFLAG_SKIP))
358                         pfctl_set_interface_flags(pf, p->pfik_name,
359                           PFI_IFLAG_SKIP, 1);
360                 if (p->pfik_flags & PFI_IFLAG_SKIP)
361                         p->pfik_flags &= ~PFI_IFLAG_SKIP;
362         }
363 }
364
365 int
366 pfctl_adjust_skip_ifaces(struct pfctl *pf)
367 {
368         struct pfi_kif          *p, *pp;
369         struct node_host        *h = NULL, *n = NULL;
370
371         PFRB_FOREACH(p, &skip_b) {
372                 if (p->pfik_group == NULL || !(p->pfik_flags & PFI_IFLAG_SKIP))
373                         continue;
374
375                 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0);
376                 if ((h = ifa_grouplookup(p->pfik_name, 0)) == NULL)
377                         continue;
378
379                 for (n = h; n != NULL; n = n->next)
380                         PFRB_FOREACH(pp, &skip_b) {
381                                 if (pp->pfik_ifp == NULL)
382                                         continue;
383
384                                 if (strncmp(pp->pfik_name, n->ifname, IFNAMSIZ))
385                                         continue;
386
387                                 if (!(pp->pfik_flags & PFI_IFLAG_SKIP))
388                                         pfctl_set_interface_flags(pf,
389                                             pp->pfik_name, PFI_IFLAG_SKIP, 1);
390                                 if (pp->pfik_flags & PFI_IFLAG_SKIP)
391                                         pp->pfik_flags &= ~PFI_IFLAG_SKIP;
392                         }
393         }
394
395         PFRB_FOREACH(p, &skip_b) {
396                 if (p->pfik_ifp == NULL || ! (p->pfik_flags & PFI_IFLAG_SKIP))
397                         continue;
398
399                 pfctl_set_interface_flags(pf, p->pfik_name, PFI_IFLAG_SKIP, 0);
400         }
401
402         return (0);
403 }
404
405 int
406 pfctl_clear_interface_flags(int dev, int opts)
407 {
408         struct pfioc_iface      pi;
409
410         if ((opts & PF_OPT_NOACTION) == 0) {
411                 bzero(&pi, sizeof(pi));
412                 pi.pfiio_flags = PFI_IFLAG_SKIP;
413
414                 if (ioctl(dev, DIOCCLRIFFLAG, &pi))
415                         err(1, "DIOCCLRIFFLAG");
416                 if ((opts & PF_OPT_QUIET) == 0)
417                         fprintf(stderr, "pf: interface flags reset\n");
418         }
419         return (0);
420 }
421
422 int
423 pfctl_clear_rules(int dev, int opts, char *anchorname)
424 {
425         struct pfr_buffer t;
426
427         memset(&t, 0, sizeof(t));
428         t.pfrb_type = PFRB_TRANS;
429         if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
430             pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
431             pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
432             pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
433                 err(1, "pfctl_clear_rules");
434         if ((opts & PF_OPT_QUIET) == 0)
435                 fprintf(stderr, "rules cleared\n");
436         return (0);
437 }
438
439 int
440 pfctl_clear_nat(int dev, int opts, char *anchorname)
441 {
442         struct pfr_buffer t;
443
444         memset(&t, 0, sizeof(t));
445         t.pfrb_type = PFRB_TRANS;
446         if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
447             pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
448             pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
449             pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
450             pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
451                 err(1, "pfctl_clear_nat");
452         if ((opts & PF_OPT_QUIET) == 0)
453                 fprintf(stderr, "nat cleared\n");
454         return (0);
455 }
456
457 int
458 pfctl_clear_altq(int dev, int opts)
459 {
460         struct pfr_buffer t;
461
462         if (!altqsupport)
463                 return (-1);
464         memset(&t, 0, sizeof(t));
465         t.pfrb_type = PFRB_TRANS;
466         if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
467             pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
468             pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
469                 err(1, "pfctl_clear_altq");
470         if ((opts & PF_OPT_QUIET) == 0)
471                 fprintf(stderr, "altq cleared\n");
472         return (0);
473 }
474
475 int
476 pfctl_clear_src_nodes(int dev, int opts)
477 {
478         if (ioctl(dev, DIOCCLRSRCNODES))
479                 err(1, "DIOCCLRSRCNODES");
480         if ((opts & PF_OPT_QUIET) == 0)
481                 fprintf(stderr, "source tracking entries cleared\n");
482         return (0);
483 }
484
485 int
486 pfctl_clear_states(int dev, const char *iface, int opts)
487 {
488         struct pfioc_state_kill psk;
489
490         memset(&psk, 0, sizeof(psk));
491         if (iface != NULL && strlcpy(psk.psk_ifname, iface,
492             sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
493                 errx(1, "invalid interface: %s", iface);
494
495         if (ioctl(dev, DIOCCLRSTATES, &psk))
496                 err(1, "DIOCCLRSTATES");
497         if ((opts & PF_OPT_QUIET) == 0)
498                 fprintf(stderr, "%d states cleared\n", psk.psk_killed);
499         return (0);
500 }
501
502 void
503 pfctl_addrprefix(char *addr, struct pf_addr *mask)
504 {
505         char *p;
506         const char *errstr;
507         int prefix, ret_ga, q, r;
508         struct addrinfo hints, *res;
509
510         if ((p = strchr(addr, '/')) == NULL)
511                 return;
512
513         *p++ = '\0';
514         prefix = strtonum(p, 0, 128, &errstr);
515         if (errstr)
516                 errx(1, "prefix is %s: %s", errstr, p);
517
518         bzero(&hints, sizeof(hints));
519         /* prefix only with numeric addresses */
520         hints.ai_flags |= AI_NUMERICHOST;
521
522         if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
523                 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
524                 /* NOTREACHED */
525         }
526
527         if (res->ai_family == AF_INET && prefix > 32)
528                 errx(1, "prefix too long for AF_INET");
529         else if (res->ai_family == AF_INET6 && prefix > 128)
530                 errx(1, "prefix too long for AF_INET6");
531
532         q = prefix >> 3;
533         r = prefix & 7;
534         switch (res->ai_family) {
535         case AF_INET:
536                 bzero(&mask->v4, sizeof(mask->v4));
537                 mask->v4.s_addr = htonl((u_int32_t)
538                     (0xffffffffffULL << (32 - prefix)));
539                 break;
540         case AF_INET6:
541                 bzero(&mask->v6, sizeof(mask->v6));
542                 if (q > 0)
543                         memset((void *)&mask->v6, 0xff, q);
544                 if (r > 0)
545                         *((u_char *)&mask->v6 + q) =
546                             (0xff00 >> r) & 0xff;
547                 break;
548         }
549         freeaddrinfo(res);
550 }
551
552 int
553 pfctl_kill_src_nodes(int dev, const char *iface, int opts)
554 {
555         struct pfioc_src_node_kill psnk;
556         struct addrinfo *res[2], *resp[2];
557         struct sockaddr last_src, last_dst;
558         int killed, sources, dests;
559         int ret_ga;
560
561         killed = sources = dests = 0;
562
563         memset(&psnk, 0, sizeof(psnk));
564         memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
565             sizeof(psnk.psnk_src.addr.v.a.mask));
566         memset(&last_src, 0xff, sizeof(last_src));
567         memset(&last_dst, 0xff, sizeof(last_dst));
568
569         pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
570
571         if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
572                 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
573                 /* NOTREACHED */
574         }
575         for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
576                 if (resp[0]->ai_addr == NULL)
577                         continue;
578                 /* We get lots of duplicates.  Catch the easy ones */
579                 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
580                         continue;
581                 last_src = *(struct sockaddr *)resp[0]->ai_addr;
582
583                 psnk.psnk_af = resp[0]->ai_family;
584                 sources++;
585
586                 if (psnk.psnk_af == AF_INET)
587                         psnk.psnk_src.addr.v.a.addr.v4 =
588                             ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
589                 else if (psnk.psnk_af == AF_INET6)
590                         psnk.psnk_src.addr.v.a.addr.v6 =
591                             ((struct sockaddr_in6 *)resp[0]->ai_addr)->
592                             sin6_addr;
593                 else
594                         errx(1, "Unknown address family %d", psnk.psnk_af);
595
596                 if (src_node_killers > 1) {
597                         dests = 0;
598                         memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
599                             sizeof(psnk.psnk_dst.addr.v.a.mask));
600                         memset(&last_dst, 0xff, sizeof(last_dst));
601                         pfctl_addrprefix(src_node_kill[1],
602                             &psnk.psnk_dst.addr.v.a.mask);
603                         if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
604                             &res[1]))) {
605                                 errx(1, "getaddrinfo: %s",
606                                     gai_strerror(ret_ga));
607                                 /* NOTREACHED */
608                         }
609                         for (resp[1] = res[1]; resp[1];
610                             resp[1] = resp[1]->ai_next) {
611                                 if (resp[1]->ai_addr == NULL)
612                                         continue;
613                                 if (psnk.psnk_af != resp[1]->ai_family)
614                                         continue;
615
616                                 if (memcmp(&last_dst, resp[1]->ai_addr,
617                                     sizeof(last_dst)) == 0)
618                                         continue;
619                                 last_dst = *(struct sockaddr *)resp[1]->ai_addr;
620
621                                 dests++;
622
623                                 if (psnk.psnk_af == AF_INET)
624                                         psnk.psnk_dst.addr.v.a.addr.v4 =
625                                             ((struct sockaddr_in *)resp[1]->
626                                             ai_addr)->sin_addr;
627                                 else if (psnk.psnk_af == AF_INET6)
628                                         psnk.psnk_dst.addr.v.a.addr.v6 =
629                                             ((struct sockaddr_in6 *)resp[1]->
630                                             ai_addr)->sin6_addr;
631                                 else
632                                         errx(1, "Unknown address family %d",
633                                             psnk.psnk_af);
634
635                                 if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
636                                         err(1, "DIOCKILLSRCNODES");
637                                 killed += psnk.psnk_killed;
638                         }
639                         freeaddrinfo(res[1]);
640                 } else {
641                         if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
642                                 err(1, "DIOCKILLSRCNODES");
643                         killed += psnk.psnk_killed;
644                 }
645         }
646
647         freeaddrinfo(res[0]);
648
649         if ((opts & PF_OPT_QUIET) == 0)
650                 fprintf(stderr, "killed %d src nodes from %d sources and %d "
651                     "destinations\n", killed, sources, dests);
652         return (0);
653 }
654
655 int
656 pfctl_net_kill_states(int dev, const char *iface, int opts)
657 {
658         struct pfioc_state_kill psk;
659         struct addrinfo *res[2], *resp[2];
660         struct sockaddr last_src, last_dst;
661         int killed, sources, dests;
662         int ret_ga;
663
664         killed = sources = dests = 0;
665
666         memset(&psk, 0, sizeof(psk));
667         memset(&psk.psk_src.addr.v.a.mask, 0xff,
668             sizeof(psk.psk_src.addr.v.a.mask));
669         memset(&last_src, 0xff, sizeof(last_src));
670         memset(&last_dst, 0xff, sizeof(last_dst));
671         if (iface != NULL && strlcpy(psk.psk_ifname, iface,
672             sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
673                 errx(1, "invalid interface: %s", iface);
674
675         pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
676
677         if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
678                 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
679                 /* NOTREACHED */
680         }
681         for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
682                 if (resp[0]->ai_addr == NULL)
683                         continue;
684                 /* We get lots of duplicates.  Catch the easy ones */
685                 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
686                         continue;
687                 last_src = *(struct sockaddr *)resp[0]->ai_addr;
688
689                 psk.psk_af = resp[0]->ai_family;
690                 sources++;
691
692                 if (psk.psk_af == AF_INET)
693                         psk.psk_src.addr.v.a.addr.v4 =
694                             ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
695                 else if (psk.psk_af == AF_INET6)
696                         psk.psk_src.addr.v.a.addr.v6 =
697                             ((struct sockaddr_in6 *)resp[0]->ai_addr)->
698                             sin6_addr;
699                 else
700                         errx(1, "Unknown address family %d", psk.psk_af);
701
702                 if (state_killers > 1) {
703                         dests = 0;
704                         memset(&psk.psk_dst.addr.v.a.mask, 0xff,
705                             sizeof(psk.psk_dst.addr.v.a.mask));
706                         memset(&last_dst, 0xff, sizeof(last_dst));
707                         pfctl_addrprefix(state_kill[1],
708                             &psk.psk_dst.addr.v.a.mask);
709                         if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
710                             &res[1]))) {
711                                 errx(1, "getaddrinfo: %s",
712                                     gai_strerror(ret_ga));
713                                 /* NOTREACHED */
714                         }
715                         for (resp[1] = res[1]; resp[1];
716                             resp[1] = resp[1]->ai_next) {
717                                 if (resp[1]->ai_addr == NULL)
718                                         continue;
719                                 if (psk.psk_af != resp[1]->ai_family)
720                                         continue;
721
722                                 if (memcmp(&last_dst, resp[1]->ai_addr,
723                                     sizeof(last_dst)) == 0)
724                                         continue;
725                                 last_dst = *(struct sockaddr *)resp[1]->ai_addr;
726
727                                 dests++;
728
729                                 if (psk.psk_af == AF_INET)
730                                         psk.psk_dst.addr.v.a.addr.v4 =
731                                             ((struct sockaddr_in *)resp[1]->
732                                             ai_addr)->sin_addr;
733                                 else if (psk.psk_af == AF_INET6)
734                                         psk.psk_dst.addr.v.a.addr.v6 =
735                                             ((struct sockaddr_in6 *)resp[1]->
736                                             ai_addr)->sin6_addr;
737                                 else
738                                         errx(1, "Unknown address family %d",
739                                             psk.psk_af);
740
741                                 if (ioctl(dev, DIOCKILLSTATES, &psk))
742                                         err(1, "DIOCKILLSTATES");
743                                 killed += psk.psk_killed;
744                         }
745                         freeaddrinfo(res[1]);
746                 } else {
747                         if (ioctl(dev, DIOCKILLSTATES, &psk))
748                                 err(1, "DIOCKILLSTATES");
749                         killed += psk.psk_killed;
750                 }
751         }
752
753         freeaddrinfo(res[0]);
754
755         if ((opts & PF_OPT_QUIET) == 0)
756                 fprintf(stderr, "killed %d states from %d sources and %d "
757                     "destinations\n", killed, sources, dests);
758         return (0);
759 }
760
761 int
762 pfctl_label_kill_states(int dev, const char *iface, int opts)
763 {
764         struct pfioc_state_kill psk;
765
766         if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
767                 warnx("no label specified");
768                 usage();
769         }
770         memset(&psk, 0, sizeof(psk));
771         if (iface != NULL && strlcpy(psk.psk_ifname, iface,
772             sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
773                 errx(1, "invalid interface: %s", iface);
774
775         if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
776             sizeof(psk.psk_label))
777                 errx(1, "label too long: %s", state_kill[1]);
778
779         if (ioctl(dev, DIOCKILLSTATES, &psk))
780                 err(1, "DIOCKILLSTATES");
781
782         if ((opts & PF_OPT_QUIET) == 0)
783                 fprintf(stderr, "killed %d states\n", psk.psk_killed);
784
785         return (0);
786 }
787
788 int
789 pfctl_id_kill_states(int dev, const char *iface, int opts)
790 {
791         struct pfioc_state_kill psk;
792         
793         if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
794                 warnx("no id specified");
795                 usage();
796         }
797
798         memset(&psk, 0, sizeof(psk));
799         if ((sscanf(state_kill[1], "%jx/%x",
800             &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
801                 HTONL(psk.psk_pfcmp.creatorid);
802         else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
803                 psk.psk_pfcmp.creatorid = 0;
804         } else {
805                 warnx("wrong id format specified");
806                 usage();
807         }
808         if (psk.psk_pfcmp.id == 0) {
809                 warnx("cannot kill id 0");
810                 usage();
811         }
812
813         psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
814         if (ioctl(dev, DIOCKILLSTATES, &psk))
815                 err(1, "DIOCKILLSTATES");
816
817         if ((opts & PF_OPT_QUIET) == 0)
818                 fprintf(stderr, "killed %d states\n", psk.psk_killed);
819
820         return (0);
821 }
822
823 int
824 pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
825     u_int32_t ticket, int r_action, char *anchorname)
826 {
827         struct pfioc_pooladdr pp;
828         struct pf_pooladdr *pa;
829         u_int32_t pnr, mpnr;
830
831         memset(&pp, 0, sizeof(pp));
832         memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
833         pp.r_action = r_action;
834         pp.r_num = nr;
835         pp.ticket = ticket;
836         if (ioctl(dev, DIOCGETADDRS, &pp)) {
837                 warn("DIOCGETADDRS");
838                 return (-1);
839         }
840         mpnr = pp.nr;
841         TAILQ_INIT(&pool->list);
842         for (pnr = 0; pnr < mpnr; ++pnr) {
843                 pp.nr = pnr;
844                 if (ioctl(dev, DIOCGETADDR, &pp)) {
845                         warn("DIOCGETADDR");
846                         return (-1);
847                 }
848                 pa = calloc(1, sizeof(struct pf_pooladdr));
849                 if (pa == NULL)
850                         err(1, "calloc");
851                 bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
852                 TAILQ_INSERT_TAIL(&pool->list, pa, entries);
853         }
854
855         return (0);
856 }
857
858 void
859 pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
860 {
861         struct pf_pooladdr *pa;
862
863         while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
864                 TAILQ_REMOVE(&src->list, pa, entries);
865                 TAILQ_INSERT_TAIL(&dst->list, pa, entries);
866         }
867 }
868
869 void
870 pfctl_clear_pool(struct pf_pool *pool)
871 {
872         struct pf_pooladdr *pa;
873
874         while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
875                 TAILQ_REMOVE(&pool->list, pa, entries);
876                 free(pa);
877         }
878 }
879
880 void
881 pfctl_print_rule_counters(struct pf_rule *rule, int opts)
882 {
883         if (opts & PF_OPT_DEBUG) {
884                 const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
885                     "p", "sa", "sp", "da", "dp" };
886                 int i;
887
888                 printf("  [ Skip steps: ");
889                 for (i = 0; i < PF_SKIP_COUNT; ++i) {
890                         if (rule->skip[i].nr == rule->nr + 1)
891                                 continue;
892                         printf("%s=", t[i]);
893                         if (rule->skip[i].nr == -1)
894                                 printf("end ");
895                         else
896                                 printf("%u ", rule->skip[i].nr);
897                 }
898                 printf("]\n");
899
900                 printf("  [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
901                     rule->qname, rule->qid, rule->pqname, rule->pqid);
902         }
903         if (opts & PF_OPT_VERBOSE) {
904                 printf("  [ Evaluations: %-8llu  Packets: %-8llu  "
905                             "Bytes: %-10llu  States: %-6ju]\n",
906                             (unsigned long long)rule->evaluations,
907                             (unsigned long long)(rule->packets[0] +
908                             rule->packets[1]),
909                             (unsigned long long)(rule->bytes[0] +
910                             rule->bytes[1]), (uintmax_t)rule->u_states_cur);
911                 if (!(opts & PF_OPT_DEBUG))
912                         printf("  [ Inserted: uid %u pid %u "
913                             "State Creations: %-6ju]\n",
914                             (unsigned)rule->cuid, (unsigned)rule->cpid,
915                             (uintmax_t)rule->u_states_tot);
916         }
917 }
918
919 void
920 pfctl_print_title(char *title)
921 {
922         if (!first_title)
923                 printf("\n");
924         first_title = 0;
925         printf("%s\n", title);
926 }
927
928 int
929 pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
930     char *anchorname, int depth)
931 {
932         struct pfioc_rule pr;
933         u_int32_t nr, mnr, header = 0;
934         int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
935         int numeric = opts & PF_OPT_NUMERIC;
936         int len = strlen(path);
937         int brace;
938         char *p;
939
940         if (path[0])
941                 snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
942         else
943                 snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
944
945         memset(&pr, 0, sizeof(pr));
946         memcpy(pr.anchor, path, sizeof(pr.anchor));
947         if (opts & PF_OPT_SHOWALL) {
948                 pr.rule.action = PF_PASS;
949                 if (ioctl(dev, DIOCGETRULES, &pr)) {
950                         warn("DIOCGETRULES");
951                         goto error;
952                 }
953                 header++;
954         }
955         pr.rule.action = PF_SCRUB;
956         if (ioctl(dev, DIOCGETRULES, &pr)) {
957                 warn("DIOCGETRULES");
958                 goto error;
959         }
960         if (opts & PF_OPT_SHOWALL) {
961                 if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
962                         pfctl_print_title("FILTER RULES:");
963                 else if (format == PFCTL_SHOW_LABELS && labels)
964                         pfctl_print_title("LABEL COUNTERS:");
965         }
966         mnr = pr.nr;
967         if (opts & PF_OPT_CLRRULECTRS)
968                 pr.action = PF_GET_CLR_CNTR;
969
970         for (nr = 0; nr < mnr; ++nr) {
971                 pr.nr = nr;
972                 if (ioctl(dev, DIOCGETRULE, &pr)) {
973                         warn("DIOCGETRULE");
974                         goto error;
975                 }
976
977                 if (pfctl_get_pool(dev, &pr.rule.rpool,
978                     nr, pr.ticket, PF_SCRUB, path) != 0)
979                         goto error;
980
981                 switch (format) {
982                 case PFCTL_SHOW_LABELS:
983                         break;
984                 case PFCTL_SHOW_RULES:
985                         if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
986                                 labels = 1;
987                         print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
988                         printf("\n");
989                         pfctl_print_rule_counters(&pr.rule, opts);
990                         break;
991                 case PFCTL_SHOW_NOTHING:
992                         break;
993                 }
994                 pfctl_clear_pool(&pr.rule.rpool);
995         }
996         pr.rule.action = PF_PASS;
997         if (ioctl(dev, DIOCGETRULES, &pr)) {
998                 warn("DIOCGETRULES");
999                 goto error;
1000         }
1001         mnr = pr.nr;
1002         for (nr = 0; nr < mnr; ++nr) {
1003                 pr.nr = nr;
1004                 if (ioctl(dev, DIOCGETRULE, &pr)) {
1005                         warn("DIOCGETRULE");
1006                         goto error;
1007                 }
1008
1009                 if (pfctl_get_pool(dev, &pr.rule.rpool,
1010                     nr, pr.ticket, PF_PASS, path) != 0)
1011                         goto error;
1012
1013                 switch (format) {
1014                 case PFCTL_SHOW_LABELS:
1015                         if (pr.rule.label[0]) {
1016                                 printf("%s %llu %llu %llu %llu"
1017                                     " %llu %llu %llu %ju\n",
1018                                     pr.rule.label,
1019                                     (unsigned long long)pr.rule.evaluations,
1020                                     (unsigned long long)(pr.rule.packets[0] +
1021                                     pr.rule.packets[1]),
1022                                     (unsigned long long)(pr.rule.bytes[0] +
1023                                     pr.rule.bytes[1]),
1024                                     (unsigned long long)pr.rule.packets[0],
1025                                     (unsigned long long)pr.rule.bytes[0],
1026                                     (unsigned long long)pr.rule.packets[1],
1027                                     (unsigned long long)pr.rule.bytes[1],
1028                                     (uintmax_t)pr.rule.u_states_tot);
1029                         }
1030                         break;
1031                 case PFCTL_SHOW_RULES:
1032                         brace = 0;
1033                         if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
1034                                 labels = 1;
1035                         INDENT(depth, !(opts & PF_OPT_VERBOSE));
1036                         if (pr.anchor_call[0] &&
1037                            ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
1038                            ((void *)p == (void *)pr.anchor_call ||
1039                            *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
1040                                 brace++;
1041                                 if ((p = strrchr(pr.anchor_call, '/')) !=
1042                                     NULL)
1043                                         p++;
1044                                 else
1045                                         p = &pr.anchor_call[0];
1046                         } else
1047                                 p = &pr.anchor_call[0];
1048                 
1049                         print_rule(&pr.rule, p, rule_numbers, numeric);
1050                         if (brace)
1051                                 printf(" {\n");
1052                         else
1053                                 printf("\n");
1054                         pfctl_print_rule_counters(&pr.rule, opts);
1055                         if (brace) { 
1056                                 pfctl_show_rules(dev, path, opts, format,
1057                                     p, depth + 1);
1058                                 INDENT(depth, !(opts & PF_OPT_VERBOSE));
1059                                 printf("}\n");
1060                         }
1061                         break;
1062                 case PFCTL_SHOW_NOTHING:
1063                         break;
1064                 }
1065                 pfctl_clear_pool(&pr.rule.rpool);
1066         }
1067         path[len] = '\0';
1068         return (0);
1069
1070  error:
1071         path[len] = '\0';
1072         return (-1);
1073 }
1074
1075 int
1076 pfctl_show_nat(int dev, int opts, char *anchorname)
1077 {
1078         struct pfioc_rule pr;
1079         u_int32_t mnr, nr;
1080         static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
1081         int i, dotitle = opts & PF_OPT_SHOWALL;
1082
1083         memset(&pr, 0, sizeof(pr));
1084         memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
1085         for (i = 0; i < 3; i++) {
1086                 pr.rule.action = nattype[i];
1087                 if (ioctl(dev, DIOCGETRULES, &pr)) {
1088                         warn("DIOCGETRULES");
1089                         return (-1);
1090                 }
1091                 mnr = pr.nr;
1092                 for (nr = 0; nr < mnr; ++nr) {
1093                         pr.nr = nr;
1094                         if (ioctl(dev, DIOCGETRULE, &pr)) {
1095                                 warn("DIOCGETRULE");
1096                                 return (-1);
1097                         }
1098                         if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
1099                             pr.ticket, nattype[i], anchorname) != 0)
1100                                 return (-1);
1101                         if (dotitle) {
1102                                 pfctl_print_title("TRANSLATION RULES:");
1103                                 dotitle = 0;
1104                         }
1105                         print_rule(&pr.rule, pr.anchor_call,
1106                             opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
1107                         printf("\n");
1108                         pfctl_print_rule_counters(&pr.rule, opts);
1109                         pfctl_clear_pool(&pr.rule.rpool);
1110                 }
1111         }
1112         return (0);
1113 }
1114
1115 int
1116 pfctl_show_src_nodes(int dev, int opts)
1117 {
1118         struct pfioc_src_nodes psn;
1119         struct pf_src_node *p;
1120         char *inbuf = NULL, *newinbuf = NULL;
1121         unsigned int len = 0;
1122         int i;
1123
1124         memset(&psn, 0, sizeof(psn));
1125         for (;;) {
1126                 psn.psn_len = len;
1127                 if (len) {
1128                         newinbuf = realloc(inbuf, len);
1129                         if (newinbuf == NULL)
1130                                 err(1, "realloc");
1131                         psn.psn_buf = inbuf = newinbuf;
1132                 }
1133                 if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
1134                         warn("DIOCGETSRCNODES");
1135                         free(inbuf);
1136                         return (-1);
1137                 }
1138                 if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
1139                         break;
1140                 if (len == 0 && psn.psn_len == 0)
1141                         goto done;
1142                 if (len == 0 && psn.psn_len != 0)
1143                         len = psn.psn_len;
1144                 if (psn.psn_len == 0)
1145                         goto done;      /* no src_nodes */
1146                 len *= 2;
1147         }
1148         p = psn.psn_src_nodes;
1149         if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
1150                 pfctl_print_title("SOURCE TRACKING NODES:");
1151         for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
1152                 print_src_node(p, opts);
1153                 p++;
1154         }
1155 done:
1156         free(inbuf);
1157         return (0);
1158 }
1159
1160 int
1161 pfctl_show_states(int dev, const char *iface, int opts)
1162 {
1163         struct pfioc_states ps;
1164         struct pfsync_state *p;
1165         char *inbuf = NULL, *newinbuf = NULL;
1166         unsigned int len = 0;
1167         int i, dotitle = (opts & PF_OPT_SHOWALL);
1168
1169         memset(&ps, 0, sizeof(ps));
1170         for (;;) {
1171                 ps.ps_len = len;
1172                 if (len) {
1173                         newinbuf = realloc(inbuf, len);
1174                         if (newinbuf == NULL)
1175                                 err(1, "realloc");
1176                         ps.ps_buf = inbuf = newinbuf;
1177                 }
1178                 if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
1179                         warn("DIOCGETSTATES");
1180                         free(inbuf);
1181                         return (-1);
1182                 }
1183                 if (ps.ps_len + sizeof(struct pfioc_states) < len)
1184                         break;
1185                 if (len == 0 && ps.ps_len == 0)
1186                         goto done;
1187                 if (len == 0 && ps.ps_len != 0)
1188                         len = ps.ps_len;
1189                 if (ps.ps_len == 0)
1190                         goto done;      /* no states */
1191                 len *= 2;
1192         }
1193         p = ps.ps_states;
1194         for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
1195                 if (iface != NULL && strcmp(p->ifname, iface))
1196                         continue;
1197                 if (dotitle) {
1198                         pfctl_print_title("STATES:");
1199                         dotitle = 0;
1200                 }
1201                 print_state(p, opts);
1202         }
1203 done:
1204         free(inbuf);
1205         return (0);
1206 }
1207
1208 int
1209 pfctl_show_status(int dev, int opts)
1210 {
1211         struct pf_status status;
1212
1213         if (ioctl(dev, DIOCGETSTATUS, &status)) {
1214                 warn("DIOCGETSTATUS");
1215                 return (-1);
1216         }
1217         if (opts & PF_OPT_SHOWALL)
1218                 pfctl_print_title("INFO:");
1219         print_status(&status, opts);
1220         return (0);
1221 }
1222
1223 int
1224 pfctl_show_running(int dev)
1225 {
1226         struct pf_status status;
1227
1228         if (ioctl(dev, DIOCGETSTATUS, &status)) {
1229                 warn("DIOCGETSTATUS");
1230                 return (-1);
1231         }
1232
1233         print_running(&status);
1234         return (!status.running);
1235 }
1236
1237 int
1238 pfctl_show_timeouts(int dev, int opts)
1239 {
1240         struct pfioc_tm pt;
1241         int i;
1242
1243         if (opts & PF_OPT_SHOWALL)
1244                 pfctl_print_title("TIMEOUTS:");
1245         memset(&pt, 0, sizeof(pt));
1246         for (i = 0; pf_timeouts[i].name; i++) {
1247                 pt.timeout = pf_timeouts[i].timeout;
1248                 if (ioctl(dev, DIOCGETTIMEOUT, &pt))
1249                         err(1, "DIOCGETTIMEOUT");
1250                 printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
1251                 if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
1252                     pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
1253                         printf(" states");
1254                 else
1255                         printf("s");
1256                 printf("\n");
1257         }
1258         return (0);
1259
1260 }
1261
1262 int
1263 pfctl_show_limits(int dev, int opts)
1264 {
1265         struct pfioc_limit pl;
1266         int i;
1267
1268         if (opts & PF_OPT_SHOWALL)
1269                 pfctl_print_title("LIMITS:");
1270         memset(&pl, 0, sizeof(pl));
1271         for (i = 0; pf_limits[i].name; i++) {
1272                 pl.index = pf_limits[i].index;
1273                 if (ioctl(dev, DIOCGETLIMIT, &pl))
1274                         err(1, "DIOCGETLIMIT");
1275                 printf("%-13s ", pf_limits[i].name);
1276                 if (pl.limit == UINT_MAX)
1277                         printf("unlimited\n");
1278                 else
1279                         printf("hard limit %8u\n", pl.limit);
1280         }
1281         return (0);
1282 }
1283
1284 /* callbacks for rule/nat/rdr/addr */
1285 int
1286 pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
1287 {
1288         struct pf_pooladdr *pa;
1289
1290         if ((pf->opts & PF_OPT_NOACTION) == 0) {
1291                 if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
1292                         err(1, "DIOCBEGINADDRS");
1293         }
1294
1295         pf->paddr.af = af;
1296         TAILQ_FOREACH(pa, &p->list, entries) {
1297                 memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
1298                 if ((pf->opts & PF_OPT_NOACTION) == 0) {
1299                         if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
1300                                 err(1, "DIOCADDADDR");
1301                 }
1302         }
1303         return (0);
1304 }
1305
1306 int
1307 pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
1308 {
1309         u_int8_t                rs_num;
1310         struct pf_rule          *rule;
1311         struct pf_ruleset       *rs;
1312         char                    *p;
1313
1314         rs_num = pf_get_ruleset_number(r->action);
1315         if (rs_num == PF_RULESET_MAX)
1316                 errx(1, "Invalid rule type %d", r->action);
1317
1318         rs = &pf->anchor->ruleset;
1319
1320         if (anchor_call[0] && r->anchor == NULL) {
1321                 /* 
1322                  * Don't make non-brace anchors part of the main anchor pool.
1323                  */
1324                 if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
1325                         err(1, "pfctl_add_rule: calloc");
1326                 
1327                 pf_init_ruleset(&r->anchor->ruleset);
1328                 r->anchor->ruleset.anchor = r->anchor;
1329                 if (strlcpy(r->anchor->path, anchor_call,
1330                     sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
1331                         errx(1, "pfctl_add_rule: strlcpy");
1332                 if ((p = strrchr(anchor_call, '/')) != NULL) {
1333                         if (!strlen(p))
1334                                 err(1, "pfctl_add_rule: bad anchor name %s",
1335                                     anchor_call);
1336                 } else
1337                         p = (char *)anchor_call;
1338                 if (strlcpy(r->anchor->name, p,
1339                     sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
1340                         errx(1, "pfctl_add_rule: strlcpy");
1341         }
1342
1343         if ((rule = calloc(1, sizeof(*rule))) == NULL)
1344                 err(1, "calloc");
1345         bcopy(r, rule, sizeof(*rule));
1346         TAILQ_INIT(&rule->rpool.list);
1347         pfctl_move_pool(&r->rpool, &rule->rpool);
1348
1349         TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
1350         return (0);
1351 }
1352
1353 int
1354 pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
1355 {
1356         int osize = pf->trans->pfrb_size;
1357
1358         if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
1359                 if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
1360                     pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
1361                     pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
1362                         return (1);
1363         }
1364         if (a == pf->astack[0] && ((altqsupport &&
1365             (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
1366                 if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
1367                         return (2);
1368         }
1369         if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
1370                 if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
1371                     pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
1372                         return (3);
1373         }
1374         if (pf->loadopt & PFCTL_FLAG_TABLE)
1375                 if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
1376                         return (4);
1377         if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
1378                 return (5);
1379
1380         return (0);
1381 }
1382
1383 int
1384 pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
1385     int rs_num, int depth)
1386 {
1387         struct pf_rule *r;
1388         int             error, len = strlen(path);
1389         int             brace = 0;
1390
1391         pf->anchor = rs->anchor;
1392
1393         if (path[0])
1394                 snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
1395         else
1396                 snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
1397
1398         if (depth) {
1399                 if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
1400                         brace++;
1401                         if (pf->opts & PF_OPT_VERBOSE)
1402                                 printf(" {\n");
1403                         if ((pf->opts & PF_OPT_NOACTION) == 0 &&
1404                             (error = pfctl_ruleset_trans(pf,
1405                             path, rs->anchor))) {
1406                                 printf("pfctl_load_rulesets: "
1407                                     "pfctl_ruleset_trans %d\n", error);
1408                                 goto error;
1409                         }
1410                 } else if (pf->opts & PF_OPT_VERBOSE)
1411                         printf("\n");
1412
1413         }
1414
1415         if (pf->optimize && rs_num == PF_RULESET_FILTER)
1416                 pfctl_optimize_ruleset(pf, rs);
1417
1418         while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
1419                 TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
1420                 if ((error = pfctl_load_rule(pf, path, r, depth)))
1421                         goto error;
1422                 if (r->anchor) {
1423                         if ((error = pfctl_load_ruleset(pf, path,
1424                             &r->anchor->ruleset, rs_num, depth + 1)))
1425                                 goto error;
1426                 } else if (pf->opts & PF_OPT_VERBOSE)
1427                         printf("\n");
1428                 free(r);
1429         }
1430         if (brace && pf->opts & PF_OPT_VERBOSE) {
1431                 INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
1432                 printf("}\n");
1433         }
1434         path[len] = '\0';
1435         return (0);
1436
1437  error:
1438         path[len] = '\0';
1439         return (error);
1440
1441 }
1442
1443 int
1444 pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
1445 {
1446         u_int8_t                rs_num = pf_get_ruleset_number(r->action);
1447         char                    *name;
1448         struct pfioc_rule       pr;
1449         int                     len = strlen(path);
1450
1451         bzero(&pr, sizeof(pr));
1452         /* set up anchor before adding to path for anchor_call */
1453         if ((pf->opts & PF_OPT_NOACTION) == 0)
1454                 pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
1455         if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
1456                 errx(1, "pfctl_load_rule: strlcpy");
1457
1458         if (r->anchor) {
1459                 if (r->anchor->match) {
1460                         if (path[0])
1461                                 snprintf(&path[len], MAXPATHLEN - len,
1462                                     "/%s", r->anchor->name);
1463                         else
1464                                 snprintf(&path[len], MAXPATHLEN - len,
1465                                     "%s", r->anchor->name);
1466                         name = r->anchor->name;
1467                 } else
1468                         name = r->anchor->path;
1469         } else
1470                 name = "";
1471
1472         if ((pf->opts & PF_OPT_NOACTION) == 0) {
1473                 if (pfctl_add_pool(pf, &r->rpool, r->af))
1474                         return (1);
1475                 pr.pool_ticket = pf->paddr.ticket;
1476                 memcpy(&pr.rule, r, sizeof(pr.rule));
1477                 if (r->anchor && strlcpy(pr.anchor_call, name,
1478                     sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
1479                         errx(1, "pfctl_load_rule: strlcpy");
1480                 if (ioctl(pf->dev, DIOCADDRULE, &pr))
1481                         err(1, "DIOCADDRULE");
1482         }
1483
1484         if (pf->opts & PF_OPT_VERBOSE) {
1485                 INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
1486                 print_rule(r, r->anchor ? r->anchor->name : "",
1487                     pf->opts & PF_OPT_VERBOSE2,
1488                     pf->opts & PF_OPT_NUMERIC);
1489         }
1490         path[len] = '\0';
1491         pfctl_clear_pool(&r->rpool);
1492         return (0);
1493 }
1494
1495 int
1496 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
1497 {
1498         if (altqsupport &&
1499             (loadopt & PFCTL_FLAG_ALTQ) != 0) {
1500                 memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
1501                 if ((pf->opts & PF_OPT_NOACTION) == 0) {
1502                         if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
1503                                 if (errno == ENXIO)
1504                                         errx(1, "qtype not configured");
1505                                 else if (errno == ENODEV)
1506                                         errx(1, "%s: driver does not support "
1507                                             "altq", a->ifname);
1508                                 else
1509                                         err(1, "DIOCADDALTQ");
1510                         }
1511                 }
1512                 pfaltq_store(&pf->paltq->altq);
1513         }
1514         return (0);
1515 }
1516
1517 int
1518 pfctl_rules(int dev, char *filename, int opts, int optimize,
1519     char *anchorname, struct pfr_buffer *trans)
1520 {
1521 #define ERR(x) do { warn(x); goto _error; } while(0)
1522 #define ERRX(x) do { warnx(x); goto _error; } while(0)
1523
1524         struct pfr_buffer       *t, buf;
1525         struct pfioc_altq        pa;
1526         struct pfctl             pf;
1527         struct pf_ruleset       *rs;
1528         struct pfr_table         trs;
1529         char                    *path;
1530         int                      osize;
1531
1532         RB_INIT(&pf_anchors);
1533         memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
1534         pf_init_ruleset(&pf_main_anchor.ruleset);
1535         pf_main_anchor.ruleset.anchor = &pf_main_anchor;
1536         if (trans == NULL) {
1537                 bzero(&buf, sizeof(buf));
1538                 buf.pfrb_type = PFRB_TRANS;
1539                 t = &buf;
1540                 osize = 0;
1541         } else {
1542                 t = trans;
1543                 osize = t->pfrb_size;
1544         }
1545
1546         memset(&pa, 0, sizeof(pa));
1547         memset(&pf, 0, sizeof(pf));
1548         memset(&trs, 0, sizeof(trs));
1549         if ((path = calloc(1, MAXPATHLEN)) == NULL)
1550                 ERRX("pfctl_rules: calloc");
1551         if (strlcpy(trs.pfrt_anchor, anchorname,
1552             sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
1553                 ERRX("pfctl_rules: strlcpy");
1554         pf.dev = dev;
1555         pf.opts = opts;
1556         pf.optimize = optimize;
1557         pf.loadopt = loadopt;
1558
1559         /* non-brace anchor, create without resolving the path */
1560         if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
1561                 ERRX("pfctl_rules: calloc");
1562         rs = &pf.anchor->ruleset;
1563         pf_init_ruleset(rs);
1564         rs->anchor = pf.anchor;
1565         if (strlcpy(pf.anchor->path, anchorname,
1566             sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
1567                 errx(1, "pfctl_add_rule: strlcpy");
1568         if (strlcpy(pf.anchor->name, anchorname,
1569             sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
1570                 errx(1, "pfctl_add_rule: strlcpy");
1571
1572
1573         pf.astack[0] = pf.anchor;
1574         pf.asd = 0;
1575         if (anchorname[0])
1576                 pf.loadopt &= ~PFCTL_FLAG_ALTQ;
1577         pf.paltq = &pa;
1578         pf.trans = t;
1579         pfctl_init_options(&pf);
1580
1581         if ((opts & PF_OPT_NOACTION) == 0) {
1582                 /*
1583                  * XXX For the time being we need to open transactions for
1584                  * the main ruleset before parsing, because tables are still
1585                  * loaded at parse time.
1586                  */
1587                 if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
1588                         ERRX("pfctl_rules");
1589                 if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
1590                         pa.ticket =
1591                             pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
1592                 if (pf.loadopt & PFCTL_FLAG_TABLE)
1593                         pf.astack[0]->ruleset.tticket =
1594                             pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
1595         }
1596
1597         if (parse_config(filename, &pf) < 0) {
1598                 if ((opts & PF_OPT_NOACTION) == 0)
1599                         ERRX("Syntax error in config file: "
1600                             "pf rules not loaded");
1601                 else
1602                         goto _error;
1603         }
1604         if (loadopt & PFCTL_FLAG_OPTION)
1605                 pfctl_adjust_skip_ifaces(&pf);
1606
1607         if ((pf.loadopt & PFCTL_FLAG_FILTER &&
1608             (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
1609             (pf.loadopt & PFCTL_FLAG_NAT &&
1610             (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
1611             pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
1612             pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
1613             (pf.loadopt & PFCTL_FLAG_FILTER &&
1614             pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
1615                 if ((opts & PF_OPT_NOACTION) == 0)
1616                         ERRX("Unable to load rules into kernel");
1617                 else
1618                         goto _error;
1619         }
1620
1621         if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
1622                 if (check_commit_altq(dev, opts) != 0)
1623                         ERRX("errors in altq config");
1624
1625         /* process "load anchor" directives */
1626         if (!anchorname[0])
1627                 if (pfctl_load_anchors(dev, &pf, t) == -1)
1628                         ERRX("load anchors");
1629
1630         if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
1631                 if (!anchorname[0])
1632                         if (pfctl_load_options(&pf))
1633                                 goto _error;
1634                 if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
1635                         ERR("DIOCXCOMMIT");
1636         }
1637         free(path);
1638         return (0);
1639
1640 _error:
1641         if (trans == NULL) {    /* main ruleset */
1642                 if ((opts & PF_OPT_NOACTION) == 0)
1643                         if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
1644                                 err(1, "DIOCXROLLBACK");
1645                 exit(1);
1646         } else {                /* sub ruleset */
1647                 free(path);
1648                 return (-1);
1649         }
1650
1651 #undef ERR
1652 #undef ERRX
1653 }
1654
1655 FILE *
1656 pfctl_fopen(const char *name, const char *mode)
1657 {
1658         struct stat      st;
1659         FILE            *fp;
1660
1661         fp = fopen(name, mode);
1662         if (fp == NULL)
1663                 return (NULL);
1664         if (fstat(fileno(fp), &st)) {
1665                 fclose(fp);
1666                 return (NULL);
1667         }
1668         if (S_ISDIR(st.st_mode)) {
1669                 fclose(fp);
1670                 errno = EISDIR;
1671                 return (NULL);
1672         }
1673         return (fp);
1674 }
1675
1676 void
1677 pfctl_init_options(struct pfctl *pf)
1678 {
1679
1680         pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
1681         pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
1682         pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
1683         pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
1684         pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
1685         pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
1686         pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
1687         pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
1688         pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
1689         pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
1690         pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
1691         pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
1692         pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
1693         pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
1694         pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
1695         pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
1696         pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
1697         pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
1698         pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
1699         pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
1700
1701         pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
1702         pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
1703         pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
1704         pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
1705
1706         pf->debug = PF_DEBUG_URGENT;
1707 }
1708
1709 int
1710 pfctl_load_options(struct pfctl *pf)
1711 {
1712         int i, error = 0;
1713
1714         if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1715                 return (0);
1716
1717         /* load limits */
1718         for (i = 0; i < PF_LIMIT_MAX; i++) {
1719                 if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
1720                         continue;
1721                 if (pfctl_load_limit(pf, i, pf->limit[i]))
1722                         error = 1;
1723         }
1724
1725         /*
1726          * If we've set the limit, but haven't explicitly set adaptive
1727          * timeouts, do it now with a start of 60% and end of 120%.
1728          */
1729         if (pf->limit_set[PF_LIMIT_STATES] &&
1730             !pf->timeout_set[PFTM_ADAPTIVE_START] &&
1731             !pf->timeout_set[PFTM_ADAPTIVE_END]) {
1732                 pf->timeout[PFTM_ADAPTIVE_START] =
1733                         (pf->limit[PF_LIMIT_STATES] / 10) * 6;
1734                 pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
1735                 pf->timeout[PFTM_ADAPTIVE_END] =
1736                         (pf->limit[PF_LIMIT_STATES] / 10) * 12;
1737                 pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
1738         }
1739
1740         /* load timeouts */
1741         for (i = 0; i < PFTM_MAX; i++) {
1742                 if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
1743                         continue;
1744                 if (pfctl_load_timeout(pf, i, pf->timeout[i]))
1745                         error = 1;
1746         }
1747
1748         /* load debug */
1749         if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
1750                 if (pfctl_load_debug(pf, pf->debug))
1751                         error = 1;
1752
1753         /* load logif */
1754         if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
1755                 if (pfctl_load_logif(pf, pf->ifname))
1756                         error = 1;
1757
1758         /* load hostid */
1759         if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
1760                 if (pfctl_load_hostid(pf, pf->hostid))
1761                         error = 1;
1762
1763         return (error);
1764 }
1765
1766 int
1767 pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
1768 {
1769         int i;
1770
1771
1772         for (i = 0; pf_limits[i].name; i++) {
1773                 if (strcasecmp(opt, pf_limits[i].name) == 0) {
1774                         pf->limit[pf_limits[i].index] = limit;
1775                         pf->limit_set[pf_limits[i].index] = 1;
1776                         break;
1777                 }
1778         }
1779         if (pf_limits[i].name == NULL) {
1780                 warnx("Bad pool name.");
1781                 return (1);
1782         }
1783
1784         if (pf->opts & PF_OPT_VERBOSE)
1785                 printf("set limit %s %d\n", opt, limit);
1786
1787         return (0);
1788 }
1789
1790 int
1791 pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
1792 {
1793         struct pfioc_limit pl;
1794
1795         memset(&pl, 0, sizeof(pl));
1796         pl.index = index;
1797         pl.limit = limit;
1798         if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
1799                 if (errno == EBUSY)
1800                         warnx("Current pool size exceeds requested hard limit");
1801                 else
1802                         warnx("DIOCSETLIMIT");
1803                 return (1);
1804         }
1805         return (0);
1806 }
1807
1808 int
1809 pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
1810 {
1811         int i;
1812
1813         if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1814                 return (0);
1815
1816         for (i = 0; pf_timeouts[i].name; i++) {
1817                 if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
1818                         pf->timeout[pf_timeouts[i].timeout] = seconds;
1819                         pf->timeout_set[pf_timeouts[i].timeout] = 1;
1820                         break;
1821                 }
1822         }
1823
1824         if (pf_timeouts[i].name == NULL) {
1825                 warnx("Bad timeout name.");
1826                 return (1);
1827         }
1828
1829
1830         if (pf->opts & PF_OPT_VERBOSE && ! quiet)
1831                 printf("set timeout %s %d\n", opt, seconds);
1832
1833         return (0);
1834 }
1835
1836 int
1837 pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
1838 {
1839         struct pfioc_tm pt;
1840
1841         memset(&pt, 0, sizeof(pt));
1842         pt.timeout = timeout;
1843         pt.seconds = seconds;
1844         if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
1845                 warnx("DIOCSETTIMEOUT");
1846                 return (1);
1847         }
1848         return (0);
1849 }
1850
1851 int
1852 pfctl_set_optimization(struct pfctl *pf, const char *opt)
1853 {
1854         const struct pf_hint *hint;
1855         int i, r;
1856
1857         if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1858                 return (0);
1859
1860         for (i = 0; pf_hints[i].name; i++)
1861                 if (strcasecmp(opt, pf_hints[i].name) == 0)
1862                         break;
1863
1864         hint = pf_hints[i].hint;
1865         if (hint == NULL) {
1866                 warnx("invalid state timeouts optimization");
1867                 return (1);
1868         }
1869
1870         for (i = 0; hint[i].name; i++)
1871                 if ((r = pfctl_set_timeout(pf, hint[i].name,
1872                     hint[i].timeout, 1)))
1873                         return (r);
1874
1875         if (pf->opts & PF_OPT_VERBOSE)
1876                 printf("set optimization %s\n", opt);
1877
1878         return (0);
1879 }
1880
1881 int
1882 pfctl_set_logif(struct pfctl *pf, char *ifname)
1883 {
1884
1885         if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1886                 return (0);
1887
1888         if (!strcmp(ifname, "none")) {
1889                 free(pf->ifname);
1890                 pf->ifname = NULL;
1891         } else {
1892                 pf->ifname = strdup(ifname);
1893                 if (!pf->ifname)
1894                         errx(1, "pfctl_set_logif: strdup");
1895         }
1896         pf->ifname_set = 1;
1897
1898         if (pf->opts & PF_OPT_VERBOSE)
1899                 printf("set loginterface %s\n", ifname);
1900
1901         return (0);
1902 }
1903
1904 int
1905 pfctl_load_logif(struct pfctl *pf, char *ifname)
1906 {
1907         struct pfioc_if pi;
1908
1909         memset(&pi, 0, sizeof(pi));
1910         if (ifname && strlcpy(pi.ifname, ifname,
1911             sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
1912                 warnx("pfctl_load_logif: strlcpy");
1913                 return (1);
1914         }
1915         if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
1916                 warnx("DIOCSETSTATUSIF");
1917                 return (1);
1918         }
1919         return (0);
1920 }
1921
1922 int
1923 pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
1924 {
1925         if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1926                 return (0);
1927
1928         HTONL(hostid);
1929
1930         pf->hostid = hostid;
1931         pf->hostid_set = 1;
1932
1933         if (pf->opts & PF_OPT_VERBOSE)
1934                 printf("set hostid 0x%08x\n", ntohl(hostid));
1935
1936         return (0);
1937 }
1938
1939 int
1940 pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
1941 {
1942         if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
1943                 warnx("DIOCSETHOSTID");
1944                 return (1);
1945         }
1946         return (0);
1947 }
1948
1949 int
1950 pfctl_set_debug(struct pfctl *pf, char *d)
1951 {
1952         u_int32_t       level;
1953
1954         if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1955                 return (0);
1956
1957         if (!strcmp(d, "none"))
1958                 pf->debug = PF_DEBUG_NONE;
1959         else if (!strcmp(d, "urgent"))
1960                 pf->debug = PF_DEBUG_URGENT;
1961         else if (!strcmp(d, "misc"))
1962                 pf->debug = PF_DEBUG_MISC;
1963         else if (!strcmp(d, "loud"))
1964                 pf->debug = PF_DEBUG_NOISY;
1965         else {
1966                 warnx("unknown debug level \"%s\"", d);
1967                 return (-1);
1968         }
1969
1970         pf->debug_set = 1;
1971         level = pf->debug;
1972
1973         if ((pf->opts & PF_OPT_NOACTION) == 0)
1974                 if (ioctl(dev, DIOCSETDEBUG, &level))
1975                         err(1, "DIOCSETDEBUG");
1976
1977         if (pf->opts & PF_OPT_VERBOSE)
1978                 printf("set debug %s\n", d);
1979
1980         return (0);
1981 }
1982
1983 int
1984 pfctl_load_debug(struct pfctl *pf, unsigned int level)
1985 {
1986         if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
1987                 warnx("DIOCSETDEBUG");
1988                 return (1);
1989         }
1990         return (0);
1991 }
1992
1993 int
1994 pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
1995 {
1996         struct pfioc_iface      pi;
1997
1998         if ((loadopt & PFCTL_FLAG_OPTION) == 0)
1999                 return (0);
2000
2001         bzero(&pi, sizeof(pi));
2002
2003         pi.pfiio_flags = flags;
2004
2005         if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
2006             sizeof(pi.pfiio_name))
2007                 errx(1, "pfctl_set_interface_flags: strlcpy");
2008
2009         if ((pf->opts & PF_OPT_NOACTION) == 0) {
2010                 if (how == 0) {
2011                         if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
2012                                 err(1, "DIOCCLRIFFLAG");
2013                 } else {
2014                         if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
2015                                 err(1, "DIOCSETIFFLAG");
2016                         pfctl_check_skip_ifaces(ifname);
2017                 }
2018         }
2019         return (0);
2020 }
2021
2022 void
2023 pfctl_debug(int dev, u_int32_t level, int opts)
2024 {
2025         if (ioctl(dev, DIOCSETDEBUG, &level))
2026                 err(1, "DIOCSETDEBUG");
2027         if ((opts & PF_OPT_QUIET) == 0) {
2028                 fprintf(stderr, "debug level set to '");
2029                 switch (level) {
2030                 case PF_DEBUG_NONE:
2031                         fprintf(stderr, "none");
2032                         break;
2033                 case PF_DEBUG_URGENT:
2034                         fprintf(stderr, "urgent");
2035                         break;
2036                 case PF_DEBUG_MISC:
2037                         fprintf(stderr, "misc");
2038                         break;
2039                 case PF_DEBUG_NOISY:
2040                         fprintf(stderr, "loud");
2041                         break;
2042                 default:
2043                         fprintf(stderr, "<invalid>");
2044                         break;
2045                 }
2046                 fprintf(stderr, "'\n");
2047         }
2048 }
2049
2050 int
2051 pfctl_test_altqsupport(int dev, int opts)
2052 {
2053         struct pfioc_altq pa;
2054
2055         if (ioctl(dev, DIOCGETALTQS, &pa)) {
2056                 if (errno == ENODEV) {
2057                         if (opts & PF_OPT_VERBOSE)
2058                                 fprintf(stderr, "No ALTQ support in kernel\n"
2059                                     "ALTQ related functions disabled\n");
2060                         return (0);
2061                 } else
2062                         err(1, "DIOCGETALTQS");
2063         }
2064         return (1);
2065 }
2066
2067 int
2068 pfctl_show_anchors(int dev, int opts, char *anchorname)
2069 {
2070         struct pfioc_ruleset     pr;
2071         u_int32_t                mnr, nr;
2072
2073         memset(&pr, 0, sizeof(pr));
2074         memcpy(pr.path, anchorname, sizeof(pr.path));
2075         if (ioctl(dev, DIOCGETRULESETS, &pr)) {
2076                 if (errno == EINVAL)
2077                         fprintf(stderr, "Anchor '%s' not found.\n",
2078                             anchorname);
2079                 else
2080                         err(1, "DIOCGETRULESETS");
2081                 return (-1);
2082         }
2083         mnr = pr.nr;
2084         for (nr = 0; nr < mnr; ++nr) {
2085                 char sub[MAXPATHLEN];
2086
2087                 pr.nr = nr;
2088                 if (ioctl(dev, DIOCGETRULESET, &pr))
2089                         err(1, "DIOCGETRULESET");
2090                 if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
2091                         continue;
2092                 sub[0] = 0;
2093                 if (pr.path[0]) {
2094                         strlcat(sub, pr.path, sizeof(sub));
2095                         strlcat(sub, "/", sizeof(sub));
2096                 }
2097                 strlcat(sub, pr.name, sizeof(sub));
2098                 if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
2099                         printf("  %s\n", sub);
2100                 if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
2101                         return (-1);
2102         }
2103         return (0);
2104 }
2105
2106 const char *
2107 pfctl_lookup_option(char *cmd, const char * const *list)
2108 {
2109         if (cmd != NULL && *cmd)
2110                 for (; *list; list++)
2111                         if (!strncmp(cmd, *list, strlen(cmd)))
2112                                 return (*list);
2113         return (NULL);
2114 }
2115
2116 int
2117 main(int argc, char *argv[])
2118 {
2119         int      error = 0;
2120         int      ch;
2121         int      mode = O_RDONLY;
2122         int      opts = 0;
2123         int      optimize = PF_OPTIMIZE_BASIC;
2124         char     anchorname[MAXPATHLEN];
2125         char    *path;
2126
2127         if (argc < 2)
2128                 usage();
2129
2130         while ((ch = getopt(argc, argv,
2131             "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
2132                 switch (ch) {
2133                 case 'a':
2134                         anchoropt = optarg;
2135                         break;
2136                 case 'd':
2137                         opts |= PF_OPT_DISABLE;
2138                         mode = O_RDWR;
2139                         break;
2140                 case 'D':
2141                         if (pfctl_cmdline_symset(optarg) < 0)
2142                                 warnx("could not parse macro definition %s",
2143                                     optarg);
2144                         break;
2145                 case 'e':
2146                         opts |= PF_OPT_ENABLE;
2147                         mode = O_RDWR;
2148                         break;
2149                 case 'q':
2150                         opts |= PF_OPT_QUIET;
2151                         break;
2152                 case 'F':
2153                         clearopt = pfctl_lookup_option(optarg, clearopt_list);
2154                         if (clearopt == NULL) {
2155                                 warnx("Unknown flush modifier '%s'", optarg);
2156                                 usage();
2157                         }
2158                         mode = O_RDWR;
2159                         break;
2160                 case 'i':
2161                         ifaceopt = optarg;
2162                         break;
2163                 case 'k':
2164                         if (state_killers >= 2) {
2165                                 warnx("can only specify -k twice");
2166                                 usage();
2167                                 /* NOTREACHED */
2168                         }
2169                         state_kill[state_killers++] = optarg;
2170                         mode = O_RDWR;
2171                         break;
2172                 case 'K':
2173                         if (src_node_killers >= 2) {
2174                                 warnx("can only specify -K twice");
2175                                 usage();
2176                                 /* NOTREACHED */
2177                         }
2178                         src_node_kill[src_node_killers++] = optarg;
2179                         mode = O_RDWR;
2180                         break;
2181                 case 'm':
2182                         opts |= PF_OPT_MERGE;
2183                         break;
2184                 case 'n':
2185                         opts |= PF_OPT_NOACTION;
2186                         break;
2187                 case 'N':
2188                         loadopt |= PFCTL_FLAG_NAT;
2189                         break;
2190                 case 'r':
2191                         opts |= PF_OPT_USEDNS;
2192                         break;
2193                 case 'f':
2194                         rulesopt = optarg;
2195                         mode = O_RDWR;
2196                         break;
2197                 case 'g':
2198                         opts |= PF_OPT_DEBUG;
2199                         break;
2200                 case 'A':
2201                         loadopt |= PFCTL_FLAG_ALTQ;
2202                         break;
2203                 case 'R':
2204                         loadopt |= PFCTL_FLAG_FILTER;
2205                         break;
2206                 case 'o':
2207                         optiopt = pfctl_lookup_option(optarg, optiopt_list);
2208                         if (optiopt == NULL) {
2209                                 warnx("Unknown optimization '%s'", optarg);
2210                                 usage();
2211                         }
2212                         opts |= PF_OPT_OPTIMIZE;
2213                         break;
2214                 case 'O':
2215                         loadopt |= PFCTL_FLAG_OPTION;
2216                         break;
2217                 case 'p':
2218                         pf_device = optarg;
2219                         break;
2220                 case 'P':
2221                         opts |= PF_OPT_NUMERIC;
2222                         break;
2223                 case 's':
2224                         showopt = pfctl_lookup_option(optarg, showopt_list);
2225                         if (showopt == NULL) {
2226                                 warnx("Unknown show modifier '%s'", optarg);
2227                                 usage();
2228                         }
2229                         break;
2230                 case 't':
2231                         tableopt = optarg;
2232                         break;
2233                 case 'T':
2234                         tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
2235                         if (tblcmdopt == NULL) {
2236                                 warnx("Unknown table command '%s'", optarg);
2237                                 usage();
2238                         }
2239                         break;
2240                 case 'v':
2241                         if (opts & PF_OPT_VERBOSE)
2242                                 opts |= PF_OPT_VERBOSE2;
2243                         opts |= PF_OPT_VERBOSE;
2244                         break;
2245                 case 'x':
2246                         debugopt = pfctl_lookup_option(optarg, debugopt_list);
2247                         if (debugopt == NULL) {
2248                                 warnx("Unknown debug level '%s'", optarg);
2249                                 usage();
2250                         }
2251                         mode = O_RDWR;
2252                         break;
2253                 case 'z':
2254                         opts |= PF_OPT_CLRRULECTRS;
2255                         mode = O_RDWR;
2256                         break;
2257                 case 'h':
2258                         /* FALLTHROUGH */
2259                 default:
2260                         usage();
2261                         /* NOTREACHED */
2262                 }
2263         }
2264
2265         if (tblcmdopt != NULL) {
2266                 argc -= optind;
2267                 argv += optind;
2268                 ch = *tblcmdopt;
2269                 if (ch == 'l') {
2270                         loadopt |= PFCTL_FLAG_TABLE;
2271                         tblcmdopt = NULL;
2272                 } else
2273                         mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
2274         } else if (argc != optind) {
2275                 warnx("unknown command line argument: %s ...", argv[optind]);
2276                 usage();
2277                 /* NOTREACHED */
2278         }
2279         if (loadopt == 0)
2280                 loadopt = ~0;
2281
2282         if ((path = calloc(1, MAXPATHLEN)) == NULL)
2283                 errx(1, "pfctl: calloc");
2284         memset(anchorname, 0, sizeof(anchorname));
2285         if (anchoropt != NULL) {
2286                 int len = strlen(anchoropt);
2287
2288                 if (anchoropt[len - 1] == '*') {
2289                         if (len >= 2 && anchoropt[len - 2] == '/')
2290                                 anchoropt[len - 2] = '\0';
2291                         else
2292                                 anchoropt[len - 1] = '\0';
2293                         opts |= PF_OPT_RECURSE;
2294                 }
2295                 if (strlcpy(anchorname, anchoropt,
2296                     sizeof(anchorname)) >= sizeof(anchorname))
2297                         errx(1, "anchor name '%s' too long",
2298                             anchoropt);
2299                 loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
2300         }
2301
2302         if ((opts & PF_OPT_NOACTION) == 0) {
2303                 dev = open(pf_device, mode);
2304                 if (dev == -1)
2305                         err(1, "%s", pf_device);
2306                 altqsupport = pfctl_test_altqsupport(dev, opts);
2307         } else {
2308                 dev = open(pf_device, O_RDONLY);
2309                 if (dev >= 0)
2310                         opts |= PF_OPT_DUMMYACTION;
2311                 /* turn off options */
2312                 opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
2313                 clearopt = showopt = debugopt = NULL;
2314 #if !defined(ENABLE_ALTQ)
2315                 altqsupport = 0;
2316 #else
2317                 altqsupport = 1;
2318 #endif
2319         }
2320
2321         if (opts & PF_OPT_DISABLE)
2322                 if (pfctl_disable(dev, opts))
2323                         error = 1;
2324
2325         if (showopt != NULL) {
2326                 switch (*showopt) {
2327                 case 'A':
2328                         pfctl_show_anchors(dev, opts, anchorname);
2329                         break;
2330                 case 'r':
2331                         pfctl_load_fingerprints(dev, opts);
2332                         pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
2333                             anchorname, 0);
2334                         break;
2335                 case 'l':
2336                         pfctl_load_fingerprints(dev, opts);
2337                         pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
2338                             anchorname, 0);
2339                         break;
2340                 case 'n':
2341                         pfctl_load_fingerprints(dev, opts);
2342                         pfctl_show_nat(dev, opts, anchorname);
2343                         break;
2344                 case 'q':
2345                         pfctl_show_altq(dev, ifaceopt, opts,
2346                             opts & PF_OPT_VERBOSE2);
2347                         break;
2348                 case 's':
2349                         pfctl_show_states(dev, ifaceopt, opts);
2350                         break;
2351                 case 'S':
2352                         pfctl_show_src_nodes(dev, opts);
2353                         break;
2354                 case 'i':
2355                         pfctl_show_status(dev, opts);
2356                         break;
2357                 case 'R':
2358                         error = pfctl_show_running(dev);
2359                         break;
2360                 case 't':
2361                         pfctl_show_timeouts(dev, opts);
2362                         break;
2363                 case 'm':
2364                         pfctl_show_limits(dev, opts);
2365                         break;
2366                 case 'a':
2367                         opts |= PF_OPT_SHOWALL;
2368                         pfctl_load_fingerprints(dev, opts);
2369
2370                         pfctl_show_nat(dev, opts, anchorname);
2371                         pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
2372                         pfctl_show_altq(dev, ifaceopt, opts, 0);
2373                         pfctl_show_states(dev, ifaceopt, opts);
2374                         pfctl_show_src_nodes(dev, opts);
2375                         pfctl_show_status(dev, opts);
2376                         pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
2377                         pfctl_show_timeouts(dev, opts);
2378                         pfctl_show_limits(dev, opts);
2379                         pfctl_show_tables(anchorname, opts);
2380                         pfctl_show_fingerprints(opts);
2381                         break;
2382                 case 'T':
2383                         pfctl_show_tables(anchorname, opts);
2384                         break;
2385                 case 'o':
2386                         pfctl_load_fingerprints(dev, opts);
2387                         pfctl_show_fingerprints(opts);
2388                         break;
2389                 case 'I':
2390                         pfctl_show_ifaces(ifaceopt, opts);
2391                         break;
2392                 }
2393         }
2394
2395         if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
2396                 pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
2397                     anchorname, 0);
2398
2399         if (clearopt != NULL) {
2400                 if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2401                         errx(1, "anchor names beginning with '_' cannot "
2402                             "be modified from the command line");
2403
2404                 switch (*clearopt) {
2405                 case 'r':
2406                         pfctl_clear_rules(dev, opts, anchorname);
2407                         break;
2408                 case 'n':
2409                         pfctl_clear_nat(dev, opts, anchorname);
2410                         break;
2411                 case 'q':
2412                         pfctl_clear_altq(dev, opts);
2413                         break;
2414                 case 's':
2415                         pfctl_clear_states(dev, ifaceopt, opts);
2416                         break;
2417                 case 'S':
2418                         pfctl_clear_src_nodes(dev, opts);
2419                         break;
2420                 case 'i':
2421                         pfctl_clear_stats(dev, opts);
2422                         break;
2423                 case 'a':
2424                         pfctl_clear_rules(dev, opts, anchorname);
2425                         pfctl_clear_nat(dev, opts, anchorname);
2426                         pfctl_clear_tables(anchorname, opts);
2427                         if (!*anchorname) {
2428                                 pfctl_clear_altq(dev, opts);
2429                                 pfctl_clear_states(dev, ifaceopt, opts);
2430                                 pfctl_clear_src_nodes(dev, opts);
2431                                 pfctl_clear_stats(dev, opts);
2432                                 pfctl_clear_fingerprints(dev, opts);
2433                                 pfctl_clear_interface_flags(dev, opts);
2434                         }
2435                         break;
2436                 case 'o':
2437                         pfctl_clear_fingerprints(dev, opts);
2438                         break;
2439                 case 'T':
2440                         pfctl_clear_tables(anchorname, opts);
2441                         break;
2442                 }
2443         }
2444         if (state_killers) {
2445                 if (!strcmp(state_kill[0], "label"))
2446                         pfctl_label_kill_states(dev, ifaceopt, opts);
2447                 else if (!strcmp(state_kill[0], "id"))
2448                         pfctl_id_kill_states(dev, ifaceopt, opts);
2449                 else
2450                         pfctl_net_kill_states(dev, ifaceopt, opts);
2451         }
2452
2453         if (src_node_killers)
2454                 pfctl_kill_src_nodes(dev, ifaceopt, opts);
2455
2456         if (tblcmdopt != NULL) {
2457                 error = pfctl_command_tables(argc, argv, tableopt,
2458                     tblcmdopt, rulesopt, anchorname, opts);
2459                 rulesopt = NULL;
2460         }
2461         if (optiopt != NULL) {
2462                 switch (*optiopt) {
2463                 case 'n':
2464                         optimize = 0;
2465                         break;
2466                 case 'b':
2467                         optimize |= PF_OPTIMIZE_BASIC;
2468                         break;
2469                 case 'o':
2470                 case 'p':
2471                         optimize |= PF_OPTIMIZE_PROFILE;
2472                         break;
2473                 }
2474         }
2475
2476         if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
2477             !anchorname[0] && !(opts & PF_OPT_NOACTION))
2478                 if (pfctl_get_skip_ifaces())
2479                         error = 1;
2480
2481         if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
2482             !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
2483                 if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
2484                         error = 1;
2485
2486         if (rulesopt != NULL) {
2487                 if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
2488                         errx(1, "anchor names beginning with '_' cannot "
2489                             "be modified from the command line");
2490                 if (pfctl_rules(dev, rulesopt, opts, optimize,
2491                     anchorname, NULL))
2492                         error = 1;
2493                 else if (!(opts & PF_OPT_NOACTION) &&
2494                     (loadopt & PFCTL_FLAG_TABLE))
2495                         warn_namespace_collision(NULL);
2496         }
2497
2498         if (opts & PF_OPT_ENABLE)
2499                 if (pfctl_enable(dev, opts))
2500                         error = 1;
2501
2502         if (debugopt != NULL) {
2503                 switch (*debugopt) {
2504                 case 'n':
2505                         pfctl_debug(dev, PF_DEBUG_NONE, opts);
2506                         break;
2507                 case 'u':
2508                         pfctl_debug(dev, PF_DEBUG_URGENT, opts);
2509                         break;
2510                 case 'm':
2511                         pfctl_debug(dev, PF_DEBUG_MISC, opts);
2512                         break;
2513                 case 'l':
2514                         pfctl_debug(dev, PF_DEBUG_NOISY, opts);
2515                         break;
2516                 }
2517         }
2518
2519         exit(error);
2520 }