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

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 686583c was 686583c, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/29/16 at 14:04:42

pfctl: Use static where possible.

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