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

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since c70221c was c70221c, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/06/16 at 07:50:51

pfctl: Add const and move static variables.

Note: This should be upstreamed into BSD.

Make everything constant that can be constant and move static variables
out of their functions.

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