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