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