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

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

pfctl: Adapt for RTEMS.

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