source: rtems-libbsd/freebsd/contrib/pf/pfctl/pfctl.c @ 084d4db

4.11
Last change on this file since 084d4db was 084d4db, checked in by Christian Mauderer <Christian.Mauderer@…>, on Jul 5, 2016 at 2:07:37 PM

pfctl: Import sources from FreeBSD.

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