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