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

4.11
Last change on this file since bf8e51b was bf8e51b, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/05/16 at 14:31:43

pfctl: Match prototype.

Note: This should be upstreamed into BSD.

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