summaryrefslogtreecommitdiffstats
path: root/freebsd/sbin/pfctl
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sbin/pfctl
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sbin/pfctl')
-rw-r--r--freebsd/sbin/pfctl/parse.c9315
-rw-r--r--freebsd/sbin/pfctl/parse.h337
-rw-r--r--freebsd/sbin/pfctl/parse.y6290
-rw-r--r--freebsd/sbin/pfctl/pf_print_state.c387
-rw-r--r--freebsd/sbin/pfctl/pfctl.c2445
-rw-r--r--freebsd/sbin/pfctl/pfctl.h130
-rw-r--r--freebsd/sbin/pfctl/pfctl_altq.c1536
-rw-r--r--freebsd/sbin/pfctl/pfctl_optimize.c1705
-rw-r--r--freebsd/sbin/pfctl/pfctl_osfp.c1123
-rw-r--r--freebsd/sbin/pfctl/pfctl_parser.c1780
-rw-r--r--freebsd/sbin/pfctl/pfctl_parser.h322
-rw-r--r--freebsd/sbin/pfctl/pfctl_qstats.c528
-rw-r--r--freebsd/sbin/pfctl/pfctl_radix.c597
-rw-r--r--freebsd/sbin/pfctl/pfctl_table.c650
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h25
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h262
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h36
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h4
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h22
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h9
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h11
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h7
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h5
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h5
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h4
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h6
26 files changed, 27541 insertions, 0 deletions
diff --git a/freebsd/sbin/pfctl/parse.c b/freebsd/sbin/pfctl/parse.c
new file mode 100644
index 00000000..1ae5fc95
--- /dev/null
+++ b/freebsd/sbin/pfctl/parse.c
@@ -0,0 +1,9315 @@
+/* original parser id follows */
+/* yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93" */
+/* (use YYMAJOR/YYMINOR for ifdefs dependent on parser version) */
+
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYPATCH 20160324
+
+#define YYEMPTY (-1)
+#define yyclearin (yychar = YYEMPTY)
+#define yyerrok (yyerrflag = 0)
+#define YYRECOVERING() (yyerrflag != 0)
+#define YYENOMEM (-2)
+#define YYEOF 0
+
+#ifndef yyparse
+#define yyparse pfctlyparse
+#endif /* yyparse */
+
+#ifndef yylex
+#define yylex pfctlylex
+#endif /* yylex */
+
+#ifndef yyerror
+#define yyerror pfctlyerror
+#endif /* yyerror */
+
+#ifndef yychar
+#define yychar pfctlychar
+#endif /* yychar */
+
+#ifndef yyval
+#define yyval pfctlyval
+#endif /* yyval */
+
+#ifndef yylval
+#define yylval pfctlylval
+#endif /* yylval */
+
+#ifndef yydebug
+#define yydebug pfctlydebug
+#endif /* yydebug */
+
+#ifndef yynerrs
+#define yynerrs pfctlynerrs
+#endif /* yynerrs */
+
+#ifndef yyerrflag
+#define yyerrflag pfctlyerrflag
+#endif /* yyerrflag */
+
+#ifndef yylhs
+#define yylhs pfctlylhs
+#endif /* yylhs */
+
+#ifndef yylen
+#define yylen pfctlylen
+#endif /* yylen */
+
+#ifndef yydefred
+#define yydefred pfctlydefred
+#endif /* yydefred */
+
+#ifndef yydgoto
+#define yydgoto pfctlydgoto
+#endif /* yydgoto */
+
+#ifndef yysindex
+#define yysindex pfctlysindex
+#endif /* yysindex */
+
+#ifndef yyrindex
+#define yyrindex pfctlyrindex
+#endif /* yyrindex */
+
+#ifndef yygindex
+#define yygindex pfctlygindex
+#endif /* yygindex */
+
+#ifndef yytable
+#define yytable pfctlytable
+#endif /* yytable */
+
+#ifndef yycheck
+#define yycheck pfctlycheck
+#endif /* yycheck */
+
+#ifndef yyname
+#define yyname pfctlyname
+#endif /* yyname */
+
+#ifndef yyrule
+#define yyrule pfctlyrule
+#endif /* yyrule */
+#define YYPREFIX "pfctly"
+
+#define YYPURE 0
+
+#line 30 "../../freebsd/sbin/pfctl/parse.y"
+#ifdef __rtems__
+#include <machine/rtems-bsd-user-space.h>
+#endif /* __rtems__ */
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset
+#define pf_anchor_setup _bsd_pf_anchor_setup
+#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <err.h>
+#include <limits.h>
+#include <pwd.h>
+#include <grp.h>
+#include <md5.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-parse-data.h"
+#endif /* __rtems__ */
+
+static struct pfctl *pf = NULL;
+static int debug = 0;
+static int rulestate = 0;
+static u_int16_t returnicmpdefault =
+ (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+static u_int16_t returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+static int blockpolicy = PFRULE_DROP;
+static int require_order = 1;
+static int default_statelock;
+
+static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
+static struct file {
+ TAILQ_ENTRY(file) entry;
+ FILE *stream;
+ char *name;
+ int lineno;
+ int errors;
+} *file;
+struct file *pushfile(const char *, int);
+int popfile(void);
+int check_file_secrecy(int, const char *);
+int yyparse(void);
+int yylex(void);
+int yyerror(const char *, ...);
+int kw_cmp(const void *, const void *);
+int lookup(char *);
+int lgetc(int);
+int lungetc(int);
+int findeol(void);
+
+static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
+struct sym {
+ TAILQ_ENTRY(sym) entry;
+ int used;
+ int persist;
+ char *nam;
+ char *val;
+};
+int symset(const char *, const char *, int);
+char *symget(const char *);
+
+int atoul(char *, u_long *);
+
+enum {
+ PFCTL_STATE_NONE,
+ PFCTL_STATE_OPTION,
+ PFCTL_STATE_SCRUB,
+ PFCTL_STATE_QUEUE,
+ PFCTL_STATE_NAT,
+ PFCTL_STATE_FILTER
+};
+
+struct node_proto {
+ u_int8_t proto;
+ struct node_proto *next;
+ struct node_proto *tail;
+};
+
+struct node_port {
+ u_int16_t port[2];
+ u_int8_t op;
+ struct node_port *next;
+ struct node_port *tail;
+};
+
+struct node_uid {
+ uid_t uid[2];
+ u_int8_t op;
+ struct node_uid *next;
+ struct node_uid *tail;
+};
+
+struct node_gid {
+ gid_t gid[2];
+ u_int8_t op;
+ struct node_gid *next;
+ struct node_gid *tail;
+};
+
+struct node_icmp {
+ u_int8_t code;
+ u_int8_t type;
+ u_int8_t proto;
+ struct node_icmp *next;
+ struct node_icmp *tail;
+};
+
+enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
+ PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
+ PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
+ PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
+ PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
+
+enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
+
+struct node_state_opt {
+ int type;
+ union {
+ u_int32_t max_states;
+ u_int32_t max_src_states;
+ u_int32_t max_src_conn;
+ struct {
+ u_int32_t limit;
+ u_int32_t seconds;
+ } max_src_conn_rate;
+ struct {
+ u_int8_t flush;
+ char tblname[PF_TABLE_NAME_SIZE];
+ } overload;
+ u_int32_t max_src_nodes;
+ u_int8_t src_track;
+ u_int32_t statelock;
+ struct {
+ int number;
+ u_int32_t seconds;
+ } timeout;
+ } data;
+ struct node_state_opt *next;
+ struct node_state_opt *tail;
+};
+
+struct peer {
+ struct node_host *host;
+ struct node_port *port;
+};
+
+static struct node_queue {
+ char queue[PF_QNAME_SIZE];
+ char parent[PF_QNAME_SIZE];
+ char ifname[IFNAMSIZ];
+ int scheduler;
+ struct node_queue *next;
+ struct node_queue *tail;
+} *queues = NULL;
+
+struct node_qassign {
+ char *qname;
+ char *pqname;
+};
+
+static struct filter_opts {
+ int marker;
+#define FOM_FLAGS 0x01
+#define FOM_ICMP 0x02
+#define FOM_TOS 0x04
+#define FOM_KEEP 0x08
+#define FOM_SRCTRACK 0x10
+#define FOM_SETPRIO 0x0400
+#define FOM_PRIO 0x2000
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } flags;
+ struct node_icmp *icmpspec;
+ u_int32_t tos;
+ u_int32_t prob;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep;
+ int fragment;
+ int allowopts;
+ char *label;
+ struct node_qassign queues;
+ char *tag;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+ u_int8_t prio;
+ u_int8_t set_prio[2];
+ struct {
+ struct node_host *addr;
+ u_int16_t port;
+ } divert;
+} filter_opts;
+
+static struct antispoof_opts {
+ char *label;
+ u_int rtableid;
+} antispoof_opts;
+
+static struct scrub_opts {
+ int marker;
+#define SOM_MINTTL 0x01
+#define SOM_MAXMSS 0x02
+#define SOM_FRAGCACHE 0x04
+#define SOM_SETTOS 0x08
+ int nodf;
+ int minttl;
+ int maxmss;
+ int settos;
+ int fragcache;
+ int randomid;
+ int reassemble_tcp;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+} scrub_opts;
+
+static struct queue_opts {
+ int marker;
+#define QOM_BWSPEC 0x01
+#define QOM_SCHEDULER 0x02
+#define QOM_PRIORITY 0x04
+#define QOM_TBRSIZE 0x08
+#define QOM_QLIMIT 0x10
+ struct node_queue_bw queue_bwspec;
+ struct node_queue_opt scheduler;
+ int priority;
+ int tbrsize;
+ int qlimit;
+} queue_opts;
+
+static struct table_opts {
+ int flags;
+ int init_addr;
+ struct node_tinithead init_nodes;
+} table_opts;
+
+static struct pool_opts {
+ int marker;
+#define POM_TYPE 0x01
+#define POM_STICKYADDRESS 0x02
+ u_int8_t opts;
+ int type;
+ int staticport;
+ struct pf_poolhashkey *key;
+
+} pool_opts;
+
+static struct codel_opts codel_opts;
+static struct node_hfsc_opts hfsc_opts;
+static struct node_fairq_opts fairq_opts;
+static struct node_state_opt *keep_state_defaults = NULL;
+
+int disallow_table(struct node_host *, const char *);
+int disallow_urpf_failed(struct node_host *, const char *);
+int disallow_alias(struct node_host *, const char *);
+int rule_consistent(struct pf_rule *, int);
+int filter_consistent(struct pf_rule *, int);
+int nat_consistent(struct pf_rule *);
+int rdr_consistent(struct pf_rule *);
+int process_tabledef(char *, struct table_opts *);
+void expand_label_str(char *, size_t, const char *, const char *);
+void expand_label_if(const char *, char *, size_t, const char *);
+void expand_label_addr(const char *, char *, size_t, u_int8_t,
+ struct node_host *);
+void expand_label_port(const char *, char *, size_t,
+ struct node_port *);
+void expand_label_proto(const char *, char *, size_t, u_int8_t);
+void expand_label_nr(const char *, char *, size_t);
+void expand_label(char *, size_t, const char *, u_int8_t,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, u_int8_t);
+void expand_rule(struct pf_rule *, struct node_if *,
+ struct node_host *, struct node_proto *, struct node_os *,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, struct node_uid *, struct node_gid *,
+ struct node_icmp *, const char *);
+int expand_altq(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw bwspec,
+ struct node_queue_opt *);
+int expand_queue(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw,
+ struct node_queue_opt *);
+int expand_skip_interface(struct node_if *);
+
+int check_rulestate(int);
+int getservice(char *);
+int rule_label(struct pf_rule *, char *);
+int rt_tableid_max(void);
+
+void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
+void decide_address_family(struct node_host *, sa_family_t *);
+void remove_invalid_hosts(struct node_host **, sa_family_t *);
+int invalid_redirect(struct node_host *, sa_family_t);
+u_int16_t parseicmpspec(char *, sa_family_t);
+
+static TAILQ_HEAD(loadanchorshead, loadanchors)
+ loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
+
+struct loadanchors {
+ TAILQ_ENTRY(loadanchors) entries;
+ char *anchorname;
+ char *filename;
+};
+
+typedef struct {
+ union {
+ int64_t number;
+ double probability;
+ int i;
+ char *string;
+ u_int rtableid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } b;
+ struct range {
+ int a;
+ int b;
+ int t;
+ } range;
+ struct node_if *interface;
+ struct node_proto *proto;
+ struct node_icmp *icmp;
+ struct node_host *host;
+ struct node_os *os;
+ struct node_port *port;
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct node_state_opt *state_opt;
+ struct peer peer;
+ struct {
+ struct peer src, dst;
+ struct node_os *src_os;
+ } fromto;
+ struct {
+ struct node_host *host;
+ u_int8_t rt;
+ u_int8_t pool_opts;
+ sa_family_t af;
+ struct pf_poolhashkey *key;
+ } route;
+ struct redirection {
+ struct node_host *host;
+ struct range rport;
+ } *redirection;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep_state;
+ struct {
+ u_int8_t log;
+ u_int8_t logif;
+ u_int8_t quick;
+ } logquick;
+ struct {
+ int neg;
+ char *name;
+ } tagged;
+ struct pf_poolhashkey *hashkey;
+ struct node_queue *queue;
+ struct node_queue_opt queue_options;
+ struct node_queue_bw queue_bwspec;
+ struct node_qassign qassign;
+ struct filter_opts filter_opts;
+ struct antispoof_opts antispoof_opts;
+ struct queue_opts queue_opts;
+ struct scrub_opts scrub_opts;
+ struct table_opts table_opts;
+ struct pool_opts pool_opts;
+ struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ struct codel_opts codel_opts;
+ } v;
+ int lineno;
+} YYSTYPE;
+
+#define PPORT_RANGE 1
+#define PPORT_STAR 2
+int parseport(char *, struct range *r, int);
+
+#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
+ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
+ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
+
+#line 534 "pfctly.tab.c"
+
+/* compatibility with bison */
+#ifdef YYPARSE_PARAM
+/* compatibility with FreeBSD */
+# ifdef YYPARSE_PARAM_TYPE
+# define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM)
+# else
+# define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM)
+# endif
+#else
+# define YYPARSE_DECL() yyparse(void)
+#endif
+
+/* Parameters sent to lex. */
+#ifdef YYLEX_PARAM
+# define YYLEX_DECL() yylex(void *YYLEX_PARAM)
+# define YYLEX yylex(YYLEX_PARAM)
+#else
+# define YYLEX_DECL() yylex(void)
+# define YYLEX yylex()
+#endif
+
+/* Parameters sent to yyerror. */
+#ifndef YYERROR_DECL
+#define YYERROR_DECL() yyerror(const char *s)
+#endif
+#ifndef YYERROR_CALL
+#define YYERROR_CALL(msg) yyerror(msg)
+#endif
+
+extern int YYPARSE_DECL();
+
+#define PASS 257
+#define BLOCK 258
+#define SCRUB 259
+#define RETURN 260
+#define IN 261
+#define OS 262
+#define OUT 263
+#define LOG 264
+#define QUICK 265
+#define ON 266
+#define FROM 267
+#define TO 268
+#define FLAGS 269
+#define RETURNRST 270
+#define RETURNICMP 271
+#define RETURNICMP6 272
+#define PROTO 273
+#define INET 274
+#define INET6 275
+#define ALL 276
+#define ANY 277
+#define ICMPTYPE 278
+#define ICMP6TYPE 279
+#define CODE 280
+#define KEEP 281
+#define MODULATE 282
+#define STATE 283
+#define PORT 284
+#define RDR 285
+#define NAT 286
+#define BINAT 287
+#define ARROW 288
+#define NODF 289
+#define MINTTL 290
+#define ERROR 291
+#define ALLOWOPTS 292
+#define FASTROUTE 293
+#define FILENAME 294
+#define ROUTETO 295
+#define DUPTO 296
+#define REPLYTO 297
+#define NO 298
+#define LABEL 299
+#define NOROUTE 300
+#define URPFFAILED 301
+#define FRAGMENT 302
+#define USER 303
+#define GROUP 304
+#define MAXMSS 305
+#define MAXIMUM 306
+#define TTL 307
+#define TOS 308
+#define DROP 309
+#define TABLE 310
+#define REASSEMBLE 311
+#define FRAGDROP 312
+#define FRAGCROP 313
+#define ANCHOR 314
+#define NATANCHOR 315
+#define RDRANCHOR 316
+#define BINATANCHOR 317
+#define SET 318
+#define OPTIMIZATION 319
+#define TIMEOUT 320
+#define LIMIT 321
+#define LOGINTERFACE 322
+#define BLOCKPOLICY 323
+#define RANDOMID 324
+#define REQUIREORDER 325
+#define SYNPROXY 326
+#define FINGERPRINTS 327
+#define NOSYNC 328
+#define DEBUG 329
+#define SKIP 330
+#define HOSTID 331
+#define ANTISPOOF 332
+#define FOR 333
+#define INCLUDE 334
+#define BITMASK 335
+#define RANDOM 336
+#define SOURCEHASH 337
+#define ROUNDROBIN 338
+#define STATICPORT 339
+#define PROBABILITY 340
+#define ALTQ 341
+#define CBQ 342
+#define CODEL 343
+#define PRIQ 344
+#define HFSC 345
+#define FAIRQ 346
+#define BANDWIDTH 347
+#define TBRSIZE 348
+#define LINKSHARE 349
+#define REALTIME 350
+#define UPPERLIMIT 351
+#define QUEUE 352
+#define PRIORITY 353
+#define QLIMIT 354
+#define HOGS 355
+#define BUCKETS 356
+#define RTABLE 357
+#define TARGET 358
+#define INTERVAL 359
+#define LOAD 360
+#define RULESET_OPTIMIZATION 361
+#define PRIO 362
+#define STICKYADDRESS 363
+#define MAXSRCSTATES 364
+#define MAXSRCNODES 365
+#define SOURCETRACK 366
+#define GLOBAL 367
+#define RULE 368
+#define MAXSRCCONN 369
+#define MAXSRCCONNRATE 370
+#define OVERLOAD 371
+#define FLUSH 372
+#define SLOPPY 373
+#define TAGGED 374
+#define TAG 375
+#define IFBOUND 376
+#define FLOATING 377
+#define STATEPOLICY 378
+#define STATEDEFAULTS 379
+#define ROUTE 380
+#define SETTOS 381
+#define DIVERTTO 382
+#define DIVERTREPLY 383
+#define STRING 384
+#define NUMBER 385
+#define PORTBINARY 386
+#define YYERRCODE 256
+typedef int YYINT;
+static const YYINT pfctlylhs[] = { -1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 137, 150, 150,
+ 150, 150, 150, 150, 18, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 77, 77, 80, 80, 81, 81, 82, 82, 147,
+ 79, 79, 156, 156, 156, 156, 158, 157, 157, 143,
+ 143, 143, 143, 144, 26, 139, 159, 126, 126, 128,
+ 128, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 17, 17, 17, 148, 92, 92, 93, 93, 94, 94,
+ 161, 120, 120, 122, 122, 121, 121, 11, 11, 149,
+ 162, 129, 129, 131, 131, 130, 130, 130, 130, 145,
+ 146, 163, 123, 123, 125, 125, 124, 124, 124, 124,
+ 124, 113, 113, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 100, 100, 101, 102, 102, 103, 164,
+ 106, 104, 104, 105, 105, 105, 105, 105, 105, 105,
+ 165, 109, 107, 107, 108, 108, 108, 108, 108, 166,
+ 112, 110, 110, 111, 111, 111, 96, 96, 96, 97,
+ 97, 98, 142, 167, 114, 114, 116, 116, 115, 115,
+ 115, 115, 115, 115, 115, 115, 115, 115, 115, 115,
+ 115, 115, 115, 115, 115, 115, 115, 117, 117, 119,
+ 119, 118, 30, 30, 13, 13, 23, 23, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 44, 44,
+ 45, 45, 15, 15, 15, 88, 88, 87, 87, 87,
+ 87, 87, 89, 89, 90, 90, 91, 91, 91, 91,
+ 1, 1, 1, 2, 2, 3, 4, 16, 16, 16,
+ 35, 35, 35, 36, 36, 37, 38, 38, 46, 46,
+ 61, 61, 61, 62, 63, 63, 48, 48, 49, 49,
+ 47, 47, 47, 152, 152, 50, 50, 50, 51, 51,
+ 55, 55, 52, 52, 52, 53, 53, 53, 53, 53,
+ 53, 53, 5, 5, 54, 64, 64, 65, 65, 66,
+ 66, 66, 31, 33, 67, 67, 68, 68, 69, 69,
+ 69, 8, 8, 70, 70, 71, 71, 72, 72, 72,
+ 9, 9, 28, 27, 27, 27, 39, 39, 39, 39,
+ 40, 40, 42, 42, 41, 41, 41, 43, 43, 43,
+ 6, 6, 7, 7, 10, 10, 19, 19, 19, 22,
+ 22, 83, 83, 83, 83, 20, 20, 20, 84, 84,
+ 85, 85, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 76, 95, 95, 95, 14, 14, 32,
+ 57, 57, 56, 56, 75, 75, 75, 34, 34, 168,
+ 132, 132, 134, 134, 133, 133, 133, 133, 133, 133,
+ 74, 74, 74, 25, 25, 25, 25, 24, 24, 140,
+ 141, 78, 78, 135, 135, 136, 136, 58, 58, 59,
+ 59, 60, 60, 73, 73, 73, 73, 73, 151, 151,
+ 153, 153, 154, 155, 155, 160, 160, 12, 12, 21,
+ 21, 21, 21, 21, 21,
+};
+static const YYINT pfctlylen[] = { 2,
+ 0, 3, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 4, 3, 2, 2, 3,
+ 3, 3, 3, 3, 1, 3, 3, 3, 6, 3,
+ 6, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 2, 1, 2, 1, 1, 1, 3,
+ 1, 0, 0, 2, 3, 3, 0, 5, 0, 10,
+ 7, 7, 7, 5, 2, 8, 0, 2, 0, 2,
+ 1, 1, 2, 2, 2, 1, 2, 1, 2, 3,
+ 2, 2, 2, 5, 2, 5, 2, 4, 1, 3,
+ 0, 2, 0, 2, 1, 1, 2, 1, 0, 5,
+ 0, 2, 0, 2, 1, 1, 3, 4, 2, 5,
+ 5, 0, 2, 0, 2, 1, 2, 2, 2, 1,
+ 2, 1, 1, 1, 4, 1, 4, 1, 4, 1,
+ 4, 1, 4, 1, 3, 1, 1, 3, 1, 0,
+ 2, 1, 3, 2, 8, 2, 8, 2, 8, 1,
+ 0, 2, 1, 3, 2, 6, 2, 2, 1, 0,
+ 2, 1, 3, 2, 2, 1, 0, 1, 4, 2,
+ 4, 1, 9, 0, 2, 0, 2, 1, 2, 2,
+ 1, 1, 2, 2, 1, 1, 1, 1, 1, 2,
+ 3, 2, 2, 2, 4, 1, 1, 4, 2, 3,
+ 1, 1, 2, 6, 1, 1, 1, 2, 0, 1,
+ 1, 5, 1, 1, 4, 4, 6, 1, 1, 1,
+ 1, 1, 0, 1, 1, 0, 1, 0, 1, 1,
+ 2, 2, 1, 4, 1, 3, 1, 1, 1, 2,
+ 0, 2, 5, 2, 4, 2, 1, 0, 1, 1,
+ 0, 2, 5, 2, 4, 1, 1, 1, 1, 3,
+ 0, 2, 5, 1, 2, 4, 0, 2, 0, 2,
+ 1, 3, 2, 2, 0, 1, 1, 4, 2, 0,
+ 2, 4, 2, 2, 2, 1, 3, 3, 3, 1,
+ 3, 3, 1, 1, 3, 1, 4, 2, 4, 1,
+ 2, 3, 1, 1, 1, 4, 2, 4, 1, 2,
+ 3, 1, 1, 1, 4, 2, 4, 1, 2, 3,
+ 1, 1, 1, 4, 3, 2, 2, 5, 2, 5,
+ 2, 4, 2, 4, 1, 3, 3, 1, 3, 3,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 1,
+ 1, 2, 3, 3, 3, 0, 1, 2, 3, 0,
+ 1, 3, 2, 1, 2, 2, 4, 5, 2, 1,
+ 1, 1, 2, 2, 2, 4, 6, 0, 1, 1,
+ 1, 4, 2, 4, 0, 2, 4, 0, 1, 0,
+ 2, 0, 2, 1, 1, 1, 2, 1, 1, 1,
+ 0, 2, 4, 0, 1, 2, 1, 3, 3, 10,
+ 13, 0, 2, 0, 3, 0, 2, 1, 4, 2,
+ 4, 1, 4, 0, 1, 3, 3, 3, 2, 2,
+ 4, 2, 2, 4, 2, 1, 0, 1, 1, 1,
+ 2, 2, 1, 2, 1,
+};
+static const YYINT pfctlydefred[] = { 0,
+ 0, 0, 0, 0, 207, 0, 379, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 19, 0,
+ 0, 0, 0, 0, 0, 17, 218, 0, 0, 0,
+ 210, 208, 0, 51, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 18, 0, 0, 0,
+ 0, 0, 65, 0, 0, 0, 224, 225, 0, 0,
+ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 24, 16, 22, 21, 23, 20,
+ 0, 0, 0, 0, 0, 44, 0, 0, 0, 26,
+ 0, 0, 0, 28, 0, 0, 30, 43, 42, 32,
+ 35, 34, 438, 439, 36, 37, 39, 40, 294, 293,
+ 33, 27, 25, 350, 351, 38, 0, 364, 0, 0,
+ 0, 0, 0, 0, 372, 0, 370, 371, 0, 361,
+ 0, 232, 0, 0, 231, 0, 98, 242, 0, 0,
+ 0, 0, 0, 49, 48, 50, 0, 0, 409, 407,
+ 408, 0, 0, 249, 250, 0, 0, 0, 219, 220,
+ 0, 221, 222, 0, 0, 227, 0, 0, 0, 0,
+ 430, 429, 0, 0, 433, 0, 363, 365, 369, 348,
+ 349, 366, 0, 0, 373, 436, 0, 0, 237, 238,
+ 239, 0, 235, 247, 0, 0, 89, 85, 0, 0,
+ 246, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 120, 116, 0, 0, 0, 46, 406, 0, 0,
+ 0, 0, 0, 0, 215, 0, 216, 100, 0, 0,
+ 0, 0, 0, 274, 0, 0, 0, 0, 0, 0,
+ 362, 240, 234, 0, 0, 0, 84, 0, 0, 0,
+ 172, 0, 110, 168, 0, 160, 0, 140, 151, 122,
+ 123, 117, 121, 118, 119, 115, 111, 64, 0, 425,
+ 0, 0, 0, 0, 257, 258, 0, 252, 256, 0,
+ 259, 0, 0, 0, 212, 0, 0, 106, 0, 105,
+ 0, 0, 0, 0, 0, 432, 29, 0, 435, 31,
+ 0, 367, 0, 236, 0, 0, 90, 0, 0, 96,
+ 95, 0, 243, 0, 244, 0, 136, 0, 134, 0,
+ 0, 139, 0, 137, 0, 0, 0, 0, 0, 418,
+ 0, 0, 422, 0, 0, 0, 0, 0, 276, 0,
+ 0, 0, 268, 0, 277, 0, 0, 0, 0, 0,
+ 217, 109, 0, 104, 0, 0, 61, 62, 63, 0,
+ 0, 0, 368, 86, 0, 87, 374, 97, 94, 0,
+ 0, 0, 125, 0, 133, 0, 0, 166, 0, 162,
+ 127, 0, 129, 0, 0, 0, 150, 0, 142, 131,
+ 0, 0, 0, 159, 0, 153, 0, 0, 0, 426,
+ 0, 428, 427, 0, 0, 0, 0, 440, 0, 0,
+ 0, 0, 0, 273, 296, 304, 0, 284, 285, 0,
+ 0, 0, 0, 283, 0, 0, 413, 0, 0, 264,
+ 0, 262, 0, 260, 0, 107, 0, 0, 0, 417,
+ 431, 434, 358, 0, 245, 169, 0, 170, 135, 165,
+ 164, 0, 138, 0, 144, 0, 146, 0, 148, 0,
+ 0, 155, 157, 158, 0, 0, 0, 0, 0, 395,
+ 396, 0, 398, 399, 400, 394, 0, 0, 253, 0,
+ 254, 0, 441, 442, 444, 301, 0, 0, 0, 0,
+ 0, 0, 0, 0, 272, 0, 0, 0, 270, 66,
+ 0, 281, 108, 0, 0, 0, 88, 0, 163, 0,
+ 0, 0, 143, 0, 154, 0, 0, 420, 423, 0,
+ 419, 397, 389, 393, 173, 0, 0, 0, 302, 278,
+ 287, 288, 289, 295, 292, 291, 415, 0, 0, 0,
+ 0, 72, 0, 0, 0, 0, 78, 0, 0, 0,
+ 76, 71, 0, 0, 57, 60, 0, 0, 0, 0,
+ 0, 187, 0, 186, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 196, 0, 181, 182, 188,
+ 185, 189, 178, 0, 197, 171, 0, 0, 0, 0,
+ 279, 0, 0, 255, 297, 0, 298, 0, 381, 0,
+ 410, 265, 263, 0, 73, 81, 83, 82, 74, 77,
+ 79, 345, 346, 75, 0, 70, 282, 0, 326, 323,
+ 0, 0, 341, 342, 0, 0, 327, 343, 344, 0,
+ 0, 329, 0, 0, 352, 312, 313, 0, 0, 0,
+ 179, 305, 321, 322, 0, 0, 0, 180, 314, 184,
+ 0, 0, 202, 199, 0, 205, 206, 192, 375, 0,
+ 193, 183, 190, 0, 194, 303, 0, 177, 0, 0,
+ 0, 0, 0, 421, 0, 0, 0, 0, 80, 53,
+ 325, 0, 0, 0, 0, 0, 0, 353, 354, 0,
+ 0, 310, 0, 0, 319, 203, 0, 201, 0, 355,
+ 0, 0, 191, 0, 0, 0, 156, 0, 299, 0,
+ 0, 387, 380, 266, 0, 324, 0, 0, 336, 337,
+ 0, 0, 339, 340, 0, 0, 0, 311, 0, 0,
+ 320, 0, 198, 0, 376, 0, 195, 0, 0, 0,
+ 0, 411, 383, 382, 0, 54, 58, 0, 0, 328,
+ 0, 331, 330, 0, 333, 359, 306, 0, 307, 315,
+ 0, 316, 0, 200, 0, 145, 147, 149, 0, 0,
+ 55, 56, 0, 0, 0, 0, 0, 377, 0, 384,
+ 332, 334, 308, 317, 204, 403,
+};
+static const YYINT pfctlydgoto[] = { 2,
+ 79, 279, 168, 227, 141, 656, 661, 669, 676, 644,
+ 372, 135, 688, 21, 89, 186, 581, 142, 157, 393,
+ 442, 158, 22, 23, 179, 24, 608, 652, 52, 683,
+ 695, 742, 443, 552, 252, 435, 308, 309, 609, 747,
+ 657, 751, 662, 191, 194, 312, 373, 313, 464, 374,
+ 547, 375, 454, 455, 468, 741, 630, 363, 498, 364,
+ 379, 462, 571, 444, 557, 445, 671, 756, 672, 678,
+ 759, 679, 304, 772, 569, 340, 130, 377, 55, 57,
+ 176, 446, 611, 718, 159, 160, 75, 197, 76, 222,
+ 223, 164, 335, 228, 612, 283, 401, 284, 242, 348,
+ 349, 353, 354, 418, 419, 355, 425, 426, 357, 409,
+ 410, 350, 292, 535, 613, 614, 615, 684, 729, 277,
+ 341, 342, 170, 243, 244, 530, 582, 583, 258, 320,
+ 321, 430, 506, 507, 459, 387, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 3,
+ 124, 204, 266, 127, 268, 745, 586, 648, 531, 217,
+ 278, 259, 171, 356, 358, 351, 536, 431,
+};
+static const YYINT pfctlysindex[] = { -28,
+ 0, 118, 1618, 94, 0, 604, 0, 57, -163, -158,
+ -158, -158, 1728, 392, -129, 213, -35, -49, 463, 0,
+ 680, -20, 213, -20, 519, 525, 538, 552, 569, 622,
+ 651, 664, 670, 678, 684, 691, 711, 714, 0, 716,
+ 424, 720, 726, 731, 749, 0, 0, 545, 650, 657,
+ 0, 0, 230, 0, -20, -158, 213, 213, 213, 386,
+ -93, -72, -226, -58, -230, 390, 403, 213, -107, -158,
+ 371, 1487, 754, 540, 486, 556, 0, 27, 0, 213,
+ -158, 428, 0, 326, 326, 326, 0, 0, 392, 579,
+ 392, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 516, 475, 532, 768, 601, 0, 579, 579, 579, 0,
+ 492, 496, 883, 0, 518, 883, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 529, 0, 555, 559,
+ 489, 567, 577, 841, 0, 587, 0, 0, 931, 0,
+ 347, 0, 19, 579, 0, 883, 0, 0, 611, 655,
+ 1926, 0, 744, 0, 0, 0, 428, 540, 0, 0,
+ 0, 213, 213, 0, 0, 747, 213, 632, 0, 0,
+ 599, 0, 0, 997, 0, 0, 213, 747, 747, 747,
+ 0, 0, 883, -156, 0, 669, 0, 0, 0, 0,
+ 0, 0, 994, 689, 0, 0, 1487, -158, 0, 0,
+ 0, 603, 0, 0, 883, 611, 0, 0, 0, 1006,
+ 0, -57, 1022, 1024, 1028, 1035, 1050, 535, 707, 713,
+ 739, 0, 0, 1926, -57, -158, 0, 0, 579, 382,
+ -47, -187, 579, 1067, 0, 532, 0, 0, -81, 579,
+ -187, -187, -187, 0, 883, 13, 883, 49, 770, 1034,
+ 0, 0, 0, 347, 34, 1082, 0, -101, 67, 883,
+ 0, 883, 0, 0, 745, 0, 750, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 747, 0,
+ 39, 39, 39, 579, 0, 0, 883, 0, 0, 192,
+ 0, 758, 894, 747, 0, 1119, 777, 0, 883, 0,
+ -81, 747, 810, 810, 810, 0, 0, -156, 0, 0,
+ 669, 0, 801, 0, 82, 883, 0, 790, 791, 0,
+ 0, -101, 0, 1006, 0, 797, 0, 679, 0, 1134,
+ 349, 0, 724, 0, 1141, 483, 1142, -274, 922, 0,
+ 883, 807, 0, 0, 0, 0, 747, 541, 0, 83,
+ 883, 246, 0, 908, 0, 813, 1006, -45, 926, -187,
+ 0, 0, 28, 0, -187, 815, 0, 0, 0, 883,
+ 883, 834, 0, 0, 34, 0, 0, 0, 0, 883,
+ 86, 883, 0, 745, 0, -107, -107, 0, 931, 0,
+ 0, 750, 0, 24, 187, 214, 0, 931, 0, 0,
+ 224, 535, -107, 0, 931, 0, 190, 56, 190, 0,
+ 765, 0, 0, -187, 97, 883, 883, 0, 1143, 1144,
+ 1146, 428, 822, 0, 0, 0, 32, 0, 0, 575,
+ 1167, 838, 839, 0, 1171, 83, 0, 852, 810, 0,
+ 883, 0, 192, 0, 0, 0, 883, 108, 0, 0,
+ 0, 0, 0, 883, 0, 0, 797, 0, 0, 0,
+ 0, 349, 0, 535, 0, 535, 0, 535, 0, 483,
+ 535, 0, 0, 0, -274, 959, 883, 136, 1188, 0,
+ 0, -158, 0, 0, 0, 0, 765, 0, 0, 541,
+ 0, 61, 0, 0, 0, 0, 428, 137, 846, 847,
+ 848, 1193, 1176, 855, 0, -158, 953, 858, 0, 0,
+ 1405, 0, 0, 32, 1122, 4400, 0, 883, 0, 931,
+ 931, 931, 0, -107, 0, 32, 758, 0, 0, 56,
+ 0, 0, 0, 0, 0, 883, 155, 883, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 417, 0, 883,
+ 200, 0, 863, 595, 866, 868, 0, 869, 550, 879,
+ 0, 0, 1405, 883, 0, 0, 235, 361, 376, 972,
+ 975, 0, 976, 0, 135, 283, 550, 37, 978, 562,
+ 69, 877, 880, -158, 570, 0, 890, 0, 0, 0,
+ 0, 0, 0, 4400, 0, 0, 888, 892, 893, 535,
+ 0, 1006, 883, 0, 0, 61, 0, 883, 0, 984,
+ 0, 0, 0, 858, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -158, 0, 0, 1265, 0, 0,
+ 896, 1234, 0, 0, 883, 1007, 0, 0, 0, 883,
+ 1008, 0, 1249, 1249, 0, 0, 0, 883, 904, 630,
+ 0, 0, 0, 0, 883, 909, 642, 0, 0, 0,
+ -16, 934, 0, 0, 1249, 0, 0, 0, 0, 913,
+ 0, 0, 0, 1014, 0, 0, -158, 0, 931, 931,
+ 931, 1262, 810, 0, 883, 190, 428, 883, 0, 0,
+ 0, 896, 644, 659, 661, 665, 1487, 0, 0, 116,
+ 630, 0, 158, 642, 0, 0, 919, 0, 728, 0,
+ 734, 428, 0, 535, 535, 535, 0, 1017, 0, 883,
+ 363, 0, 0, 0, 654, 0, 385, 883, 0, 0,
+ 429, 883, 0, 0, 773, 452, 883, 0, 472, 883,
+ 0, 931, 0, 934, 0, 927, 0, 1269, 1271, 1272,
+ 190, 0, 0, 0, 190, 0, 0, 1296, 1304, 0,
+ 644, 0, 0, 661, 0, 0, 0, 116, 0, 0,
+ 158, 0, 930, 0, 1276, 0, 0, 0, 1037, 883,
+ 0, 0, 883, 883, 883, 883, 1277, 0, 428, 0,
+ 0, 0, 0, 0, 0, 0,
+};
+static const YYINT pfctlyrindex[] = { 36,
+ 0, 723, 738, 0, 0, 1644, 0, 0, 2743, 0,
+ 0, 0, 0, 986, 0, 1156, 0, 0, 0, 0,
+ 0, 2290, 2701, 4182, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1712, 1836, 1959,
+ 0, 0, 0, 0, 3033, 1283, 1115, 1115, 1115, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1312, 0, 0,
+ 0, 0, 1155, 1394, 0, 1521, 0, 939, 1813, 1027,
+ 0, 0, 0, 4235, 4235, 878, 0, 0, 2811, 4313,
+ 4202, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3144, 0, 629, 629, 629, 0,
+ 0, 0, -99, 0, 0, 942, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 289, 0, 0, 0, 0, 0, 0, 0, 793, 0,
+ 0, 0, 0, 15, 0, -23, 0, 0, 0, 0,
+ 0, 1055, 0, 0, 0, 0, 1318, 4267, 0, 0,
+ 0, 533, 2922, 0, 0, 4320, 3576, 0, 0, 0,
+ 687, 0, 0, 0, 2, 0, 3255, 219, 219, 219,
+ 0, 0, 1481, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 459, 0, 0, 78, 0, 0, 0, 30, 939,
+ 0, 1321, 258, 438, 795, 992, 1012, 0, 0, 0,
+ 0, 0, 0, 6, 1321, 0, 0, 0, -204, 3323,
+ 0, 505, 2139, 0, 0, 0, 0, 0, 0, 3459,
+ 73, 73, 73, 0, 574, -96, -27, 948, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -13, -18,
+ 0, 942, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1066, 0,
+ 0, 0, 0, 3528, 0, 0, 697, 0, 0, 510,
+ 0, 154, 2167, 8, 0, 0, 0, 0, 1352, 0,
+ 684, 3645, 1331, 1331, 1331, 0, 0, 0, 0, 0,
+ 0, 0, 572, 0, 80, -17, 0, 0, 0, 0,
+ 0, 519, 0, 939, 0, 0, 0, 948, 0, 0,
+ 0, 0, 948, 0, 0, 0, 0, 0, 0, 0,
+ 78, 0, 0, 2499, 2499, 2499, 3697, 0, 0, 0,
+ 59, 0, 0, 2057, 0, 0, 748, 0, 2388, 2543,
+ 0, 0, 510, 0, 3795, 0, 0, 0, 0, 574,
+ -27, 690, 0, 0, 0, 0, 0, 0, 0, -18,
+ 948, -27, 0, 0, 0, 0, 0, 0, 287, 0,
+ 0, 0, 0, 0, 0, 0, 0, 285, 0, 0,
+ 0, 0, 0, 0, 514, 0, 0, 0, 0, 0,
+ 0, 0, 0, 3846, 687, 142, 175, 0, 0, 710,
+ 733, 0, 695, 0, 0, 0, 510, 0, 0, 414,
+ 0, 0, 0, 0, 547, 0, 0, 0, 195, 0,
+ 942, 0, 510, 0, 882, 0, 1184, 704, 3935, 0,
+ 0, 0, 0, -17, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 23, -17, 80, 0, 0,
+ 0, 2610, 0, 0, 0, 0, 3391, 4079, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 704, 0, 0,
+ 0, 0, 0, 0, 0, 0, 75, 0, 0, 0,
+ 973, 0, 0, 510, 1338, 973, 0, -27, 0, 964,
+ 964, 964, 0, 0, 0, 510, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 142, 240, 10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 229, -27,
+ 948, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 11, 1184, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0,
+ 0, 43, -17, 0, 0, 0, 0, 209, 0, 653,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 697, 917, 0, 0, 0, 697,
+ 968, 0, 3981, 3981, 0, 0, 0, 175, 123, 0,
+ 0, 0, 0, 0, 175, 828, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3981, 0, 0, 0, 0, 0,
+ 0, 0, 0, 4033, 0, 0, 0, 0, 687, 687,
+ 687, 0, 1, 0, 10, 0, 0, -27, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 999, 0,
+ 948, 0, 0, 0, 0, 0, 0, 1353, 0, 87,
+ 264, 0, 0, 0, 0, 0, 687, 142, 0, 0,
+ 687, 142, 0, 0, 1707, 240, 10, 0, 240, 10,
+ 0, 964, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1357, 87,
+ 0, 0, 142, 142, 10, 10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+};
+static const YYINT pfctlygindex[] = { 0,
+ 1557, 0, -208, -102, -320, 0, 0, -476, -619, 771,
+ -70, 0, 0, 1359, 490, 1165, 0, 0, 0, 0,
+ 328, 1307, 0, 0, 874, 0, 0, -612, 0, 0,
+ 647, 578, -308, 0, 1650, 0, -331, 0, 0, 0,
+ -668, 0, -525, 0, 1128, 851, 923, 0, 0, -345,
+ 0, 0, -315, 0, 946, 0, 0, -379, 0, 677,
+ 0, -497, 0, 938, 0, -457, 0, 0, -554, 0,
+ 0, -444, 0, 0, 0, -421, 0, 860, 0, -8,
+ 1218, -80, 0, -182, 688, 1196, 537, 0, 130, 0,
+ 1136, 0, 0, -223, 0, 1170, 0, -312, 0, 0,
+ 1015, 0, 1004, 0, 936, 0, 0, 937, 0, 0,
+ 958, 0, 1472, 933, 821, 0, 0, -591, 0, 0,
+ 1100, 0, 1274, 1205, 0, 0, 872, 0, 0, 1135,
+ 0, -337, 955, 0, 842, -319, 0, 0, 0, 1462,
+ 1464, -3, -2, 0, 0, 0, 0, 0, 0, 0,
+ -169, -119, 0, -192, 0, 0, 0, 0, 0, -178,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define YYTABLESIZE 4783
+static const YYINT pfctlytable[] = { 44,
+ 45, 177, 58, 59, 388, 389, 206, 169, 412, 275,
+ 416, 103, 256, 267, 275, 113, 275, 251, 175, 437,
+ 68, 280, 275, 727, 248, 275, 275, 432, 433, 123,
+ 570, 412, 280, 402, 265, 1, 436, 467, 711, 93,
+ 251, 319, 275, 274, 748, 1, 230, 116, 497, 128,
+ 126, 336, 414, 275, 558, 280, 216, 725, 226, 167,
+ 167, 143, 248, 484, 167, 282, 231, 133, 248, 275,
+ 275, 275, 173, 226, 421, 307, 682, 461, 362, 310,
+ 422, 423, 267, 264, 385, 480, 481, 328, 311, 331,
+ 728, 275, 216, 439, 1, 362, 177, 275, 275, 746,
+ 344, 467, 494, 46, 761, 275, 275, 275, 690, 424,
+ 216, 496, 803, 499, 610, 439, 53, 275, 275, 437,
+ 440, 438, 441, 276, 101, 216, 275, 20, 113, 216,
+ 275, 175, 309, 516, 275, 400, 708, 327, 391, 527,
+ 216, 225, 440, 438, 441, 326, 275, 329, 439, 166,
+ 371, 216, 466, 134, 371, 309, 395, 129, 390, 169,
+ 345, 361, 346, 412, 538, 757, 309, 439, 705, 404,
+ 623, 474, 794, 330, 412, 440, 438, 441, 556, 216,
+ 216, 275, 309, 309, 309, 275, 412, 368, 584, 752,
+ 439, 343, 610, 722, 440, 438, 441, 338, 216, 383,
+ 621, 131, 121, 162, 416, 437, 394, 275, 559, 272,
+ 476, 275, 317, 180, 180, 180, 396, 440, 438, 441,
+ 54, 509, 477, 620, 167, 56, 486, 122, 251, 452,
+ 482, 631, 533, 805, 275, 275, 275, 298, 392, 490,
+ 87, 428, 88, 216, 758, 309, 495, 309, 275, 453,
+ 132, 447, 629, 488, 77, 339, 510, 668, 804, 275,
+ 549, 560, 437, 491, 81, 121, 275, 124, 275, 251,
+ 471, 472, 437, 169, 251, 251, 139, 140, 760, 625,
+ 475, 651, 478, 251, 275, 452, 412, 437, 416, 534,
+ 122, 1, 1, 1, 1, 101, 251, 251, 347, 437,
+ 437, 437, 318, 437, 369, 453, 458, 248, 369, 251,
+ 280, 125, 251, 248, 371, 439, 511, 512, 251, 550,
+ 1, 1, 1, 437, 633, 141, 281, 161, 91, 347,
+ 414, 251, 347, 1, 267, 275, 305, 306, 460, 534,
+ 267, 528, 440, 438, 441, 1, 806, 532, 80, 1,
+ 1, 1, 1, 1, 537, 412, 275, 113, 275, 275,
+ 275, 617, 618, 619, 251, 275, 275, 1, 726, 1,
+ 437, 248, 412, 4, 5, 6, 1, 548, 626, 280,
+ 124, 251, 99, 738, 99, 101, 91, 1, 251, 113,
+ 740, 309, 634, 275, 275, 1, 280, 280, 681, 414,
+ 309, 309, 224, 309, 309, 675, 216, 290, 291, 385,
+ 385, 385, 385, 385, 309, 7, 99, 224, 616, 1,
+ 309, 309, 360, 286, 309, 309, 309, 8, 216, 267,
+ 309, 9, 10, 11, 12, 13, 624, 385, 627, 360,
+ 309, 412, 275, 275, 174, 175, 286, 132, 309, 14,
+ 632, 15, 689, 286, 286, 799, 452, 286, 16, 800,
+ 580, 275, 309, 437, 647, 607, 174, 175, 369, 17,
+ 275, 275, 216, 286, 309, 370, 453, 18, 78, 309,
+ 251, 719, 416, 655, 309, 251, 251, 774, 412, 412,
+ 412, 412, 412, 553, 251, 216, 309, 309, 660, 666,
+ 667, 19, 730, 704, 309, 309, 309, 309, 706, 780,
+ 412, 649, 580, 91, 267, 216, 412, 567, 666, 667,
+ 734, 735, 736, 82, 696, 275, 275, 412, 92, 416,
+ 416, 416, 416, 416, 93, 713, 286, 267, 286, 628,
+ 715, 673, 674, 607, 115, 448, 449, 94, 720, 99,
+ 764, 458, 766, 783, 152, 723, 290, 416, 275, 275,
+ 132, 95, 775, 390, 390, 390, 390, 390, 781, 99,
+ 290, 291, 784, 450, 451, 251, 787, 788, 96, 290,
+ 791, 356, 178, 793, 111, 739, 290, 290, 744, 73,
+ 290, 390, 275, 275, 347, 693, 790, 290, 291, 124,
+ 124, 124, 124, 124, 124, 124, 290, 290, 291, 124,
+ 124, 124, 356, 114, 218, 356, 347, 275, 650, 519,
+ 773, 520, 219, 437, 437, 183, 743, 187, 782, 450,
+ 451, 97, 785, 437, 437, 437, 709, 789, 248, 255,
+ 792, 124, 216, 273, 437, 437, 216, 437, 437, 220,
+ 221, 696, 347, 347, 347, 73, 74, 347, 347, 347,
+ 98, 347, 386, 776, 347, 347, 673, 674, 437, 290,
+ 437, 290, 347, 99, 300, 286, 301, 302, 303, 100,
+ 810, 286, 286, 811, 812, 813, 814, 101, 733, 112,
+ 286, 286, 286, 102, 286, 286, 113, 286, 275, 357,
+ 103, 286, 286, 286, 300, 286, 406, 407, 84, 85,
+ 86, 286, 286, 286, 286, 286, 286, 286, 286, 403,
+ 104, 286, 216, 105, 286, 106, 437, 300, 743, 107,
+ 357, 286, 408, 357, 437, 108, 437, 286, 300, 286,
+ 109, 778, 779, 437, 653, 654, 144, 145, 286, 286,
+ 286, 286, 286, 286, 300, 300, 300, 414, 110, 658,
+ 659, 437, 437, 437, 411, 286, 267, 216, 763, 120,
+ 286, 216, 267, 136, 765, 286, 286, 216, 777, 132,
+ 132, 132, 132, 132, 132, 132, 137, 286, 286, 132,
+ 132, 132, 267, 161, 286, 286, 286, 286, 286, 241,
+ 450, 451, 41, 73, 126, 241, 241, 241, 290, 99,
+ 99, 174, 175, 786, 290, 290, 216, 300, 163, 300,
+ 165, 132, 188, 290, 290, 290, 437, 290, 290, 195,
+ 290, 414, 415, 416, 290, 290, 290, 318, 290, 267,
+ 267, 267, 267, 267, 290, 290, 290, 290, 290, 290,
+ 290, 290, 184, 185, 290, 210, 211, 290, 189, 190,
+ 318, 267, 437, 47, 290, 196, 417, 267, 437, 437,
+ 290, 318, 290, 48, 49, 50, 201, 356, 267, 267,
+ 202, 290, 290, 290, 290, 290, 290, 318, 318, 318,
+ 248, 69, 203, 99, 99, 248, 248, 437, 290, 356,
+ 214, 248, 205, 290, 248, 636, 637, 638, 290, 290,
+ 5, 6, 51, 207, 67, 192, 193, 126, 290, 291,
+ 290, 290, 670, 677, 305, 306, 335, 290, 290, 290,
+ 290, 290, 275, 642, 643, 356, 356, 356, 83, 208,
+ 356, 356, 356, 209, 356, 686, 687, 356, 356, 335,
+ 318, 212, 318, 694, 175, 356, 300, 275, 181, 182,
+ 335, 213, 300, 300, 84, 85, 86, 9, 10, 11,
+ 12, 215, 300, 300, 216, 300, 300, 338, 365, 366,
+ 437, 378, 300, 300, 300, 248, 300, 386, 386, 386,
+ 386, 386, 300, 300, 224, 357, 300, 300, 300, 300,
+ 338, 128, 300, 437, 437, 300, 232, 378, 378, 378,
+ 246, 338, 300, 666, 667, 386, 254, 357, 300, 251,
+ 300, 130, 378, 378, 378, 673, 674, 653, 654, 300,
+ 300, 300, 300, 300, 300, 414, 241, 257, 167, 335,
+ 269, 335, 749, 750, 658, 659, 300, 670, 753, 754,
+ 677, 300, 125, 357, 357, 357, 300, 300, 357, 357,
+ 357, 285, 357, 286, 114, 357, 357, 287, 300, 300,
+ 437, 437, 270, 357, 288, 300, 300, 300, 300, 300,
+ 275, 275, 414, 414, 414, 414, 414, 437, 437, 289,
+ 338, 293, 338, 443, 443, 333, 318, 294, 437, 500,
+ 501, 502, 503, 504, 414, 318, 318, 315, 318, 318,
+ 414, 323, 324, 325, 128, 670, 445, 445, 677, 318,
+ 437, 99, 337, 295, 241, 318, 318, 505, 347, 318,
+ 318, 318, 376, 352, 130, 318, 126, 126, 126, 126,
+ 126, 126, 126, 404, 404, 318, 126, 126, 126, 241,
+ 404, 404, 404, 318, 332, 378, 437, 437, 437, 381,
+ 382, 437, 437, 437, 233, 437, 386, 318, 437, 437,
+ 67, 67, 392, 397, 405, 398, 437, 114, 126, 318,
+ 281, 413, 420, 67, 318, 335, 67, 233, 427, 318,
+ 429, 456, 67, 463, 335, 335, 457, 335, 335, 470,
+ 473, 318, 318, 513, 514, 67, 515, 517, 335, 318,
+ 318, 318, 318, 521, 335, 335, 275, 524, 335, 335,
+ 335, 522, 523, 275, 335, 526, 546, 275, 551, 561,
+ 465, 562, 563, 564, 335, 469, 338, 565, 67, 566,
+ 568, 460, 335, 275, 585, 338, 338, 635, 338, 338,
+ 639, 640, 645, 641, 663, 67, 335, 664, 665, 338,
+ 685, 691, 67, 697, 692, 338, 338, 707, 335, 338,
+ 338, 338, 699, 335, 710, 338, 700, 701, 335, 650,
+ 712, 198, 199, 200, 508, 338, 714, 716, 717, 721,
+ 335, 335, 45, 338, 724, 681, 731, 732, 335, 335,
+ 335, 335, 737, 762, 771, 801, 275, 338, 275, 796,
+ 795, 797, 798, 802, 807, 45, 808, 815, 228, 338,
+ 809, 241, 99, 45, 338, 275, 45, 47, 229, 338,
+ 167, 437, 251, 128, 128, 128, 128, 128, 128, 128,
+ 416, 338, 338, 128, 128, 128, 99, 59, 437, 338,
+ 338, 338, 338, 130, 130, 130, 130, 130, 130, 130,
+ 437, 41, 401, 130, 130, 130, 402, 680, 241, 241,
+ 241, 241, 241, 241, 241, 128, 241, 146, 767, 241,
+ 241, 241, 241, 316, 275, 529, 816, 241, 241, 241,
+ 241, 275, 518, 525, 247, 130, 112, 112, 112, 112,
+ 112, 112, 112, 230, 755, 45, 622, 112, 112, 334,
+ 241, 275, 271, 299, 297, 483, 233, 314, 479, 233,
+ 233, 233, 233, 233, 322, 543, 230, 233, 233, 233,
+ 233, 545, 233, 233, 698, 233, 233, 167, 114, 539,
+ 555, 399, 233, 233, 233, 245, 233, 233, 296, 233,
+ 233, 233, 233, 233, 646, 384, 233, 233, 233, 233,
+ 275, 554, 233, 703, 42, 233, 43, 0, 367, 0,
+ 0, 241, 233, 0, 275, 0, 275, 0, 233, 0,
+ 233, 0, 0, 275, 275, 0, 0, 233, 0, 233,
+ 233, 233, 233, 233, 233, 0, 0, 241, 241, 241,
+ 241, 241, 241, 241, 0, 0, 233, 241, 241, 241,
+ 0, 233, 0, 275, 0, 0, 233, 233, 0, 0,
+ 275, 0, 0, 0, 275, 0, 0, 0, 233, 233,
+ 229, 0, 0, 0, 0, 233, 233, 233, 0, 0,
+ 275, 275, 275, 0, 45, 0, 0, 0, 45, 45,
+ 45, 45, 0, 229, 0, 45, 45, 45, 45, 0,
+ 45, 45, 0, 45, 45, 0, 0, 275, 275, 0,
+ 45, 45, 45, 0, 45, 0, 0, 0, 0, 90,
+ 45, 45, 0, 0, 45, 45, 45, 45, 0, 0,
+ 45, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 45, 0, 0, 275, 0, 275, 45, 0, 45, 0,
+ 0, 0, 0, 117, 118, 119, 0, 45, 45, 45,
+ 45, 45, 45, 0, 138, 0, 0, 39, 275, 0,
+ 0, 0, 0, 0, 45, 0, 172, 0, 0, 45,
+ 0, 0, 0, 0, 45, 45, 0, 0, 0, 0,
+ 0, 275, 275, 209, 0, 230, 45, 45, 0, 230,
+ 230, 230, 230, 45, 45, 45, 230, 230, 230, 230,
+ 0, 230, 230, 0, 230, 230, 209, 0, 0, 0,
+ 0, 0, 230, 230, 0, 230, 230, 0, 230, 230,
+ 230, 230, 230, 572, 573, 230, 230, 230, 230, 0,
+ 0, 230, 0, 0, 230, 0, 574, 0, 0, 575,
+ 0, 230, 0, 0, 0, 576, 0, 230, 0, 230,
+ 0, 211, 0, 0, 0, 0, 230, 0, 577, 0,
+ 0, 0, 0, 230, 0, 275, 275, 0, 249, 250,
+ 0, 0, 40, 253, 211, 230, 0, 0, 0, 0,
+ 230, 0, 0, 260, 0, 230, 0, 275, 0, 0,
+ 0, 578, 0, 0, 0, 0, 0, 230, 230, 0,
+ 0, 0, 0, 0, 230, 230, 230, 0, 0, 0,
+ 275, 275, 229, 0, 0, 579, 229, 229, 229, 229,
+ 0, 0, 147, 229, 229, 229, 229, 0, 229, 229,
+ 0, 229, 229, 0, 0, 0, 0, 0, 0, 229,
+ 229, 0, 229, 229, 148, 229, 229, 229, 229, 229,
+ 0, 0, 229, 229, 229, 229, 0, 0, 229, 0,
+ 0, 229, 0, 0, 0, 0, 0, 0, 229, 275,
+ 0, 0, 0, 0, 229, 213, 229, 261, 262, 263,
+ 149, 150, 151, 229, 0, 152, 153, 154, 0, 155,
+ 229, 0, 144, 145, 275, 275, 0, 0, 213, 0,
+ 156, 0, 229, 38, 5, 6, 0, 229, 0, 0,
+ 0, 0, 229, 0, 0, 485, 487, 489, 0, 0,
+ 0, 0, 492, 493, 229, 229, 0, 0, 0, 0,
+ 0, 229, 229, 229, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 0, 0, 7, 209, 209, 209, 209,
+ 0, 209, 209, 0, 209, 209, 0, 0, 0, 0,
+ 0, 9, 10, 11, 12, 209, 209, 0, 209, 209,
+ 209, 209, 209, 0, 0, 209, 209, 209, 359, 0,
+ 0, 209, 0, 0, 0, 540, 0, 541, 0, 542,
+ 0, 209, 544, 380, 0, 0, 0, 0, 214, 209,
+ 0, 385, 211, 211, 211, 211, 211, 211, 211, 211,
+ 211, 0, 0, 209, 211, 211, 211, 211, 0, 211,
+ 211, 214, 211, 211, 0, 209, 0, 0, 0, 0,
+ 209, 0, 0, 211, 211, 209, 211, 211, 211, 211,
+ 211, 0, 437, 211, 211, 211, 434, 209, 209, 211,
+ 0, 0, 0, 0, 0, 209, 209, 0, 0, 211,
+ 0, 0, 0, 0, 437, 0, 0, 211, 0, 0,
+ 0, 0, 0, 0, 0, 0, 60, 61, 62, 63,
+ 64, 211, 65, 0, 66, 0, 67, 68, 69, 0,
+ 0, 0, 0, 211, 0, 0, 271, 0, 211, 0,
+ 437, 437, 437, 211, 0, 437, 437, 437, 0, 437,
+ 0, 0, 437, 437, 0, 211, 211, 0, 70, 271,
+ 437, 702, 0, 211, 211, 0, 213, 213, 213, 213,
+ 213, 213, 213, 213, 213, 71, 72, 0, 213, 213,
+ 213, 213, 0, 213, 213, 0, 213, 213, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 213, 213, 0,
+ 213, 213, 213, 213, 213, 0, 0, 213, 213, 213,
+ 0, 0, 0, 213, 0, 0, 0, 0, 248, 0,
+ 0, 0, 0, 213, 112, 112, 112, 112, 112, 112,
+ 112, 213, 0, 0, 114, 112, 112, 0, 0, 0,
+ 0, 248, 0, 0, 0, 213, 261, 0, 0, 271,
+ 0, 0, 0, 0, 0, 0, 0, 213, 0, 0,
+ 0, 0, 213, 0, 0, 0, 0, 213, 0, 261,
+ 0, 0, 0, 0, 0, 768, 769, 770, 0, 213,
+ 213, 0, 0, 0, 0, 0, 0, 213, 213, 214,
+ 214, 214, 214, 214, 214, 214, 214, 214, 0, 0,
+ 0, 214, 214, 214, 214, 0, 214, 214, 0, 214,
+ 214, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 214, 214, 0, 214, 214, 214, 214, 214, 0, 0,
+ 214, 214, 214, 0, 0, 0, 214, 233, 234, 235,
+ 236, 237, 238, 239, 0, 0, 214, 0, 240, 241,
+ 0, 0, 0, 0, 214, 0, 0, 0, 0, 261,
+ 0, 0, 0, 0, 0, 0, 0, 0, 214, 223,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 214, 0, 0, 0, 0, 214, 0, 0, 271, 0,
+ 214, 0, 223, 0, 271, 271, 0, 0, 0, 0,
+ 0, 0, 214, 214, 271, 271, 0, 271, 271, 0,
+ 214, 214, 0, 0, 271, 271, 271, 0, 271, 0,
+ 0, 0, 0, 0, 271, 271, 0, 0, 271, 271,
+ 271, 271, 0, 0, 271, 0, 0, 271, 0, 0,
+ 0, 0, 0, 0, 271, 0, 0, 0, 0, 0,
+ 271, 0, 271, 0, 0, 0, 0, 0, 0, 0,
+ 0, 271, 271, 271, 271, 271, 271, 269, 0, 0,
+ 248, 0, 0, 0, 0, 248, 248, 0, 271, 0,
+ 0, 248, 0, 271, 248, 0, 0, 0, 271, 271,
+ 269, 0, 0, 0, 0, 0, 0, 248, 248, 0,
+ 271, 271, 0, 0, 261, 261, 0, 271, 271, 271,
+ 248, 0, 0, 248, 261, 261, 0, 261, 261, 248,
+ 0, 0, 0, 0, 261, 261, 261, 0, 261, 0,
+ 0, 0, 248, 0, 261, 261, 0, 0, 261, 261,
+ 261, 261, 0, 0, 261, 0, 0, 261, 0, 0,
+ 0, 0, 0, 0, 261, 0, 0, 0, 0, 0,
+ 261, 0, 261, 0, 0, 248, 0, 0, 0, 0,
+ 0, 261, 261, 261, 261, 261, 261, 0, 392, 0,
+ 269, 0, 248, 0, 0, 0, 0, 0, 261, 248,
+ 0, 0, 0, 261, 0, 0, 0, 0, 261, 261,
+ 0, 392, 0, 0, 0, 0, 0, 0, 0, 0,
+ 261, 261, 0, 0, 0, 0, 0, 261, 261, 261,
+ 0, 223, 267, 223, 223, 223, 223, 223, 223, 0,
+ 0, 0, 223, 223, 223, 223, 0, 223, 223, 0,
+ 223, 223, 0, 0, 0, 267, 0, 0, 0, 0,
+ 0, 223, 223, 0, 223, 223, 223, 223, 223, 0,
+ 0, 223, 223, 223, 0, 0, 0, 223, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 223, 0, 0,
+ 0, 0, 0, 0, 0, 223, 0, 0, 0, 388,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 223,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 223, 388, 0, 0, 0, 223, 0, 0, 0,
+ 0, 223, 0, 0, 0, 0, 269, 0, 0, 0,
+ 0, 0, 0, 223, 223, 269, 269, 0, 269, 269,
+ 0, 223, 223, 0, 0, 269, 269, 269, 0, 269,
+ 0, 0, 0, 0, 0, 269, 269, 0, 0, 269,
+ 269, 269, 269, 0, 0, 269, 0, 0, 269, 0,
+ 0, 0, 0, 0, 0, 269, 0, 0, 0, 0,
+ 241, 269, 0, 269, 0, 0, 0, 0, 0, 0,
+ 0, 0, 269, 269, 269, 269, 269, 269, 0, 0,
+ 0, 0, 0, 241, 0, 0, 0, 0, 0, 269,
+ 0, 0, 0, 0, 269, 0, 0, 0, 0, 269,
+ 269, 0, 52, 0, 0, 0, 0, 0, 0, 0,
+ 392, 269, 269, 0, 0, 392, 392, 392, 269, 269,
+ 269, 392, 392, 392, 392, 52, 392, 392, 0, 392,
+ 392, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 392, 0, 0, 0, 0, 0, 392, 392, 0, 0,
+ 392, 392, 392, 0, 267, 0, 392, 0, 0, 0,
+ 267, 0, 0, 0, 0, 0, 392, 0, 0, 0,
+ 228, 0, 0, 0, 392, 0, 0, 0, 0, 0,
+ 0, 267, 267, 390, 390, 390, 390, 390, 392, 0,
+ 0, 0, 0, 228, 267, 0, 0, 267, 0, 0,
+ 392, 0, 0, 267, 0, 392, 0, 0, 0, 0,
+ 392, 390, 0, 0, 0, 52, 267, 0, 0, 0,
+ 0, 388, 392, 392, 0, 0, 388, 388, 388, 0,
+ 392, 392, 388, 388, 388, 388, 0, 388, 388, 0,
+ 388, 388, 0, 0, 0, 0, 0, 0, 0, 267,
+ 0, 388, 0, 0, 0, 0, 0, 388, 388, 0,
+ 0, 388, 388, 388, 0, 0, 267, 388, 0, 0,
+ 0, 0, 0, 267, 0, 0, 0, 388, 0, 0,
+ 0, 241, 0, 0, 0, 388, 0, 0, 0, 0,
+ 0, 0, 0, 0, 388, 388, 388, 388, 388, 388,
+ 0, 0, 0, 0, 241, 0, 0, 0, 0, 0,
+ 0, 388, 241, 0, 0, 0, 388, 241, 241, 0,
+ 0, 388, 388, 241, 241, 241, 241, 0, 0, 0,
+ 0, 0, 0, 388, 388, 0, 0, 0, 241, 0,
+ 0, 388, 388, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 52, 52, 52, 0, 52, 52, 52,
+ 52, 52, 0, 0, 0, 52, 52, 52, 52, 0,
+ 52, 52, 0, 52, 52, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 52, 241, 241, 241, 241, 241,
+ 52, 52, 223, 0, 52, 52, 52, 0, 0, 0,
+ 52, 0, 0, 0, 0, 0, 0, 241, 0, 0,
+ 52, 0, 0, 241, 0, 223, 0, 0, 52, 0,
+ 0, 0, 228, 0, 241, 241, 228, 228, 228, 228,
+ 0, 0, 52, 228, 228, 228, 228, 0, 228, 228,
+ 0, 228, 228, 0, 52, 0, 0, 0, 0, 52,
+ 0, 0, 228, 228, 52, 228, 228, 228, 228, 228,
+ 0, 0, 228, 228, 228, 0, 52, 52, 228, 0,
+ 0, 0, 0, 0, 52, 52, 0, 0, 228, 0,
+ 0, 0, 0, 0, 0, 0, 228, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 228, 0, 0, 226, 0, 223, 0, 0, 0, 0,
+ 0, 0, 228, 0, 0, 0, 0, 228, 0, 0,
+ 0, 0, 228, 0, 0, 0, 226, 0, 0, 0,
+ 0, 0, 0, 241, 228, 228, 0, 0, 241, 241,
+ 241, 0, 228, 228, 241, 241, 241, 241, 0, 241,
+ 241, 0, 241, 241, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 241, 241, 0, 241, 241, 241, 241,
+ 241, 0, 0, 241, 241, 241, 0, 0, 0, 241,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 241,
+ 0, 0, 0, 0, 0, 0, 0, 241, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 241, 0, 0, 241, 0, 226, 0, 0, 0,
+ 0, 0, 0, 241, 0, 0, 0, 0, 241, 0,
+ 0, 0, 0, 241, 0, 0, 0, 241, 0, 0,
+ 0, 0, 0, 0, 223, 241, 241, 223, 223, 223,
+ 223, 223, 0, 241, 241, 223, 223, 223, 223, 0,
+ 223, 223, 0, 223, 223, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 223, 0, 0, 0, 0, 0,
+ 223, 223, 424, 0, 223, 223, 223, 0, 0, 0,
+ 223, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 223, 0, 0, 0, 0, 424, 0, 0, 223, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 223, 0, 0, 0, 0, 241, 0, 0,
+ 0, 0, 0, 0, 223, 0, 0, 0, 0, 223,
+ 0, 0, 0, 0, 223, 0, 0, 0, 0, 0,
+ 391, 0, 0, 0, 0, 226, 223, 223, 0, 226,
+ 226, 226, 226, 0, 223, 223, 226, 226, 226, 226,
+ 0, 226, 226, 391, 226, 226, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 226, 0, 0, 0, 0,
+ 0, 226, 226, 0, 0, 226, 226, 226, 0, 0,
+ 0, 226, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 226, 0, 0, 0, 0, 0, 0, 248, 226,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 226, 0, 0, 0, 0, 0, 0,
+ 0, 248, 0, 0, 0, 226, 0, 0, 0, 0,
+ 226, 0, 0, 0, 0, 226, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 241, 226, 226, 0,
+ 0, 241, 241, 241, 0, 226, 226, 241, 241, 241,
+ 241, 0, 241, 241, 0, 241, 241, 248, 0, 0,
+ 0, 0, 0, 0, 0, 0, 241, 0, 0, 0,
+ 0, 0, 241, 241, 0, 0, 241, 241, 241, 0,
+ 248, 0, 241, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 241, 0, 0, 0, 0, 0, 0, 0,
+ 241, 248, 0, 0, 424, 241, 0, 0, 0, 424,
+ 424, 424, 0, 0, 241, 424, 424, 424, 424, 0,
+ 424, 424, 0, 424, 424, 0, 241, 0, 241, 0,
+ 0, 241, 0, 0, 424, 0, 241, 0, 0, 0,
+ 424, 424, 0, 0, 424, 424, 424, 0, 241, 241,
+ 424, 0, 0, 0, 0, 0, 241, 241, 0, 0,
+ 424, 0, 0, 0, 0, 0, 0, 0, 424, 0,
+ 0, 0, 391, 0, 251, 0, 0, 391, 391, 391,
+ 0, 0, 424, 391, 391, 391, 391, 0, 391, 391,
+ 0, 391, 391, 0, 424, 0, 0, 251, 0, 424,
+ 0, 0, 391, 0, 424, 0, 0, 0, 391, 391,
+ 0, 0, 391, 391, 391, 0, 424, 424, 391, 0,
+ 0, 0, 0, 0, 424, 424, 251, 0, 391, 0,
+ 0, 0, 0, 0, 0, 0, 391, 0, 0, 0,
+ 248, 0, 0, 0, 0, 248, 248, 248, 0, 251,
+ 391, 248, 0, 0, 248, 0, 248, 248, 0, 248,
+ 248, 0, 391, 0, 0, 0, 0, 391, 0, 0,
+ 248, 0, 391, 0, 0, 0, 248, 248, 0, 0,
+ 248, 248, 248, 0, 391, 391, 248, 251, 0, 0,
+ 0, 0, 391, 391, 0, 0, 248, 0, 0, 0,
+ 0, 0, 0, 0, 248, 0, 0, 0, 0, 248,
+ 0, 0, 0, 0, 248, 248, 248, 0, 248, 0,
+ 248, 0, 0, 248, 267, 248, 248, 0, 248, 248,
+ 248, 0, 0, 0, 0, 248, 0, 0, 0, 248,
+ 248, 0, 0, 0, 0, 248, 248, 267, 0, 248,
+ 248, 248, 248, 248, 0, 248, 0, 241, 0, 0,
+ 248, 248, 241, 241, 0, 248, 0, 0, 241, 241,
+ 241, 241, 0, 248, 0, 267, 0, 0, 0, 0,
+ 0, 0, 0, 0, 241, 241, 0, 248, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 241, 267, 248,
+ 241, 0, 0, 0, 248, 0, 241, 0, 0, 248,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 241,
+ 0, 248, 248, 0, 0, 0, 251, 0, 0, 248,
+ 248, 251, 251, 251, 0, 0, 0, 267, 0, 0,
+ 251, 0, 251, 251, 0, 251, 251, 0, 0, 0,
+ 0, 0, 241, 0, 0, 0, 251, 0, 0, 0,
+ 0, 0, 251, 251, 176, 0, 251, 251, 251, 241,
+ 0, 0, 251, 0, 0, 0, 241, 0, 251, 0,
+ 0, 0, 251, 251, 251, 251, 0, 174, 0, 0,
+ 251, 0, 251, 0, 251, 251, 0, 251, 251, 0,
+ 0, 0, 0, 0, 251, 0, 0, 0, 251, 0,
+ 360, 0, 0, 0, 251, 251, 251, 0, 251, 251,
+ 251, 251, 0, 0, 251, 0, 251, 0, 0, 0,
+ 0, 0, 0, 360, 251, 0, 0, 0, 251, 251,
+ 0, 0, 251, 0, 0, 0, 251, 251, 0, 0,
+ 0, 0, 0, 0, 0, 0, 251, 0, 0, 0,
+ 0, 0, 49, 0, 0, 0, 0, 0, 251, 0,
+ 0, 0, 0, 251, 0, 0, 267, 176, 251, 0,
+ 0, 0, 267, 267, 0, 49, 0, 0, 0, 0,
+ 251, 251, 267, 267, 0, 267, 267, 0, 251, 251,
+ 0, 0, 0, 0, 0, 0, 267, 0, 176, 0,
+ 0, 0, 267, 267, 0, 0, 267, 267, 267, 0,
+ 0, 0, 267, 360, 0, 0, 0, 267, 0, 0,
+ 0, 174, 267, 267, 267, 0, 0, 0, 0, 0,
+ 267, 0, 0, 267, 267, 0, 267, 267, 0, 0,
+ 0, 0, 0, 0, 267, 0, 0, 267, 0, 0,
+ 0, 0, 0, 267, 267, 0, 267, 267, 267, 267,
+ 0, 267, 0, 267, 0, 49, 267, 0, 0, 0,
+ 0, 0, 0, 267, 0, 0, 0, 0, 267, 267,
+ 0, 267, 0, 0, 0, 0, 267, 267, 0, 0,
+ 0, 0, 0, 0, 0, 267, 0, 0, 0, 0,
+ 0, 223, 0, 0, 0, 0, 0, 267, 0, 0,
+ 0, 0, 267, 174, 0, 0, 0, 267, 0, 0,
+ 0, 228, 174, 174, 223, 174, 174, 0, 0, 267,
+ 267, 0, 0, 0, 0, 0, 174, 267, 267, 0,
+ 0, 0, 174, 174, 228, 0, 174, 174, 174, 0,
+ 0, 0, 174, 0, 404, 0, 0, 0, 0, 360,
+ 0, 0, 174, 0, 0, 0, 0, 0, 360, 360,
+ 174, 360, 360, 0, 0, 0, 0, 404, 0, 0,
+ 0, 0, 360, 0, 174, 0, 405, 0, 360, 360,
+ 0, 0, 360, 360, 360, 0, 174, 0, 360, 0,
+ 0, 174, 0, 0, 0, 0, 174, 0, 360, 405,
+ 0, 49, 0, 0, 0, 0, 360, 0, 174, 174,
+ 49, 49, 0, 49, 49, 0, 174, 174, 0, 0,
+ 360, 0, 248, 0, 49, 0, 0, 0, 0, 251,
+ 49, 49, 360, 0, 49, 49, 49, 360, 0, 0,
+ 49, 0, 360, 0, 0, 248, 0, 174, 0, 0,
+ 49, 0, 251, 0, 360, 360, 174, 174, 49, 174,
+ 174, 0, 360, 360, 0, 0, 0, 0, 0, 0,
+ 174, 0, 49, 0, 0, 0, 174, 174, 0, 0,
+ 174, 174, 174, 0, 49, 0, 174, 0, 0, 49,
+ 0, 0, 0, 0, 49, 0, 174, 0, 0, 0,
+ 0, 0, 0, 0, 174, 0, 49, 49, 0, 0,
+ 0, 0, 0, 0, 49, 49, 0, 0, 174, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 174, 0, 167, 0, 0, 174, 0, 0, 0, 0,
+ 174, 0, 0, 223, 0, 223, 223, 223, 223, 223,
+ 0, 0, 174, 174, 223, 223, 223, 223, 0, 0,
+ 174, 174, 0, 228, 0, 0, 0, 228, 228, 228,
+ 223, 223, 0, 0, 228, 228, 228, 228, 0, 0,
+ 0, 0, 0, 223, 0, 0, 223, 0, 0, 0,
+ 228, 228, 223, 0, 0, 0, 404, 0, 0, 0,
+ 404, 404, 404, 228, 0, 223, 228, 404, 404, 404,
+ 404, 0, 228, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 404, 0, 0, 228, 0, 0, 405, 0,
+ 0, 0, 405, 405, 405, 0, 0, 0, 223, 405,
+ 405, 405, 405, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 405, 223, 0, 0, 228, 0,
+ 0, 0, 223, 0, 0, 0, 0, 0, 0, 404,
+ 404, 404, 404, 404, 248, 228, 0, 0, 0, 248,
+ 248, 251, 228, 0, 0, 248, 251, 251, 248, 0,
+ 0, 404, 0, 0, 0, 251, 0, 404, 0, 0,
+ 248, 405, 405, 405, 405, 405, 0, 251, 404, 404,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 405, 0, 0, 0, 0, 0, 405,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 405, 405, 0, 0, 0, 0, 0, 248, 248, 248,
+ 248, 248, 0, 0, 251, 251, 251, 251, 251, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 587, 248,
+ 0, 0, 0, 0, 0, 248, 251, 588, 589, 0,
+ 590, 591, 251, 0, 0, 0, 248, 248, 0, 0,
+ 0, 592, 0, 251, 251, 0, 0, 593, 338, 0,
+ 0, 594, 595, 596, 0, 0, 0, 597, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 598, 0, 0,
+ 0, 0, 0, 0, 0, 599, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 600,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 601, 0, 0, 0, 0, 602, 0, 0, 0,
+ 0, 603, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 604, 0, 0, 0, 0, 0,
+ 0, 605, 606,
+};
+static const YYINT pfctlycheck[] = { 3,
+ 3, 82, 11, 12, 324, 325, 126, 78, 10, 33,
+ 10, 10, 191, 206, 33, 10, 44, 10, 10, 33,
+ 10, 230, 40, 40, 10, 44, 44, 365, 366, 123,
+ 528, 33, 10, 346, 204, 0, 368, 383, 651, 10,
+ 33, 123, 33, 222, 713, 10, 166, 56, 428, 276,
+ 123, 275, 10, 44, 512, 33, 44, 677, 40, 33,
+ 33, 70, 267, 40, 33, 123, 169, 298, 273, 60,
+ 61, 62, 81, 40, 349, 123, 40, 123, 40, 267,
+ 355, 356, 10, 203, 10, 406, 407, 266, 276, 268,
+ 682, 33, 44, 33, 123, 40, 177, 125, 40, 712,
+ 279, 447, 423, 10, 724, 225, 125, 125, 40, 384,
+ 44, 427, 781, 429, 536, 33, 60, 40, 60, 40,
+ 60, 61, 62, 226, 123, 44, 40, 10, 123, 44,
+ 44, 123, 10, 442, 125, 344, 634, 125, 331, 459,
+ 44, 123, 60, 61, 62, 265, 60, 267, 33, 123,
+ 123, 44, 125, 384, 123, 33, 335, 384, 328, 230,
+ 280, 123, 282, 10, 477, 720, 44, 33, 626, 348,
+ 550, 395, 764, 125, 353, 60, 61, 62, 510, 44,
+ 44, 123, 60, 61, 62, 44, 33, 307, 534, 715,
+ 33, 125, 614, 670, 60, 61, 62, 299, 44, 319,
+ 546, 260, 359, 74, 10, 123, 125, 33, 517, 218,
+ 125, 125, 294, 84, 85, 86, 336, 60, 61, 62,
+ 384, 125, 401, 544, 33, 384, 40, 384, 10, 40,
+ 409, 569, 125, 788, 60, 61, 62, 246, 10, 418,
+ 261, 361, 263, 44, 721, 123, 425, 125, 40, 60,
+ 309, 371, 568, 40, 384, 357, 435, 123, 784, 359,
+ 125, 125, 359, 40, 314, 359, 125, 10, 60, 262,
+ 390, 391, 33, 344, 267, 268, 384, 385, 723, 125,
+ 400, 47, 402, 276, 384, 40, 288, 384, 288, 468,
+ 384, 256, 257, 258, 259, 294, 289, 290, 10, 60,
+ 61, 62, 384, 40, 277, 60, 377, 178, 277, 302,
+ 288, 384, 305, 299, 123, 33, 436, 437, 311, 498,
+ 285, 286, 287, 60, 125, 41, 384, 41, 299, 41,
+ 288, 324, 44, 298, 262, 277, 384, 385, 384, 518,
+ 268, 461, 60, 61, 62, 310, 791, 467, 384, 314,
+ 315, 316, 317, 318, 474, 357, 384, 352, 300, 301,
+ 384, 540, 541, 542, 357, 384, 384, 332, 385, 334,
+ 384, 357, 374, 256, 257, 258, 341, 497, 557, 357,
+ 123, 374, 374, 703, 374, 384, 357, 352, 381, 384,
+ 706, 269, 571, 384, 385, 360, 374, 375, 362, 357,
+ 278, 279, 384, 281, 282, 123, 44, 384, 385, 335,
+ 336, 337, 338, 339, 292, 298, 374, 384, 538, 384,
+ 298, 299, 384, 10, 302, 303, 304, 310, 44, 357,
+ 308, 314, 315, 316, 317, 318, 556, 363, 558, 384,
+ 318, 288, 384, 385, 384, 385, 33, 10, 326, 332,
+ 570, 334, 384, 40, 41, 771, 40, 44, 341, 775,
+ 531, 384, 340, 384, 584, 536, 384, 385, 277, 352,
+ 384, 385, 44, 60, 352, 284, 60, 360, 266, 357,
+ 262, 664, 288, 123, 362, 267, 268, 125, 335, 336,
+ 337, 338, 339, 502, 276, 44, 374, 375, 123, 384,
+ 385, 384, 685, 623, 382, 383, 384, 385, 628, 125,
+ 357, 277, 583, 24, 10, 44, 363, 526, 384, 385,
+ 699, 700, 701, 61, 605, 384, 385, 374, 10, 335,
+ 336, 337, 338, 339, 10, 655, 123, 33, 125, 123,
+ 660, 384, 385, 614, 55, 300, 301, 10, 668, 40,
+ 729, 622, 731, 125, 41, 675, 10, 363, 384, 385,
+ 123, 10, 741, 335, 336, 337, 338, 339, 747, 60,
+ 384, 385, 751, 384, 385, 357, 125, 756, 10, 33,
+ 759, 10, 257, 762, 40, 705, 40, 41, 708, 264,
+ 44, 363, 384, 385, 306, 604, 125, 384, 385, 342,
+ 343, 344, 345, 346, 347, 348, 60, 384, 385, 352,
+ 353, 354, 41, 384, 268, 44, 328, 44, 384, 45,
+ 740, 47, 276, 384, 385, 89, 707, 91, 748, 384,
+ 385, 10, 752, 349, 350, 351, 645, 757, 10, 41,
+ 760, 384, 44, 41, 358, 359, 44, 384, 385, 303,
+ 304, 732, 364, 365, 366, 264, 265, 369, 370, 371,
+ 10, 373, 10, 10, 376, 377, 384, 385, 384, 123,
+ 384, 125, 384, 10, 293, 262, 295, 296, 297, 10,
+ 800, 268, 269, 803, 804, 805, 806, 10, 697, 40,
+ 277, 278, 279, 10, 281, 282, 40, 284, 125, 10,
+ 10, 288, 289, 290, 10, 292, 358, 359, 285, 286,
+ 287, 298, 299, 300, 301, 302, 303, 304, 305, 41,
+ 10, 308, 44, 10, 311, 10, 268, 33, 809, 10,
+ 41, 318, 384, 44, 276, 10, 33, 324, 44, 326,
+ 10, 745, 745, 40, 384, 385, 376, 377, 335, 336,
+ 337, 338, 339, 340, 60, 61, 62, 10, 10, 384,
+ 385, 303, 304, 60, 41, 352, 262, 44, 41, 384,
+ 357, 44, 268, 384, 41, 362, 363, 44, 125, 342,
+ 343, 344, 345, 346, 347, 348, 384, 374, 375, 352,
+ 353, 354, 288, 40, 381, 382, 383, 384, 385, 267,
+ 384, 385, 10, 264, 10, 273, 274, 275, 262, 300,
+ 301, 384, 385, 41, 268, 269, 44, 123, 333, 125,
+ 265, 384, 307, 277, 278, 279, 123, 281, 282, 62,
+ 284, 349, 350, 351, 288, 289, 290, 10, 292, 335,
+ 336, 337, 338, 339, 298, 299, 300, 301, 302, 303,
+ 304, 305, 274, 275, 308, 367, 368, 311, 384, 385,
+ 33, 357, 349, 260, 318, 265, 384, 363, 355, 356,
+ 324, 44, 326, 270, 271, 272, 385, 306, 374, 375,
+ 385, 335, 336, 337, 338, 339, 340, 60, 61, 62,
+ 262, 10, 10, 384, 385, 267, 268, 384, 352, 328,
+ 60, 273, 385, 357, 276, 311, 312, 313, 362, 363,
+ 257, 258, 309, 385, 33, 384, 385, 123, 384, 385,
+ 374, 375, 595, 596, 384, 385, 10, 381, 382, 383,
+ 384, 385, 359, 384, 385, 364, 365, 366, 259, 385,
+ 369, 370, 371, 385, 373, 384, 385, 376, 377, 33,
+ 123, 385, 125, 384, 385, 384, 262, 384, 85, 86,
+ 44, 385, 268, 269, 285, 286, 287, 314, 315, 316,
+ 317, 385, 278, 279, 44, 281, 282, 10, 302, 303,
+ 277, 259, 288, 289, 290, 357, 292, 335, 336, 337,
+ 338, 339, 298, 299, 384, 306, 302, 303, 304, 305,
+ 33, 10, 308, 300, 301, 311, 352, 285, 286, 287,
+ 267, 44, 318, 384, 385, 363, 385, 328, 324, 273,
+ 326, 10, 285, 286, 287, 384, 385, 384, 385, 335,
+ 336, 337, 338, 339, 340, 288, 10, 41, 33, 123,
+ 47, 125, 384, 385, 384, 385, 352, 720, 384, 385,
+ 723, 357, 384, 364, 365, 366, 362, 363, 369, 370,
+ 371, 40, 373, 40, 10, 376, 377, 40, 374, 375,
+ 384, 385, 384, 384, 40, 381, 382, 383, 384, 385,
+ 384, 385, 335, 336, 337, 338, 339, 384, 385, 40,
+ 123, 385, 125, 384, 385, 62, 269, 385, 306, 335,
+ 336, 337, 338, 339, 357, 278, 279, 41, 281, 282,
+ 363, 261, 262, 263, 123, 788, 384, 385, 791, 292,
+ 328, 374, 41, 385, 10, 298, 299, 363, 384, 302,
+ 303, 304, 375, 384, 123, 308, 342, 343, 344, 345,
+ 346, 347, 348, 266, 267, 318, 352, 353, 354, 123,
+ 273, 274, 275, 326, 385, 262, 364, 365, 366, 41,
+ 384, 369, 370, 371, 10, 373, 357, 340, 376, 377,
+ 289, 290, 372, 384, 41, 385, 384, 123, 384, 352,
+ 384, 41, 41, 302, 357, 269, 305, 33, 267, 362,
+ 384, 284, 311, 268, 278, 279, 384, 281, 282, 385,
+ 367, 374, 375, 61, 61, 324, 61, 386, 292, 382,
+ 383, 384, 385, 47, 298, 299, 33, 47, 302, 303,
+ 304, 384, 384, 40, 308, 374, 268, 44, 41, 384,
+ 380, 385, 385, 41, 318, 385, 269, 62, 357, 385,
+ 288, 384, 326, 60, 123, 278, 279, 385, 281, 282,
+ 385, 384, 374, 385, 283, 374, 340, 283, 283, 292,
+ 283, 385, 381, 374, 385, 298, 299, 284, 352, 302,
+ 303, 304, 385, 357, 10, 308, 385, 385, 362, 384,
+ 47, 117, 118, 119, 434, 318, 280, 280, 40, 386,
+ 374, 375, 10, 326, 386, 362, 384, 284, 382, 383,
+ 384, 385, 41, 385, 288, 10, 123, 340, 125, 41,
+ 384, 41, 41, 10, 385, 33, 41, 41, 333, 352,
+ 284, 10, 384, 41, 357, 384, 44, 10, 164, 362,
+ 10, 384, 267, 342, 343, 344, 345, 346, 347, 348,
+ 10, 374, 375, 352, 353, 354, 374, 10, 385, 382,
+ 383, 384, 385, 342, 343, 344, 345, 346, 347, 348,
+ 362, 3, 10, 352, 353, 354, 10, 597, 342, 343,
+ 344, 345, 346, 347, 348, 384, 262, 71, 732, 353,
+ 354, 267, 268, 256, 33, 463, 809, 273, 274, 275,
+ 276, 40, 447, 456, 177, 384, 342, 343, 344, 345,
+ 346, 347, 348, 10, 717, 123, 547, 353, 354, 274,
+ 384, 60, 217, 249, 245, 412, 262, 253, 404, 265,
+ 266, 267, 268, 269, 260, 490, 33, 273, 274, 275,
+ 276, 495, 278, 279, 614, 281, 282, 33, 384, 482,
+ 508, 342, 288, 289, 290, 172, 292, 293, 244, 295,
+ 296, 297, 298, 299, 583, 321, 302, 303, 304, 305,
+ 277, 507, 308, 622, 3, 311, 3, -1, 304, -1,
+ -1, 357, 318, -1, 123, -1, 125, -1, 324, -1,
+ 326, -1, -1, 300, 301, -1, -1, 333, -1, 335,
+ 336, 337, 338, 339, 340, -1, -1, 342, 343, 344,
+ 345, 346, 347, 348, -1, -1, 352, 352, 353, 354,
+ -1, 357, -1, 33, -1, -1, 362, 363, -1, -1,
+ 40, -1, -1, -1, 44, -1, -1, -1, 374, 375,
+ 10, -1, -1, -1, -1, 381, 382, 383, -1, -1,
+ 60, 61, 62, -1, 262, -1, -1, -1, 266, 267,
+ 268, 269, -1, 33, -1, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, -1, 384, 385, -1,
+ 288, 289, 290, -1, 292, -1, -1, -1, -1, 23,
+ 298, 299, -1, -1, 302, 303, 304, 305, -1, -1,
+ 308, -1, -1, 311, -1, -1, -1, -1, -1, -1,
+ 318, -1, -1, 123, -1, 125, 324, -1, 326, -1,
+ -1, -1, -1, 57, 58, 59, -1, 335, 336, 337,
+ 338, 339, 340, -1, 68, -1, -1, 10, 277, -1,
+ -1, -1, -1, -1, 352, -1, 80, -1, -1, 357,
+ -1, -1, -1, -1, 362, 363, -1, -1, -1, -1,
+ -1, 300, 301, 10, -1, 262, 374, 375, -1, 266,
+ 267, 268, 269, 381, 382, 383, 273, 274, 275, 276,
+ -1, 278, 279, -1, 281, 282, 33, -1, -1, -1,
+ -1, -1, 289, 290, -1, 292, 293, -1, 295, 296,
+ 297, 298, 299, 289, 290, 302, 303, 304, 305, -1,
+ -1, 308, -1, -1, 311, -1, 302, -1, -1, 305,
+ -1, 318, -1, -1, -1, 311, -1, 324, -1, 326,
+ -1, 10, -1, -1, -1, -1, 333, -1, 324, -1,
+ -1, -1, -1, 340, -1, 384, 385, -1, 182, 183,
+ -1, -1, 125, 187, 33, 352, -1, -1, -1, -1,
+ 357, -1, -1, 197, -1, 362, -1, 277, -1, -1,
+ -1, 357, -1, -1, -1, -1, -1, 374, 375, -1,
+ -1, -1, -1, -1, 381, 382, 383, -1, -1, -1,
+ 300, 301, 262, -1, -1, 381, 266, 267, 268, 269,
+ -1, -1, 306, 273, 274, 275, 276, -1, 278, 279,
+ -1, 281, 282, -1, -1, -1, -1, -1, -1, 289,
+ 290, -1, 292, 293, 328, 295, 296, 297, 298, 299,
+ -1, -1, 302, 303, 304, 305, -1, -1, 308, -1,
+ -1, 311, -1, -1, -1, -1, -1, -1, 318, 359,
+ -1, -1, -1, -1, 324, 10, 326, 198, 199, 200,
+ 364, 365, 366, 333, -1, 369, 370, 371, -1, 373,
+ 340, -1, 376, 377, 384, 385, -1, -1, 33, -1,
+ 384, -1, 352, 256, 257, 258, -1, 357, -1, -1,
+ -1, -1, 362, -1, -1, 414, 415, 416, -1, -1,
+ -1, -1, 421, 422, 374, 375, -1, -1, -1, -1,
+ -1, 381, 382, 383, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, -1, -1, 298, 273, 274, 275, 276,
+ -1, 278, 279, -1, 281, 282, -1, -1, -1, -1,
+ -1, 314, 315, 316, 317, 292, 293, -1, 295, 296,
+ 297, 298, 299, -1, -1, 302, 303, 304, 299, -1,
+ -1, 308, -1, -1, -1, 484, -1, 486, -1, 488,
+ -1, 318, 491, 314, -1, -1, -1, -1, 10, 326,
+ -1, 322, 261, 262, 263, 264, 265, 266, 267, 268,
+ 269, -1, -1, 340, 273, 274, 275, 276, -1, 278,
+ 279, 33, 281, 282, -1, 352, -1, -1, -1, -1,
+ 357, -1, -1, 292, 293, 362, 295, 296, 297, 298,
+ 299, -1, 306, 302, 303, 304, 367, 374, 375, 308,
+ -1, -1, -1, -1, -1, 382, 383, -1, -1, 318,
+ -1, -1, -1, -1, 328, -1, -1, 326, -1, -1,
+ -1, -1, -1, -1, -1, -1, 319, 320, 321, 322,
+ 323, 340, 325, -1, 327, -1, 329, 330, 331, -1,
+ -1, -1, -1, 352, -1, -1, 10, -1, 357, -1,
+ 364, 365, 366, 362, -1, 369, 370, 371, -1, 373,
+ -1, -1, 376, 377, -1, 374, 375, -1, 361, 33,
+ 384, 620, -1, 382, 383, -1, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 378, 379, -1, 273, 274,
+ 275, 276, -1, 278, 279, -1, 281, 282, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 292, 293, -1,
+ 295, 296, 297, 298, 299, -1, -1, 302, 303, 304,
+ -1, -1, -1, 308, -1, -1, -1, -1, 10, -1,
+ -1, -1, -1, 318, 342, 343, 344, 345, 346, 347,
+ 348, 326, -1, -1, 352, 353, 354, -1, -1, -1,
+ -1, 33, -1, -1, -1, 340, 10, -1, -1, 123,
+ -1, -1, -1, -1, -1, -1, -1, 352, -1, -1,
+ -1, -1, 357, -1, -1, -1, -1, 362, -1, 33,
+ -1, -1, -1, -1, -1, 734, 735, 736, -1, 374,
+ 375, -1, -1, -1, -1, -1, -1, 382, 383, 261,
+ 262, 263, 264, 265, 266, 267, 268, 269, -1, -1,
+ -1, 273, 274, 275, 276, -1, 278, 279, -1, 281,
+ 282, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 292, 293, -1, 295, 296, 297, 298, 299, -1, -1,
+ 302, 303, 304, -1, -1, -1, 308, 342, 343, 344,
+ 345, 346, 347, 348, -1, -1, 318, -1, 353, 354,
+ -1, -1, -1, -1, 326, -1, -1, -1, -1, 123,
+ -1, -1, -1, -1, -1, -1, -1, -1, 340, 10,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 352, -1, -1, -1, -1, 357, -1, -1, 262, -1,
+ 362, -1, 33, -1, 268, 269, -1, -1, -1, -1,
+ -1, -1, 374, 375, 278, 279, -1, 281, 282, -1,
+ 382, 383, -1, -1, 288, 289, 290, -1, 292, -1,
+ -1, -1, -1, -1, 298, 299, -1, -1, 302, 303,
+ 304, 305, -1, -1, 308, -1, -1, 311, -1, -1,
+ -1, -1, -1, -1, 318, -1, -1, -1, -1, -1,
+ 324, -1, 326, -1, -1, -1, -1, -1, -1, -1,
+ -1, 335, 336, 337, 338, 339, 340, 10, -1, -1,
+ 262, -1, -1, -1, -1, 267, 268, -1, 352, -1,
+ -1, 273, -1, 357, 276, -1, -1, -1, 362, 363,
+ 33, -1, -1, -1, -1, -1, -1, 289, 290, -1,
+ 374, 375, -1, -1, 268, 269, -1, 381, 382, 383,
+ 302, -1, -1, 305, 278, 279, -1, 281, 282, 311,
+ -1, -1, -1, -1, 288, 289, 290, -1, 292, -1,
+ -1, -1, 324, -1, 298, 299, -1, -1, 302, 303,
+ 304, 305, -1, -1, 308, -1, -1, 311, -1, -1,
+ -1, -1, -1, -1, 318, -1, -1, -1, -1, -1,
+ 324, -1, 326, -1, -1, 357, -1, -1, -1, -1,
+ -1, 335, 336, 337, 338, 339, 340, -1, 10, -1,
+ 123, -1, 374, -1, -1, -1, -1, -1, 352, 381,
+ -1, -1, -1, 357, -1, -1, -1, -1, 362, 363,
+ -1, 33, -1, -1, -1, -1, -1, -1, -1, -1,
+ 374, 375, -1, -1, -1, -1, -1, 381, 382, 383,
+ -1, 262, 10, 264, 265, 266, 267, 268, 269, -1,
+ -1, -1, 273, 274, 275, 276, -1, 278, 279, -1,
+ 281, 282, -1, -1, -1, 33, -1, -1, -1, -1,
+ -1, 292, 293, -1, 295, 296, 297, 298, 299, -1,
+ -1, 302, 303, 304, -1, -1, -1, 308, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 318, -1, -1,
+ -1, -1, -1, -1, -1, 326, -1, -1, -1, 10,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 340,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 352, 33, -1, -1, -1, 357, -1, -1, -1,
+ -1, 362, -1, -1, -1, -1, 269, -1, -1, -1,
+ -1, -1, -1, 374, 375, 278, 279, -1, 281, 282,
+ -1, 382, 383, -1, -1, 288, 289, 290, -1, 292,
+ -1, -1, -1, -1, -1, 298, 299, -1, -1, 302,
+ 303, 304, 305, -1, -1, 308, -1, -1, 311, -1,
+ -1, -1, -1, -1, -1, 318, -1, -1, -1, -1,
+ 10, 324, -1, 326, -1, -1, -1, -1, -1, -1,
+ -1, -1, 335, 336, 337, 338, 339, 340, -1, -1,
+ -1, -1, -1, 33, -1, -1, -1, -1, -1, 352,
+ -1, -1, -1, -1, 357, -1, -1, -1, -1, 362,
+ 363, -1, 10, -1, -1, -1, -1, -1, -1, -1,
+ 262, 374, 375, -1, -1, 267, 268, 269, 381, 382,
+ 383, 273, 274, 275, 276, 33, 278, 279, -1, 281,
+ 282, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 292, -1, -1, -1, -1, -1, 298, 299, -1, -1,
+ 302, 303, 304, -1, 262, -1, 308, -1, -1, -1,
+ 268, -1, -1, -1, -1, -1, 318, -1, -1, -1,
+ 10, -1, -1, -1, 326, -1, -1, -1, -1, -1,
+ -1, 289, 290, 335, 336, 337, 338, 339, 340, -1,
+ -1, -1, -1, 33, 302, -1, -1, 305, -1, -1,
+ 352, -1, -1, 311, -1, 357, -1, -1, -1, -1,
+ 362, 363, -1, -1, -1, 123, 324, -1, -1, -1,
+ -1, 262, 374, 375, -1, -1, 267, 268, 269, -1,
+ 382, 383, 273, 274, 275, 276, -1, 278, 279, -1,
+ 281, 282, -1, -1, -1, -1, -1, -1, -1, 357,
+ -1, 292, -1, -1, -1, -1, -1, 298, 299, -1,
+ -1, 302, 303, 304, -1, -1, 374, 308, -1, -1,
+ -1, -1, -1, 381, -1, -1, -1, 318, -1, -1,
+ -1, 10, -1, -1, -1, 326, -1, -1, -1, -1,
+ -1, -1, -1, -1, 335, 336, 337, 338, 339, 340,
+ -1, -1, -1, -1, 33, -1, -1, -1, -1, -1,
+ -1, 352, 262, -1, -1, -1, 357, 267, 268, -1,
+ -1, 362, 363, 273, 274, 275, 276, -1, -1, -1,
+ -1, -1, -1, 374, 375, -1, -1, -1, 288, -1,
+ -1, 382, 383, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 261, 262, 263, -1, 265, 266, 267,
+ 268, 269, -1, -1, -1, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 292, 335, 336, 337, 338, 339,
+ 298, 299, 10, -1, 302, 303, 304, -1, -1, -1,
+ 308, -1, -1, -1, -1, -1, -1, 357, -1, -1,
+ 318, -1, -1, 363, -1, 33, -1, -1, 326, -1,
+ -1, -1, 262, -1, 374, 375, 266, 267, 268, 269,
+ -1, -1, 340, 273, 274, 275, 276, -1, 278, 279,
+ -1, 281, 282, -1, 352, -1, -1, -1, -1, 357,
+ -1, -1, 292, 293, 362, 295, 296, 297, 298, 299,
+ -1, -1, 302, 303, 304, -1, 374, 375, 308, -1,
+ -1, -1, -1, -1, 382, 383, -1, -1, 318, -1,
+ -1, -1, -1, -1, -1, -1, 326, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 340, -1, -1, 10, -1, 123, -1, -1, -1, -1,
+ -1, -1, 352, -1, -1, -1, -1, 357, -1, -1,
+ -1, -1, 362, -1, -1, -1, 33, -1, -1, -1,
+ -1, -1, -1, 262, 374, 375, -1, -1, 267, 268,
+ 269, -1, 382, 383, 273, 274, 275, 276, -1, 278,
+ 279, -1, 281, 282, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 292, 293, -1, 295, 296, 297, 298,
+ 299, -1, -1, 302, 303, 304, -1, -1, -1, 308,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 318,
+ -1, -1, -1, -1, -1, -1, -1, 326, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 340, -1, -1, 10, -1, 123, -1, -1, -1,
+ -1, -1, -1, 352, -1, -1, -1, -1, 357, -1,
+ -1, -1, -1, 362, -1, -1, -1, 33, -1, -1,
+ -1, -1, -1, -1, 262, 374, 375, 265, 266, 267,
+ 268, 269, -1, 382, 383, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 292, -1, -1, -1, -1, -1,
+ 298, 299, 10, -1, 302, 303, 304, -1, -1, -1,
+ 308, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 318, -1, -1, -1, -1, 33, -1, -1, 326, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 340, -1, -1, -1, -1, 123, -1, -1,
+ -1, -1, -1, -1, 352, -1, -1, -1, -1, 357,
+ -1, -1, -1, -1, 362, -1, -1, -1, -1, -1,
+ 10, -1, -1, -1, -1, 262, 374, 375, -1, 266,
+ 267, 268, 269, -1, 382, 383, 273, 274, 275, 276,
+ -1, 278, 279, 33, 281, 282, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 292, -1, -1, -1, -1,
+ -1, 298, 299, -1, -1, 302, 303, 304, -1, -1,
+ -1, 308, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 318, -1, -1, -1, -1, -1, -1, 10, 326,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 340, -1, -1, -1, -1, -1, -1,
+ -1, 33, -1, -1, -1, 352, -1, -1, -1, -1,
+ 357, -1, -1, -1, -1, 362, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 262, 374, 375, -1,
+ -1, 267, 268, 269, -1, 382, 383, 273, 274, 275,
+ 276, -1, 278, 279, -1, 281, 282, 10, -1, -1,
+ -1, -1, -1, -1, -1, -1, 292, -1, -1, -1,
+ -1, -1, 298, 299, -1, -1, 302, 303, 304, -1,
+ 33, -1, 308, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 318, -1, -1, -1, -1, -1, -1, -1,
+ 326, 123, -1, -1, 262, 10, -1, -1, -1, 267,
+ 268, 269, -1, -1, 340, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, 352, -1, 33, -1,
+ -1, 357, -1, -1, 292, -1, 362, -1, -1, -1,
+ 298, 299, -1, -1, 302, 303, 304, -1, 374, 375,
+ 308, -1, -1, -1, -1, -1, 382, 383, -1, -1,
+ 318, -1, -1, -1, -1, -1, -1, -1, 326, -1,
+ -1, -1, 262, -1, 10, -1, -1, 267, 268, 269,
+ -1, -1, 340, 273, 274, 275, 276, -1, 278, 279,
+ -1, 281, 282, -1, 352, -1, -1, 33, -1, 357,
+ -1, -1, 292, -1, 362, -1, -1, -1, 298, 299,
+ -1, -1, 302, 303, 304, -1, 374, 375, 308, -1,
+ -1, -1, -1, -1, 382, 383, 10, -1, 318, -1,
+ -1, -1, -1, -1, -1, -1, 326, -1, -1, -1,
+ 262, -1, -1, -1, -1, 267, 268, 269, -1, 33,
+ 340, 273, -1, -1, 276, -1, 278, 279, -1, 281,
+ 282, -1, 352, -1, -1, -1, -1, 357, -1, -1,
+ 292, -1, 362, -1, -1, -1, 298, 299, -1, -1,
+ 302, 303, 304, -1, 374, 375, 308, 123, -1, -1,
+ -1, -1, 382, 383, -1, -1, 318, -1, -1, -1,
+ -1, -1, -1, -1, 326, -1, -1, -1, -1, 262,
+ -1, -1, -1, -1, 267, 268, 269, -1, 340, -1,
+ 273, -1, -1, 276, 10, 278, 279, -1, 281, 282,
+ 352, -1, -1, -1, -1, 357, -1, -1, -1, 292,
+ 362, -1, -1, -1, -1, 298, 299, 33, -1, 302,
+ 303, 304, 374, 375, -1, 308, -1, 262, -1, -1,
+ 382, 383, 267, 268, -1, 318, -1, -1, 273, 274,
+ 275, 276, -1, 326, -1, 10, -1, -1, -1, -1,
+ -1, -1, -1, -1, 289, 290, -1, 340, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 302, 33, 352,
+ 305, -1, -1, -1, 357, -1, 311, -1, -1, 362,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 324,
+ -1, 374, 375, -1, -1, -1, 262, -1, -1, 382,
+ 383, 267, 268, 269, -1, -1, -1, 123, -1, -1,
+ 276, -1, 278, 279, -1, 281, 282, -1, -1, -1,
+ -1, -1, 357, -1, -1, -1, 292, -1, -1, -1,
+ -1, -1, 298, 299, 10, -1, 302, 303, 304, 374,
+ -1, -1, 308, -1, -1, -1, 381, -1, 262, -1,
+ -1, -1, 318, 267, 268, 269, -1, 33, -1, -1,
+ 326, -1, 276, -1, 278, 279, -1, 281, 282, -1,
+ -1, -1, -1, -1, 340, -1, -1, -1, 292, -1,
+ 10, -1, -1, -1, 298, 299, 352, -1, 302, 303,
+ 304, 357, -1, -1, 308, -1, 362, -1, -1, -1,
+ -1, -1, -1, 33, 318, -1, -1, -1, 374, 375,
+ -1, -1, 326, -1, -1, -1, 382, 383, -1, -1,
+ -1, -1, -1, -1, -1, -1, 340, -1, -1, -1,
+ -1, -1, 10, -1, -1, -1, -1, -1, 352, -1,
+ -1, -1, -1, 357, -1, -1, 262, 123, 362, -1,
+ -1, -1, 268, 269, -1, 33, -1, -1, -1, -1,
+ 374, 375, 278, 279, -1, 281, 282, -1, 382, 383,
+ -1, -1, -1, -1, -1, -1, 292, -1, 10, -1,
+ -1, -1, 298, 299, -1, -1, 302, 303, 304, -1,
+ -1, -1, 308, 123, -1, -1, -1, 262, -1, -1,
+ -1, 33, 318, 268, 269, -1, -1, -1, -1, -1,
+ 326, -1, -1, 278, 279, -1, 281, 282, -1, -1,
+ -1, -1, -1, -1, 340, -1, -1, 292, -1, -1,
+ -1, -1, -1, 298, 299, -1, 352, 302, 303, 304,
+ -1, 357, -1, 308, -1, 123, 362, -1, -1, -1,
+ -1, -1, -1, 318, -1, -1, -1, -1, 374, 375,
+ -1, 326, -1, -1, -1, -1, 382, 383, -1, -1,
+ -1, -1, -1, -1, -1, 340, -1, -1, -1, -1,
+ -1, 10, -1, -1, -1, -1, -1, 352, -1, -1,
+ -1, -1, 357, 269, -1, -1, -1, 362, -1, -1,
+ -1, 10, 278, 279, 33, 281, 282, -1, -1, 374,
+ 375, -1, -1, -1, -1, -1, 292, 382, 383, -1,
+ -1, -1, 298, 299, 33, -1, 302, 303, 304, -1,
+ -1, -1, 308, -1, 10, -1, -1, -1, -1, 269,
+ -1, -1, 318, -1, -1, -1, -1, -1, 278, 279,
+ 326, 281, 282, -1, -1, -1, -1, 33, -1, -1,
+ -1, -1, 292, -1, 340, -1, 10, -1, 298, 299,
+ -1, -1, 302, 303, 304, -1, 352, -1, 308, -1,
+ -1, 357, -1, -1, -1, -1, 362, -1, 318, 33,
+ -1, 269, -1, -1, -1, -1, 326, -1, 374, 375,
+ 278, 279, -1, 281, 282, -1, 382, 383, -1, -1,
+ 340, -1, 10, -1, 292, -1, -1, -1, -1, 10,
+ 298, 299, 352, -1, 302, 303, 304, 357, -1, -1,
+ 308, -1, 362, -1, -1, 33, -1, 269, -1, -1,
+ 318, -1, 33, -1, 374, 375, 278, 279, 326, 281,
+ 282, -1, 382, 383, -1, -1, -1, -1, -1, -1,
+ 292, -1, 340, -1, -1, -1, 298, 299, -1, -1,
+ 302, 303, 304, -1, 352, -1, 308, -1, -1, 357,
+ -1, -1, -1, -1, 362, -1, 318, -1, -1, -1,
+ -1, -1, -1, -1, 326, -1, 374, 375, -1, -1,
+ -1, -1, -1, -1, 382, 383, -1, -1, 340, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 352, -1, 33, -1, -1, 357, -1, -1, -1, -1,
+ 362, -1, -1, 262, -1, 264, 265, 266, 267, 268,
+ -1, -1, 374, 375, 273, 274, 275, 276, -1, -1,
+ 382, 383, -1, 262, -1, -1, -1, 266, 267, 268,
+ 289, 290, -1, -1, 273, 274, 275, 276, -1, -1,
+ -1, -1, -1, 302, -1, -1, 305, -1, -1, -1,
+ 289, 290, 311, -1, -1, -1, 262, -1, -1, -1,
+ 266, 267, 268, 302, -1, 324, 305, 273, 274, 275,
+ 276, -1, 311, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 288, -1, -1, 324, -1, -1, 262, -1,
+ -1, -1, 266, 267, 268, -1, -1, -1, 357, 273,
+ 274, 275, 276, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 288, 374, -1, -1, 357, -1,
+ -1, -1, 381, -1, -1, -1, -1, -1, -1, 335,
+ 336, 337, 338, 339, 262, 374, -1, -1, -1, 267,
+ 268, 262, 381, -1, -1, 273, 267, 268, 276, -1,
+ -1, 357, -1, -1, -1, 276, -1, 363, -1, -1,
+ 288, 335, 336, 337, 338, 339, -1, 288, 374, 375,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 357, -1, -1, -1, -1, -1, 363,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 374, 375, -1, -1, -1, -1, -1, 335, 336, 337,
+ 338, 339, -1, -1, 335, 336, 337, 338, 339, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 269, 357,
+ -1, -1, -1, -1, -1, 363, 357, 278, 279, -1,
+ 281, 282, 363, -1, -1, -1, 374, 375, -1, -1,
+ -1, 292, -1, 374, 375, -1, -1, 298, 299, -1,
+ -1, 302, 303, 304, -1, -1, -1, 308, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 318, -1, -1,
+ -1, -1, -1, -1, -1, 326, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 340,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 352, -1, -1, -1, -1, 357, -1, -1, -1,
+ -1, 362, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 375, -1, -1, -1, -1, -1,
+ -1, 382, 383,
+};
+#define YYFINAL 2
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 386
+#define YYUNDFTOKEN 557
+#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? YYUNDFTOKEN : (a))
+#if YYDEBUG
+static const char *const pfctlyname[] = {
+
+"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,"'!'",0,0,0,0,0,0,"'('","')'",0,0,"','","'-'",0,"'/'",0,0,0,0,0,0,0,0,0,0,0,
+0,"'<'","'='","'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,"PASS","BLOCK","SCRUB","RETURN","IN","OS","OUT","LOG","QUICK",
+"ON","FROM","TO","FLAGS","RETURNRST","RETURNICMP","RETURNICMP6","PROTO","INET",
+"INET6","ALL","ANY","ICMPTYPE","ICMP6TYPE","CODE","KEEP","MODULATE","STATE",
+"PORT","RDR","NAT","BINAT","ARROW","NODF","MINTTL","ERROR","ALLOWOPTS",
+"FASTROUTE","FILENAME","ROUTETO","DUPTO","REPLYTO","NO","LABEL","NOROUTE",
+"URPFFAILED","FRAGMENT","USER","GROUP","MAXMSS","MAXIMUM","TTL","TOS","DROP",
+"TABLE","REASSEMBLE","FRAGDROP","FRAGCROP","ANCHOR","NATANCHOR","RDRANCHOR",
+"BINATANCHOR","SET","OPTIMIZATION","TIMEOUT","LIMIT","LOGINTERFACE",
+"BLOCKPOLICY","RANDOMID","REQUIREORDER","SYNPROXY","FINGERPRINTS","NOSYNC",
+"DEBUG","SKIP","HOSTID","ANTISPOOF","FOR","INCLUDE","BITMASK","RANDOM",
+"SOURCEHASH","ROUNDROBIN","STATICPORT","PROBABILITY","ALTQ","CBQ","CODEL",
+"PRIQ","HFSC","FAIRQ","BANDWIDTH","TBRSIZE","LINKSHARE","REALTIME","UPPERLIMIT",
+"QUEUE","PRIORITY","QLIMIT","HOGS","BUCKETS","RTABLE","TARGET","INTERVAL",
+"LOAD","RULESET_OPTIMIZATION","PRIO","STICKYADDRESS","MAXSRCSTATES",
+"MAXSRCNODES","SOURCETRACK","GLOBAL","RULE","MAXSRCCONN","MAXSRCCONNRATE",
+"OVERLOAD","FLUSH","SLOPPY","TAGGED","TAG","IFBOUND","FLOATING","STATEPOLICY",
+"STATEDEFAULTS","ROUTE","SETTOS","DIVERTTO","DIVERTREPLY","STRING","NUMBER",
+"PORTBINARY",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"illegal-symbol",
+};
+static const char *const pfctlyrule[] = {
+"$accept : ruleset",
+"ruleset :",
+"ruleset : ruleset include '\\n'",
+"ruleset : ruleset '\\n'",
+"ruleset : ruleset option '\\n'",
+"ruleset : ruleset scrubrule '\\n'",
+"ruleset : ruleset natrule '\\n'",
+"ruleset : ruleset binatrule '\\n'",
+"ruleset : ruleset pfrule '\\n'",
+"ruleset : ruleset anchorrule '\\n'",
+"ruleset : ruleset loadrule '\\n'",
+"ruleset : ruleset altqif '\\n'",
+"ruleset : ruleset queuespec '\\n'",
+"ruleset : ruleset varset '\\n'",
+"ruleset : ruleset antispoof '\\n'",
+"ruleset : ruleset tabledef '\\n'",
+"ruleset : '{' fakeanchor '}' '\\n'",
+"ruleset : ruleset error '\\n'",
+"include : INCLUDE STRING",
+"fakeanchor : fakeanchor '\\n'",
+"fakeanchor : fakeanchor anchorrule '\\n'",
+"fakeanchor : fakeanchor binatrule '\\n'",
+"fakeanchor : fakeanchor natrule '\\n'",
+"fakeanchor : fakeanchor pfrule '\\n'",
+"fakeanchor : fakeanchor error '\\n'",
+"optimizer : string",
+"option : SET OPTIMIZATION STRING",
+"option : SET RULESET_OPTIMIZATION optimizer",
+"option : SET TIMEOUT timeout_spec",
+"option : SET TIMEOUT '{' optnl timeout_list '}'",
+"option : SET LIMIT limit_spec",
+"option : SET LIMIT '{' optnl limit_list '}'",
+"option : SET LOGINTERFACE stringall",
+"option : SET HOSTID number",
+"option : SET BLOCKPOLICY DROP",
+"option : SET BLOCKPOLICY RETURN",
+"option : SET REQUIREORDER yesno",
+"option : SET FINGERPRINTS STRING",
+"option : SET STATEPOLICY statelock",
+"option : SET DEBUG STRING",
+"option : SET SKIP interface",
+"option : SET STATEDEFAULTS state_opt_list",
+"stringall : STRING",
+"stringall : ALL",
+"string : STRING string",
+"string : STRING",
+"varstring : numberstring varstring",
+"varstring : numberstring",
+"numberstring : NUMBER",
+"numberstring : STRING",
+"varset : STRING '=' varstring",
+"anchorname : STRING",
+"anchorname :",
+"pfa_anchorlist :",
+"pfa_anchorlist : pfa_anchorlist '\\n'",
+"pfa_anchorlist : pfa_anchorlist pfrule '\\n'",
+"pfa_anchorlist : pfa_anchorlist anchorrule '\\n'",
+"$$1 :",
+"pfa_anchor : '{' $$1 '\\n' pfa_anchorlist '}'",
+"pfa_anchor :",
+"anchorrule : ANCHOR anchorname dir quick interface af proto fromto filter_opts pfa_anchor",
+"anchorrule : NATANCHOR string interface af proto fromto rtable",
+"anchorrule : RDRANCHOR string interface af proto fromto rtable",
+"anchorrule : BINATANCHOR string interface af proto fromto rtable",
+"loadrule : LOAD ANCHOR string FROM string",
+"scrubaction : no SCRUB",
+"scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts",
+"$$2 :",
+"scrub_opts : $$2 scrub_opts_l",
+"scrub_opts :",
+"scrub_opts_l : scrub_opts_l scrub_opt",
+"scrub_opts_l : scrub_opt",
+"scrub_opt : NODF",
+"scrub_opt : MINTTL NUMBER",
+"scrub_opt : MAXMSS NUMBER",
+"scrub_opt : SETTOS tos",
+"scrub_opt : fragcache",
+"scrub_opt : REASSEMBLE STRING",
+"scrub_opt : RANDOMID",
+"scrub_opt : RTABLE NUMBER",
+"scrub_opt : not TAGGED string",
+"fragcache : FRAGMENT REASSEMBLE",
+"fragcache : FRAGMENT FRAGCROP",
+"fragcache : FRAGMENT FRAGDROP",
+"antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts",
+"antispoof_ifspc : FOR antispoof_if",
+"antispoof_ifspc : FOR '{' optnl antispoof_iflst '}'",
+"antispoof_iflst : antispoof_if optnl",
+"antispoof_iflst : antispoof_iflst comma antispoof_if optnl",
+"antispoof_if : if_item",
+"antispoof_if : '(' if_item ')'",
+"$$3 :",
+"antispoof_opts : $$3 antispoof_opts_l",
+"antispoof_opts :",
+"antispoof_opts_l : antispoof_opts_l antispoof_opt",
+"antispoof_opts_l : antispoof_opt",
+"antispoof_opt : label",
+"antispoof_opt : RTABLE NUMBER",
+"not : '!'",
+"not :",
+"tabledef : TABLE '<' STRING '>' table_opts",
+"$$4 :",
+"table_opts : $$4 table_opts_l",
+"table_opts :",
+"table_opts_l : table_opts_l table_opt",
+"table_opts_l : table_opt",
+"table_opt : STRING",
+"table_opt : '{' optnl '}'",
+"table_opt : '{' optnl host_list '}'",
+"table_opt : FILENAME STRING",
+"altqif : ALTQ interface queue_opts QUEUE qassign",
+"queuespec : QUEUE STRING interface queue_opts qassign",
+"$$5 :",
+"queue_opts : $$5 queue_opts_l",
+"queue_opts :",
+"queue_opts_l : queue_opts_l queue_opt",
+"queue_opts_l : queue_opt",
+"queue_opt : BANDWIDTH bandwidth",
+"queue_opt : PRIORITY NUMBER",
+"queue_opt : QLIMIT NUMBER",
+"queue_opt : scheduler",
+"queue_opt : TBRSIZE NUMBER",
+"bandwidth : STRING",
+"bandwidth : NUMBER",
+"scheduler : CBQ",
+"scheduler : CBQ '(' cbqflags_list ')'",
+"scheduler : PRIQ",
+"scheduler : PRIQ '(' priqflags_list ')'",
+"scheduler : HFSC",
+"scheduler : HFSC '(' hfsc_opts ')'",
+"scheduler : FAIRQ",
+"scheduler : FAIRQ '(' fairq_opts ')'",
+"scheduler : CODEL",
+"scheduler : CODEL '(' codel_opts ')'",
+"cbqflags_list : cbqflags_item",
+"cbqflags_list : cbqflags_list comma cbqflags_item",
+"cbqflags_item : STRING",
+"priqflags_list : priqflags_item",
+"priqflags_list : priqflags_list comma priqflags_item",
+"priqflags_item : STRING",
+"$$6 :",
+"hfsc_opts : $$6 hfscopts_list",
+"hfscopts_list : hfscopts_item",
+"hfscopts_list : hfscopts_list comma hfscopts_item",
+"hfscopts_item : LINKSHARE bandwidth",
+"hfscopts_item : LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'",
+"hfscopts_item : REALTIME bandwidth",
+"hfscopts_item : REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'",
+"hfscopts_item : UPPERLIMIT bandwidth",
+"hfscopts_item : UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'",
+"hfscopts_item : STRING",
+"$$7 :",
+"fairq_opts : $$7 fairqopts_list",
+"fairqopts_list : fairqopts_item",
+"fairqopts_list : fairqopts_list comma fairqopts_item",
+"fairqopts_item : LINKSHARE bandwidth",
+"fairqopts_item : LINKSHARE '(' bandwidth number bandwidth ')'",
+"fairqopts_item : HOGS bandwidth",
+"fairqopts_item : BUCKETS number",
+"fairqopts_item : STRING",
+"$$8 :",
+"codel_opts : $$8 codelopts_list",
+"codelopts_list : codelopts_item",
+"codelopts_list : codelopts_list comma codelopts_item",
+"codelopts_item : INTERVAL number",
+"codelopts_item : TARGET number",
+"codelopts_item : STRING",
+"qassign :",
+"qassign : qassign_item",
+"qassign : '{' optnl qassign_list '}'",
+"qassign_list : qassign_item optnl",
+"qassign_list : qassign_list comma qassign_item optnl",
+"qassign_item : STRING",
+"pfrule : action dir logquick interface route af proto fromto filter_opts",
+"$$9 :",
+"filter_opts : $$9 filter_opts_l",
+"filter_opts :",
+"filter_opts_l : filter_opts_l filter_opt",
+"filter_opts_l : filter_opt",
+"filter_opt : USER uids",
+"filter_opt : GROUP gids",
+"filter_opt : flags",
+"filter_opt : icmpspec",
+"filter_opt : PRIO NUMBER",
+"filter_opt : TOS tos",
+"filter_opt : keep",
+"filter_opt : FRAGMENT",
+"filter_opt : ALLOWOPTS",
+"filter_opt : label",
+"filter_opt : qname",
+"filter_opt : TAG string",
+"filter_opt : not TAGGED string",
+"filter_opt : PROBABILITY probability",
+"filter_opt : RTABLE NUMBER",
+"filter_opt : DIVERTTO portplain",
+"filter_opt : DIVERTTO STRING PORT portplain",
+"filter_opt : DIVERTREPLY",
+"filter_opt : filter_sets",
+"filter_sets : SET '(' filter_sets_l ')'",
+"filter_sets : SET filter_set",
+"filter_sets_l : filter_sets_l comma filter_set",
+"filter_sets_l : filter_set",
+"filter_set : prio",
+"prio : PRIO NUMBER",
+"prio : PRIO '(' NUMBER comma NUMBER ')'",
+"probability : STRING",
+"probability : NUMBER",
+"action : PASS",
+"action : BLOCK blockspec",
+"blockspec :",
+"blockspec : DROP",
+"blockspec : RETURNRST",
+"blockspec : RETURNRST '(' TTL NUMBER ')'",
+"blockspec : RETURNICMP",
+"blockspec : RETURNICMP6",
+"blockspec : RETURNICMP '(' reticmpspec ')'",
+"blockspec : RETURNICMP6 '(' reticmp6spec ')'",
+"blockspec : RETURNICMP '(' reticmpspec comma reticmp6spec ')'",
+"blockspec : RETURN",
+"reticmpspec : STRING",
+"reticmpspec : NUMBER",
+"reticmp6spec : STRING",
+"reticmp6spec : NUMBER",
+"dir :",
+"dir : IN",
+"dir : OUT",
+"quick :",
+"quick : QUICK",
+"logquick :",
+"logquick : log",
+"logquick : QUICK",
+"logquick : log QUICK",
+"logquick : QUICK log",
+"log : LOG",
+"log : LOG '(' logopts ')'",
+"logopts : logopt",
+"logopts : logopts comma logopt",
+"logopt : ALL",
+"logopt : USER",
+"logopt : GROUP",
+"logopt : TO string",
+"interface :",
+"interface : ON if_item_not",
+"interface : ON '{' optnl if_list '}'",
+"if_list : if_item_not optnl",
+"if_list : if_list comma if_item_not optnl",
+"if_item_not : not if_item",
+"if_item : STRING",
+"af :",
+"af : INET",
+"af : INET6",
+"proto :",
+"proto : PROTO proto_item",
+"proto : PROTO '{' optnl proto_list '}'",
+"proto_list : proto_item optnl",
+"proto_list : proto_list comma proto_item optnl",
+"proto_item : protoval",
+"protoval : STRING",
+"protoval : NUMBER",
+"fromto : ALL",
+"fromto : from os to",
+"os :",
+"os : OS xos",
+"os : OS '{' optnl os_list '}'",
+"xos : STRING",
+"os_list : xos optnl",
+"os_list : os_list comma xos optnl",
+"from :",
+"from : FROM ipportspec",
+"to :",
+"to : TO ipportspec",
+"ipportspec : ipspec",
+"ipportspec : ipspec PORT portspec",
+"ipportspec : PORT portspec",
+"optnl : '\\n' optnl",
+"optnl :",
+"ipspec : ANY",
+"ipspec : xhost",
+"ipspec : '{' optnl host_list '}'",
+"toipspec : TO ipspec",
+"toipspec :",
+"host_list : ipspec optnl",
+"host_list : host_list comma ipspec optnl",
+"xhost : not host",
+"xhost : not NOROUTE",
+"xhost : not URPFFAILED",
+"host : STRING",
+"host : STRING '-' STRING",
+"host : STRING '/' NUMBER",
+"host : NUMBER '/' NUMBER",
+"host : dynaddr",
+"host : dynaddr '/' NUMBER",
+"host : '<' STRING '>'",
+"number : NUMBER",
+"number : STRING",
+"dynaddr : '(' STRING ')'",
+"portspec : port_item",
+"portspec : '{' optnl port_list '}'",
+"port_list : port_item optnl",
+"port_list : port_list comma port_item optnl",
+"port_item : portrange",
+"port_item : unaryop portrange",
+"port_item : portrange PORTBINARY portrange",
+"portplain : numberstring",
+"portrange : numberstring",
+"uids : uid_item",
+"uids : '{' optnl uid_list '}'",
+"uid_list : uid_item optnl",
+"uid_list : uid_list comma uid_item optnl",
+"uid_item : uid",
+"uid_item : unaryop uid",
+"uid_item : uid PORTBINARY uid",
+"uid : STRING",
+"uid : NUMBER",
+"gids : gid_item",
+"gids : '{' optnl gid_list '}'",
+"gid_list : gid_item optnl",
+"gid_list : gid_list comma gid_item optnl",
+"gid_item : gid",
+"gid_item : unaryop gid",
+"gid_item : gid PORTBINARY gid",
+"gid : STRING",
+"gid : NUMBER",
+"flag : STRING",
+"flags : FLAGS flag '/' flag",
+"flags : FLAGS '/' flag",
+"flags : FLAGS ANY",
+"icmpspec : ICMPTYPE icmp_item",
+"icmpspec : ICMPTYPE '{' optnl icmp_list '}'",
+"icmpspec : ICMP6TYPE icmp6_item",
+"icmpspec : ICMP6TYPE '{' optnl icmp6_list '}'",
+"icmp_list : icmp_item optnl",
+"icmp_list : icmp_list comma icmp_item optnl",
+"icmp6_list : icmp6_item optnl",
+"icmp6_list : icmp6_list comma icmp6_item optnl",
+"icmp_item : icmptype",
+"icmp_item : icmptype CODE STRING",
+"icmp_item : icmptype CODE NUMBER",
+"icmp6_item : icmp6type",
+"icmp6_item : icmp6type CODE STRING",
+"icmp6_item : icmp6type CODE NUMBER",
+"icmptype : STRING",
+"icmptype : NUMBER",
+"icmp6type : STRING",
+"icmp6type : NUMBER",
+"tos : STRING",
+"tos : NUMBER",
+"sourcetrack : SOURCETRACK",
+"sourcetrack : SOURCETRACK GLOBAL",
+"sourcetrack : SOURCETRACK RULE",
+"statelock : IFBOUND",
+"statelock : FLOATING",
+"keep : NO STATE",
+"keep : KEEP STATE state_opt_spec",
+"keep : MODULATE STATE state_opt_spec",
+"keep : SYNPROXY STATE state_opt_spec",
+"flush :",
+"flush : FLUSH",
+"flush : FLUSH GLOBAL",
+"state_opt_spec : '(' state_opt_list ')'",
+"state_opt_spec :",
+"state_opt_list : state_opt_item",
+"state_opt_list : state_opt_list comma state_opt_item",
+"state_opt_item : MAXIMUM NUMBER",
+"state_opt_item : NOSYNC",
+"state_opt_item : MAXSRCSTATES NUMBER",
+"state_opt_item : MAXSRCCONN NUMBER",
+"state_opt_item : MAXSRCCONNRATE NUMBER '/' NUMBER",
+"state_opt_item : OVERLOAD '<' STRING '>' flush",
+"state_opt_item : MAXSRCNODES NUMBER",
+"state_opt_item : sourcetrack",
+"state_opt_item : statelock",
+"state_opt_item : SLOPPY",
+"state_opt_item : STRING NUMBER",
+"label : LABEL STRING",
+"qname : QUEUE STRING",
+"qname : QUEUE '(' STRING ')'",
+"qname : QUEUE '(' STRING comma STRING ')'",
+"no :",
+"no : NO",
+"portstar : numberstring",
+"redirspec : host",
+"redirspec : '{' optnl redir_host_list '}'",
+"redir_host_list : host optnl",
+"redir_host_list : redir_host_list comma host optnl",
+"redirpool :",
+"redirpool : ARROW redirspec",
+"redirpool : ARROW redirspec PORT portstar",
+"hashkey :",
+"hashkey : string",
+"$$10 :",
+"pool_opts : $$10 pool_opts_l",
+"pool_opts :",
+"pool_opts_l : pool_opts_l pool_opt",
+"pool_opts_l : pool_opt",
+"pool_opt : BITMASK",
+"pool_opt : RANDOM",
+"pool_opt : SOURCEHASH hashkey",
+"pool_opt : ROUNDROBIN",
+"pool_opt : STATICPORT",
+"pool_opt : STICKYADDRESS",
+"redirection :",
+"redirection : ARROW host",
+"redirection : ARROW host PORT portstar",
+"natpasslog :",
+"natpasslog : PASS",
+"natpasslog : PASS log",
+"natpasslog : log",
+"nataction : no NAT natpasslog",
+"nataction : no RDR natpasslog",
+"natrule : nataction interface af proto fromto tag tagged rtable redirpool pool_opts",
+"binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag tagged rtable redirection",
+"tag :",
+"tag : TAG STRING",
+"tagged :",
+"tagged : not TAGGED string",
+"rtable :",
+"rtable : RTABLE NUMBER",
+"route_host : STRING",
+"route_host : '(' STRING host ')'",
+"route_host_list : route_host optnl",
+"route_host_list : route_host_list comma route_host optnl",
+"routespec : route_host",
+"routespec : '{' optnl route_host_list '}'",
+"route :",
+"route : FASTROUTE",
+"route : ROUTETO routespec pool_opts",
+"route : REPLYTO routespec pool_opts",
+"route : DUPTO routespec pool_opts",
+"timeout_spec : STRING NUMBER",
+"timeout_spec : INTERVAL NUMBER",
+"timeout_list : timeout_list comma timeout_spec optnl",
+"timeout_list : timeout_spec optnl",
+"limit_spec : STRING NUMBER",
+"limit_list : limit_list comma limit_spec optnl",
+"limit_list : limit_spec optnl",
+"comma : ','",
+"comma :",
+"yesno : NO",
+"yesno : STRING",
+"unaryop : '='",
+"unaryop : '!' '='",
+"unaryop : '<' '='",
+"unaryop : '<'",
+"unaryop : '>' '='",
+"unaryop : '>'",
+
+};
+#endif
+
+int yydebug;
+int yynerrs;
+
+int yyerrflag;
+int yychar;
+YYSTYPE yyval;
+YYSTYPE yylval;
+
+/* define the initial stack-sizes */
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH 10000
+#endif
+#endif
+
+#define YYINITSTACKSIZE 200
+
+typedef struct {
+ unsigned stacksize;
+ YYINT *s_base;
+ YYINT *s_mark;
+ YYINT *s_last;
+ YYSTYPE *l_base;
+ YYSTYPE *l_mark;
+} YYSTACKDATA;
+/* variables for the parser stack */
+static YYSTACKDATA yystack;
+#line 4545 "../../freebsd/sbin/pfctl/parse.y"
+#ifdef __rtems__
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack);
+#endif /* __rtems__ */
+
+int
+yyerror(const char *fmt, ...)
+{
+ va_list ap;
+
+ file->errors++;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ return (0);
+}
+
+int
+disallow_table(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_TABLE) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_urpf_failed(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_URPFFAILED) {
+ yyerror(fmt);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_alias(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (DYNIF_MULTIADDR(h->addr)) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+rule_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ switch (r->action) {
+ case PF_PASS:
+ case PF_DROP:
+ case PF_SCRUB:
+ case PF_NOSCRUB:
+ problems = filter_consistent(r, anchor_call);
+ break;
+ case PF_NAT:
+ case PF_NONAT:
+ problems = nat_consistent(r);
+ break;
+ case PF_RDR:
+ case PF_NORDR:
+ problems = rdr_consistent(r);
+ break;
+ case PF_BINAT:
+ case PF_NOBINAT:
+ default:
+ break;
+ }
+ return (problems);
+}
+
+int
+filter_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
+ (r->src.port_op || r->dst.port_op)) {
+ yyerror("port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
+ (r->type || r->code)) {
+ yyerror("icmp-type/code only applies to icmp");
+ problems++;
+ }
+ if (!r->af && (r->type || r->code)) {
+ yyerror("must indicate address family with icmp-type/code");
+ problems++;
+ }
+ if (r->overload_tblname[0] &&
+ r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
+ yyerror("'overload' requires 'max-src-conn' "
+ "or 'max-src-conn-rate'");
+ problems++;
+ }
+ if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
+ (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
+ yyerror("proto %s doesn't match address family %s",
+ r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
+ r->af == AF_INET ? "inet" : "inet6");
+ problems++;
+ }
+ if (r->allow_opts && r->action != PF_PASS) {
+ yyerror("allow-opts can only be specified for pass rules");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
+ r->dst.port_op || r->flagset || r->type || r->code)) {
+ yyerror("fragments can be filtered only on IP header fields");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
+ yyerror("return-rst can only be applied to TCP rules");
+ problems++;
+ }
+ if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
+ yyerror("max-src-nodes requires 'source-track rule'");
+ problems++;
+ }
+ if (r->action == PF_DROP && r->keep_state) {
+ yyerror("keep state on block rules doesn't make sense");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_STATESLOPPY &&
+ (r->keep_state == PF_STATE_MODULATE ||
+ r->keep_state == PF_STATE_SYNPROXY)) {
+ yyerror("sloppy state matching cannot be used with "
+ "synproxy state or modulate state");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+nat_consistent(struct pf_rule *r)
+{
+ return (0); /* yeah! */
+}
+
+int
+rdr_consistent(struct pf_rule *r)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
+ if (r->src.port_op) {
+ yyerror("src port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->dst.port_op) {
+ yyerror("dst port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->rpool.proxy_port[0]) {
+ yyerror("rpool port only applies to tcp/udp");
+ problems++;
+ }
+ }
+ if (r->dst.port_op &&
+ r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
+ yyerror("invalid port operator for rdr destination port");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+process_tabledef(char *name, struct table_opts *opts)
+{
+ struct pfr_buffer ab;
+ struct node_tinit *ti;
+
+ bzero(&ab, sizeof(ab));
+ ab.pfrb_type = PFRB_ADDRS;
+ SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
+ if (ti->file)
+ if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
+ if (errno)
+ yyerror("cannot load \"%s\": %s",
+ ti->file, strerror(errno));
+ else
+ yyerror("file \"%s\" contains bad data",
+ ti->file);
+ goto _error;
+ }
+ if (ti->host)
+ if (append_addr_host(&ab, ti->host, 0, 0)) {
+ yyerror("cannot create address buffer: %s",
+ strerror(errno));
+ goto _error;
+ }
+ }
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(name, opts->flags, opts->init_addr,
+ &opts->init_nodes);
+ if (!(pf->opts & PF_OPT_NOACTION) &&
+ pfctl_define_table(name, opts->flags, opts->init_addr,
+ pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
+ yyerror("cannot define table %s: %s", name,
+ pfr_strerror(errno));
+ goto _error;
+ }
+ pf->tdirty = 1;
+ pfr_buf_clear(&ab);
+ return (0);
+_error:
+ pfr_buf_clear(&ab);
+ return (-1);
+}
+
+struct keywords {
+ const char *k_name;
+ int k_val;
+};
+
+/* macro gore, but you should've seen the prior indentation nightmare... */
+
+#define FREE_LIST(T,r) \
+ do { \
+ T *p, *node = r; \
+ while (node != NULL) { \
+ p = node; \
+ node = node->next; \
+ free(p); \
+ } \
+ } while (0)
+
+#define LOOP_THROUGH(T,n,r,C) \
+ do { \
+ T *n; \
+ if (r == NULL) { \
+ r = calloc(1, sizeof(T)); \
+ if (r == NULL) \
+ err(1, "LOOP: calloc"); \
+ r->next = NULL; \
+ } \
+ n = r; \
+ while (n != NULL) { \
+ do { \
+ C; \
+ } while (0); \
+ n = n->next; \
+ } \
+ } while (0)
+
+void
+expand_label_str(char *label, size_t len, const char *srch, const char *repl)
+{
+ char *tmp;
+ char *p, *q;
+
+ if ((tmp = calloc(1, len)) == NULL)
+ err(1, "expand_label_str: calloc");
+ p = q = label;
+ while ((q = strstr(p, srch)) != NULL) {
+ *q = '\0';
+ if ((strlcat(tmp, p, len) >= len) ||
+ (strlcat(tmp, repl, len) >= len))
+ errx(1, "expand_label: label too long");
+ q += strlen(srch);
+ p = q;
+ }
+ if (strlcat(tmp, p, len) >= len)
+ errx(1, "expand_label: label too long");
+ strlcpy(label, tmp, len); /* always fits */
+ free(tmp);
+}
+
+void
+expand_label_if(const char *name, char *label, size_t len, const char *ifname)
+{
+ if (strstr(label, name) != NULL) {
+ if (!*ifname)
+ expand_label_str(label, len, name, "any");
+ else
+ expand_label_str(label, len, name, ifname);
+ }
+}
+
+void
+expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
+ struct node_host *h)
+{
+ char tmp[64], tmp_not[66];
+
+ if (strstr(label, name) != NULL) {
+ switch (h->addr.type) {
+ case PF_ADDR_DYNIFTL:
+ snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
+ break;
+ case PF_ADDR_TABLE:
+ snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
+ break;
+ case PF_ADDR_NOROUTE:
+ snprintf(tmp, sizeof(tmp), "no-route");
+ break;
+ case PF_ADDR_URPFFAILED:
+ snprintf(tmp, sizeof(tmp), "urpf-failed");
+ break;
+ case PF_ADDR_ADDRMASK:
+ if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
+ PF_AZERO(&h->addr.v.a.mask, af)))
+ snprintf(tmp, sizeof(tmp), "any");
+ else {
+ char a[48];
+ int bits;
+
+ if (inet_ntop(af, &h->addr.v.a.addr, a,
+ sizeof(a)) == NULL)
+ snprintf(tmp, sizeof(tmp), "?");
+ else {
+ bits = unmask(&h->addr.v.a.mask, af);
+ if ((af == AF_INET && bits < 32) ||
+ (af == AF_INET6 && bits < 128))
+ snprintf(tmp, sizeof(tmp),
+ "%s/%d", a, bits);
+ else
+ snprintf(tmp, sizeof(tmp),
+ "%s", a);
+ }
+ }
+ break;
+ default:
+ snprintf(tmp, sizeof(tmp), "?");
+ break;
+ }
+
+ if (h->not) {
+ snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
+ expand_label_str(label, len, name, tmp_not);
+ } else
+ expand_label_str(label, len, name, tmp);
+ }
+}
+
+void
+expand_label_port(const char *name, char *label, size_t len,
+ struct node_port *port)
+{
+ char a1[6], a2[6], op[13] = "";
+
+ if (strstr(label, name) != NULL) {
+ snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
+ snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
+ if (!port->op)
+ ;
+ else if (port->op == PF_OP_IRG)
+ snprintf(op, sizeof(op), "%s><%s", a1, a2);
+ else if (port->op == PF_OP_XRG)
+ snprintf(op, sizeof(op), "%s<>%s", a1, a2);
+ else if (port->op == PF_OP_EQ)
+ snprintf(op, sizeof(op), "%s", a1);
+ else if (port->op == PF_OP_NE)
+ snprintf(op, sizeof(op), "!=%s", a1);
+ else if (port->op == PF_OP_LT)
+ snprintf(op, sizeof(op), "<%s", a1);
+ else if (port->op == PF_OP_LE)
+ snprintf(op, sizeof(op), "<=%s", a1);
+ else if (port->op == PF_OP_GT)
+ snprintf(op, sizeof(op), ">%s", a1);
+ else if (port->op == PF_OP_GE)
+ snprintf(op, sizeof(op), ">=%s", a1);
+ expand_label_str(label, len, name, op);
+ }
+}
+
+void
+expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
+{
+ struct protoent *pe;
+ char n[4];
+
+ if (strstr(label, name) != NULL) {
+ pe = getprotobynumber(proto);
+ if (pe != NULL)
+ expand_label_str(label, len, name, pe->p_name);
+ else {
+ snprintf(n, sizeof(n), "%u", proto);
+ expand_label_str(label, len, name, n);
+ }
+ }
+}
+
+void
+expand_label_nr(const char *name, char *label, size_t len)
+{
+ char n[11];
+
+ if (strstr(label, name) != NULL) {
+ snprintf(n, sizeof(n), "%u", pf->anchor->match);
+ expand_label_str(label, len, name, n);
+ }
+}
+
+void
+expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
+ struct node_host *src_host, struct node_port *src_port,
+ struct node_host *dst_host, struct node_port *dst_port,
+ u_int8_t proto)
+{
+ expand_label_if("$if", label, len, ifname);
+ expand_label_addr("$srcaddr", label, len, af, src_host);
+ expand_label_addr("$dstaddr", label, len, af, dst_host);
+ expand_label_port("$srcport", label, len, src_port);
+ expand_label_port("$dstport", label, len, dst_port);
+ expand_label_proto("$proto", label, len, proto);
+ expand_label_nr("$nr", label, len);
+}
+
+int
+expand_altq(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct pf_altq pa, pb;
+ char qname[PF_QNAME_SIZE];
+ struct node_queue *n;
+ struct node_queue_bw bw;
+ int errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ memcpy(&pa, a, sizeof(struct pf_altq));
+ if (strlcpy(pa.ifname, interface->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_altq: strlcpy");
+
+ if (interface->not) {
+ yyerror("altq on ! <interface> is not supported");
+ errs++;
+ } else {
+ if (eval_pfaltq(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ if (pf->opts & PF_OPT_VERBOSE) {
+ print_altq(&pf->paltq->altq, 0,
+ &bwspec, opts);
+ if (nqueues && nqueues->tail) {
+ printf("queue { ");
+ LOOP_THROUGH(struct node_queue, queue,
+ nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC) {
+ /* now create a root queue */
+ memset(&pb, 0, sizeof(struct pf_altq));
+ if (strlcpy(qname, "root_", sizeof(qname)) >=
+ sizeof(qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcat(qname, interface->ifname,
+ sizeof(qname)) >= sizeof(qname))
+ errx(1, "expand_altq: strlcat");
+ if (strlcpy(pb.qname, qname,
+ sizeof(pb.qname)) >= sizeof(pb.qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(pb.ifname, interface->ifname,
+ sizeof(pb.ifname)) >= sizeof(pb.ifname))
+ errx(1, "expand_altq: strlcpy");
+ pb.qlimit = pa.qlimit;
+ pb.scheduler = pa.scheduler;
+ bw.bw_absolute = pa.ifbandwidth;
+ bw.bw_percent = 0;
+ if (eval_pfqueue(pf, &pb, &bw, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pb))
+ errs++;
+ }
+
+ LOOP_THROUGH(struct node_queue, queue, nqueues,
+ n = calloc(1, sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_altq: calloc");
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC)
+ if (strlcpy(n->parent, qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->queue, queue->queue,
+ sizeof(n->queue)) >= sizeof(n->queue))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->ifname, interface->ifname,
+ sizeof(n->ifname)) >= sizeof(n->ifname))
+ errx(1, "expand_altq: strlcpy");
+ n->scheduler = pa.scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ );
+ }
+ );
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+
+ return (errs);
+}
+
+int
+expand_queue(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct node_queue *n, *nq;
+ struct pf_altq pa;
+ u_int8_t found = 0;
+ u_int8_t errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ if (queues == NULL) {
+ yyerror("queue %s has no parent", a->qname);
+ FREE_LIST(struct node_queue, nqueues);
+ return (1);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_queue, tqueue, queues,
+ if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
+ (interface->ifname[0] == 0 ||
+ (!interface->not && !strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)) ||
+ (interface->not && strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)))) {
+ /* found ourself in queues */
+ found++;
+
+ memcpy(&pa, a, sizeof(struct pf_altq));
+
+ if (pa.scheduler != ALTQT_NONE &&
+ pa.scheduler != tqueue->scheduler) {
+ yyerror("exactly one scheduler type "
+ "per interface allowed");
+ return (1);
+ }
+ pa.scheduler = tqueue->scheduler;
+
+ /* scheduler dependent error checking */
+ switch (pa.scheduler) {
+ case ALTQT_PRIQ:
+ if (nqueues != NULL) {
+ yyerror("priq queues cannot "
+ "have child queues");
+ return (1);
+ }
+ if (bwspec.bw_absolute > 0 ||
+ bwspec.bw_percent < 100) {
+ yyerror("priq doesn't take "
+ "bandwidth");
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (strlcpy(pa.ifname, tqueue->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_queue: strlcpy");
+ if (strlcpy(pa.parent, tqueue->parent,
+ sizeof(pa.parent)) >= sizeof(pa.parent))
+ errx(1, "expand_queue: strlcpy");
+
+ if (eval_pfqueue(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ for (nq = nqueues; nq != NULL; nq = nq->next) {
+ if (!strcmp(a->qname, nq->queue)) {
+ yyerror("queue cannot have "
+ "itself as child");
+ errs++;
+ continue;
+ }
+ n = calloc(1,
+ sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_queue: calloc");
+ if (strlcpy(n->parent, a->qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->queue, nq->queue,
+ sizeof(n->queue)) >=
+ sizeof(n->queue))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->ifname, tqueue->ifname,
+ sizeof(n->ifname)) >=
+ sizeof(n->ifname))
+ errx(1, "expand_queue strlcpy");
+ n->scheduler = tqueue->scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ }
+ if ((pf->opts & PF_OPT_VERBOSE) && (
+ (found == 1 && interface->ifname[0] == 0) ||
+ (found > 0 && interface->ifname[0] != 0))) {
+ print_queue(&pf->paltq->altq, 0,
+ &bwspec, interface->ifname[0] != 0,
+ opts);
+ if (nqueues && nqueues->tail) {
+ printf("{ ");
+ LOOP_THROUGH(struct node_queue,
+ queue, nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+ }
+ );
+ );
+
+ FREE_LIST(struct node_queue, nqueues);
+ FREE_LIST(struct node_if, interfaces);
+
+ if (!found) {
+ yyerror("queue %s has no parent", a->qname);
+ errs++;
+ }
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+void
+expand_rule(struct pf_rule *r,
+ struct node_if *interfaces, struct node_host *rpool_hosts,
+ struct node_proto *protos, struct node_os *src_oses,
+ struct node_host *src_hosts, struct node_port *src_ports,
+ struct node_host *dst_hosts, struct node_port *dst_ports,
+ struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
+ const char *anchor_call)
+{
+ sa_family_t af = r->af;
+ int added = 0, error = 0;
+ char ifname[IF_NAMESIZE];
+ char label[PF_RULE_LABEL_SIZE];
+ char tagname[PF_TAG_NAME_SIZE];
+ char match_tagname[PF_TAG_NAME_SIZE];
+ struct pf_pooladdr *pa;
+ struct node_host *h;
+ u_int8_t flags, flagset, keep_state;
+
+ if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
+ sizeof(match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ flags = r->flags;
+ flagset = r->flagset;
+ keep_state = r->keep_state;
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_proto, proto, protos,
+ LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
+ LOOP_THROUGH(struct node_host, src_host, src_hosts,
+ LOOP_THROUGH(struct node_port, src_port, src_ports,
+ LOOP_THROUGH(struct node_os, src_os, src_oses,
+ LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
+ LOOP_THROUGH(struct node_port, dst_port, dst_ports,
+ LOOP_THROUGH(struct node_uid, uid, uids,
+ LOOP_THROUGH(struct node_gid, gid, gids,
+
+ r->af = af;
+ /* for link-local IPv6 address, interface must match up */
+ if ((r->af && src_host->af && r->af != src_host->af) ||
+ (r->af && dst_host->af && r->af != dst_host->af) ||
+ (src_host->af && dst_host->af &&
+ src_host->af != dst_host->af) ||
+ (src_host->ifindex && dst_host->ifindex &&
+ src_host->ifindex != dst_host->ifindex) ||
+ (src_host->ifindex && *interface->ifname &&
+ src_host->ifindex != if_nametoindex(interface->ifname)) ||
+ (dst_host->ifindex && *interface->ifname &&
+ dst_host->ifindex != if_nametoindex(interface->ifname)))
+ continue;
+ if (!r->af && src_host->af)
+ r->af = src_host->af;
+ else if (!r->af && dst_host->af)
+ r->af = dst_host->af;
+
+ if (*interface->ifname)
+ strlcpy(r->ifname, interface->ifname,
+ sizeof(r->ifname));
+ else if (if_indextoname(src_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else if (if_indextoname(dst_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else
+ memset(r->ifname, '\0', sizeof(r->ifname));
+
+ if (strlcpy(r->label, label, sizeof(r->label)) >=
+ sizeof(r->label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
+ sizeof(r->tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->match_tagname, match_tagname,
+ sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
+ r->af, src_host, src_port, dst_host, dst_port,
+ proto->proto);
+
+ error += check_netmask(src_host, r->af);
+ error += check_netmask(dst_host, r->af);
+
+ r->ifnot = interface->not;
+ r->proto = proto->proto;
+ r->src.addr = src_host->addr;
+ r->src.neg = src_host->not;
+ r->src.port[0] = src_port->port[0];
+ r->src.port[1] = src_port->port[1];
+ r->src.port_op = src_port->op;
+ r->dst.addr = dst_host->addr;
+ r->dst.neg = dst_host->not;
+ r->dst.port[0] = dst_port->port[0];
+ r->dst.port[1] = dst_port->port[1];
+ r->dst.port_op = dst_port->op;
+ r->uid.op = uid->op;
+ r->uid.uid[0] = uid->uid[0];
+ r->uid.uid[1] = uid->uid[1];
+ r->gid.op = gid->op;
+ r->gid.gid[0] = gid->gid[0];
+ r->gid.gid[1] = gid->gid[1];
+ r->type = icmp_type->type;
+ r->code = icmp_type->code;
+
+ if ((keep_state == PF_STATE_MODULATE ||
+ keep_state == PF_STATE_SYNPROXY) &&
+ r->proto && r->proto != IPPROTO_TCP)
+ r->keep_state = PF_STATE_NORMAL;
+ else
+ r->keep_state = keep_state;
+
+ if (r->proto && r->proto != IPPROTO_TCP) {
+ r->flags = 0;
+ r->flagset = 0;
+ } else {
+ r->flags = flags;
+ r->flagset = flagset;
+ }
+ if (icmp_type->proto && r->proto != icmp_type->proto) {
+ yyerror("icmp-type mismatch");
+ error++;
+ }
+
+ if (src_os && src_os->os) {
+ r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
+ if ((pf->opts & PF_OPT_VERBOSE2) &&
+ r->os_fingerprint == PF_OSFP_NOMATCH)
+ fprintf(stderr,
+ "warning: unknown '%s' OS fingerprint\n",
+ src_os->os);
+ } else {
+ r->os_fingerprint = PF_OSFP_ANY;
+ }
+
+ TAILQ_INIT(&r->rpool.list);
+ for (h = rpool_hosts; h != NULL; h = h->next) {
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "expand_rule: calloc");
+ pa->addr = h->addr;
+ if (h->ifname != NULL) {
+ if (strlcpy(pa->ifname, h->ifname,
+ sizeof(pa->ifname)) >=
+ sizeof(pa->ifname))
+ errx(1, "expand_rule: strlcpy");
+ } else
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
+ }
+
+ if (rule_consistent(r, anchor_call[0]) < 0 || error)
+ yyerror("skipping rule due to errors");
+ else {
+ r->nr = pf->astack[pf->asd]->match++;
+ pfctl_add_rule(pf, r, anchor_call);
+ added++;
+ }
+
+ ))))))))));
+
+ FREE_LIST(struct node_if, interfaces);
+ FREE_LIST(struct node_proto, protos);
+ FREE_LIST(struct node_host, src_hosts);
+ FREE_LIST(struct node_port, src_ports);
+ FREE_LIST(struct node_os, src_oses);
+ FREE_LIST(struct node_host, dst_hosts);
+ FREE_LIST(struct node_port, dst_ports);
+ FREE_LIST(struct node_uid, uids);
+ FREE_LIST(struct node_gid, gids);
+ FREE_LIST(struct node_icmp, icmp_types);
+ FREE_LIST(struct node_host, rpool_hosts);
+
+ if (!added)
+ yyerror("rule expands to no valid combination");
+}
+
+int
+expand_skip_interface(struct node_if *interfaces)
+{
+ int errs = 0;
+
+ if (!interfaces || (!interfaces->next && !interfaces->not &&
+ !strcmp(interfaces->ifname, "none"))) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on none\n");
+ errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
+ return (errs);
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on {");
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" %s", interface->ifname);
+ if (interface->not) {
+ yyerror("skip on ! <interface> is not supported");
+ errs++;
+ } else
+ errs += pfctl_set_interface_flags(pf,
+ interface->ifname, PFI_IFLAG_SKIP, 1);
+ );
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" }\n");
+
+ FREE_LIST(struct node_if, interfaces);
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+#undef FREE_LIST
+#undef LOOP_THROUGH
+
+int
+check_rulestate(int desired_state)
+{
+ if (require_order && (rulestate > desired_state)) {
+ yyerror("Rules must be in order: options, normalization, "
+ "queueing, translation, filtering");
+ return (1);
+ }
+ rulestate = desired_state;
+ return (0);
+}
+
+int
+kw_cmp(const void *k, const void *e)
+{
+ return (strcmp(k, ((const struct keywords *)e)->k_name));
+}
+
+int
+lookup(char *s)
+{
+ /* this has to be sorted always */
+ static const struct keywords keywords[] = {
+ { "all", ALL},
+ { "allow-opts", ALLOWOPTS},
+ { "altq", ALTQ},
+ { "anchor", ANCHOR},
+ { "antispoof", ANTISPOOF},
+ { "any", ANY},
+ { "bandwidth", BANDWIDTH},
+ { "binat", BINAT},
+ { "binat-anchor", BINATANCHOR},
+ { "bitmask", BITMASK},
+ { "block", BLOCK},
+ { "block-policy", BLOCKPOLICY},
+ { "buckets", BUCKETS},
+ { "cbq", CBQ},
+ { "code", CODE},
+ { "codelq", CODEL},
+ { "crop", FRAGCROP},
+ { "debug", DEBUG},
+ { "divert-reply", DIVERTREPLY},
+ { "divert-to", DIVERTTO},
+ { "drop", DROP},
+ { "drop-ovl", FRAGDROP},
+ { "dup-to", DUPTO},
+ { "fairq", FAIRQ},
+ { "fastroute", FASTROUTE},
+ { "file", FILENAME},
+ { "fingerprints", FINGERPRINTS},
+ { "flags", FLAGS},
+ { "floating", FLOATING},
+ { "flush", FLUSH},
+ { "for", FOR},
+ { "fragment", FRAGMENT},
+ { "from", FROM},
+ { "global", GLOBAL},
+ { "group", GROUP},
+ { "hfsc", HFSC},
+ { "hogs", HOGS},
+ { "hostid", HOSTID},
+ { "icmp-type", ICMPTYPE},
+ { "icmp6-type", ICMP6TYPE},
+ { "if-bound", IFBOUND},
+ { "in", IN},
+ { "include", INCLUDE},
+ { "inet", INET},
+ { "inet6", INET6},
+ { "interval", INTERVAL},
+ { "keep", KEEP},
+ { "label", LABEL},
+ { "limit", LIMIT},
+ { "linkshare", LINKSHARE},
+ { "load", LOAD},
+ { "log", LOG},
+ { "loginterface", LOGINTERFACE},
+ { "max", MAXIMUM},
+ { "max-mss", MAXMSS},
+ { "max-src-conn", MAXSRCCONN},
+ { "max-src-conn-rate", MAXSRCCONNRATE},
+ { "max-src-nodes", MAXSRCNODES},
+ { "max-src-states", MAXSRCSTATES},
+ { "min-ttl", MINTTL},
+ { "modulate", MODULATE},
+ { "nat", NAT},
+ { "nat-anchor", NATANCHOR},
+ { "no", NO},
+ { "no-df", NODF},
+ { "no-route", NOROUTE},
+ { "no-sync", NOSYNC},
+ { "on", ON},
+ { "optimization", OPTIMIZATION},
+ { "os", OS},
+ { "out", OUT},
+ { "overload", OVERLOAD},
+ { "pass", PASS},
+ { "port", PORT},
+ { "prio", PRIO},
+ { "priority", PRIORITY},
+ { "priq", PRIQ},
+ { "probability", PROBABILITY},
+ { "proto", PROTO},
+ { "qlimit", QLIMIT},
+ { "queue", QUEUE},
+ { "quick", QUICK},
+ { "random", RANDOM},
+ { "random-id", RANDOMID},
+ { "rdr", RDR},
+ { "rdr-anchor", RDRANCHOR},
+ { "realtime", REALTIME},
+ { "reassemble", REASSEMBLE},
+ { "reply-to", REPLYTO},
+ { "require-order", REQUIREORDER},
+ { "return", RETURN},
+ { "return-icmp", RETURNICMP},
+ { "return-icmp6", RETURNICMP6},
+ { "return-rst", RETURNRST},
+ { "round-robin", ROUNDROBIN},
+ { "route", ROUTE},
+ { "route-to", ROUTETO},
+ { "rtable", RTABLE},
+ { "rule", RULE},
+ { "ruleset-optimization", RULESET_OPTIMIZATION},
+ { "scrub", SCRUB},
+ { "set", SET},
+ { "set-tos", SETTOS},
+ { "skip", SKIP},
+ { "sloppy", SLOPPY},
+ { "source-hash", SOURCEHASH},
+ { "source-track", SOURCETRACK},
+ { "state", STATE},
+ { "state-defaults", STATEDEFAULTS},
+ { "state-policy", STATEPOLICY},
+ { "static-port", STATICPORT},
+ { "sticky-address", STICKYADDRESS},
+ { "synproxy", SYNPROXY},
+ { "table", TABLE},
+ { "tag", TAG},
+ { "tagged", TAGGED},
+ { "target", TARGET},
+ { "tbrsize", TBRSIZE},
+ { "timeout", TIMEOUT},
+ { "to", TO},
+ { "tos", TOS},
+ { "ttl", TTL},
+ { "upperlimit", UPPERLIMIT},
+ { "urpf-failed", URPFFAILED},
+ { "user", USER},
+ };
+ const struct keywords *p;
+
+ p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
+ sizeof(keywords[0]), kw_cmp);
+
+ if (p) {
+ if (debug > 1)
+ fprintf(stderr, "%s: %d\n", s, p->k_val);
+ return (p->k_val);
+ } else {
+ if (debug > 1)
+ fprintf(stderr, "string: %s\n", s);
+ return (STRING);
+ }
+}
+
+#define MAXPUSHBACK 128
+
+static char *parsebuf;
+static int parseindex;
+static char pushback_buffer[MAXPUSHBACK];
+static int pushback_index = 0;
+
+int
+lgetc(int quotec)
+{
+ int c, next;
+
+ if (parsebuf) {
+ /* Read character from the parsebuffer instead of input. */
+ if (parseindex >= 0) {
+ c = parsebuf[parseindex++];
+ if (c != '\0')
+ return (c);
+ parsebuf = NULL;
+ } else
+ parseindex++;
+ }
+
+ if (pushback_index)
+ return (pushback_buffer[--pushback_index]);
+
+ if (quotec) {
+ if ((c = getc(file->stream)) == EOF) {
+ yyerror("reached end of file while parsing quoted string");
+ if (popfile() == EOF)
+ return (EOF);
+ return (quotec);
+ }
+ return (c);
+ }
+
+ while ((c = getc(file->stream)) == '\\') {
+ next = getc(file->stream);
+ if (next != '\n') {
+ c = next;
+ break;
+ }
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+
+ while (c == EOF) {
+ if (popfile() == EOF)
+ return (EOF);
+ c = getc(file->stream);
+ }
+ return (c);
+}
+
+int
+lungetc(int c)
+{
+ if (c == EOF)
+ return (EOF);
+ if (parsebuf) {
+ parseindex--;
+ if (parseindex >= 0)
+ return (c);
+ }
+ if (pushback_index < MAXPUSHBACK-1)
+ return (pushback_buffer[pushback_index++] = c);
+ else
+ return (EOF);
+}
+
+int
+findeol(void)
+{
+ int c;
+
+ parsebuf = NULL;
+
+ /* skip to either EOF or the first real EOL */
+ while (1) {
+ if (pushback_index)
+ c = pushback_buffer[--pushback_index];
+ else
+ c = lgetc(0);
+ if (c == '\n') {
+ file->lineno++;
+ break;
+ }
+ if (c == EOF)
+ break;
+ }
+ return (ERROR);
+}
+
+int
+yylex(void)
+{
+ char buf[8096];
+ char *p, *val;
+ int quotec, next, c;
+ int token;
+
+top:
+ p = buf;
+ while ((c = lgetc(0)) == ' ' || c == '\t')
+ ; /* nothing */
+
+ yylval.lineno = file->lineno;
+ if (c == '#')
+ while ((c = lgetc(0)) != '\n' && c != EOF)
+ ; /* nothing */
+ if (c == '$' && parsebuf == NULL) {
+ while (1) {
+ if ((c = lgetc(0)) == EOF)
+ return (0);
+
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ if (isalnum(c) || c == '_') {
+ *p++ = (char)c;
+ continue;
+ }
+ *p = '\0';
+ lungetc(c);
+ break;
+ }
+ val = symget(buf);
+ if (val == NULL) {
+ yyerror("macro '%s' not defined", buf);
+ return (findeol());
+ }
+ parsebuf = val;
+ parseindex = 0;
+ goto top;
+ }
+
+ switch (c) {
+ case '\'':
+ case '"':
+ quotec = c;
+ while (1) {
+ if ((c = lgetc(quotec)) == EOF)
+ return (0);
+ if (c == '\n') {
+ file->lineno++;
+ continue;
+ } else if (c == '\\') {
+ if ((next = lgetc(quotec)) == EOF)
+ return (0);
+ if (next == quotec || c == ' ' || c == '\t')
+ c = next;
+ else if (next == '\n')
+ continue;
+ else
+ lungetc(next);
+ } else if (c == quotec) {
+ *p = '\0';
+ break;
+ }
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ *p++ = (char)c;
+ }
+ yylval.v.string = strdup(buf);
+ if (yylval.v.string == NULL)
+ err(1, "yylex: strdup");
+ return (STRING);
+ case '<':
+ next = lgetc(0);
+ if (next == '>') {
+ yylval.v.i = PF_OP_XRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '>':
+ next = lgetc(0);
+ if (next == '<') {
+ yylval.v.i = PF_OP_IRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '-':
+ next = lgetc(0);
+ if (next == '>')
+ return (ARROW);
+ lungetc(next);
+ break;
+ }
+
+#define allowed_to_end_number(x) \
+ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
+
+ if (c == '-' || isdigit(c)) {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && isdigit(c));
+ lungetc(c);
+ if (p == buf + 1 && buf[0] == '-')
+ goto nodigits;
+ if (c == EOF || allowed_to_end_number(c)) {
+ const char *errstr = NULL;
+
+ *p = '\0';
+ yylval.v.number = strtonum(buf, LLONG_MIN,
+ LLONG_MAX, &errstr);
+ if (errstr) {
+ yyerror("\"%s\" invalid number: %s",
+ buf, errstr);
+ return (findeol());
+ }
+ return (NUMBER);
+ } else {
+nodigits:
+ while (p > buf + 1)
+ lungetc(*--p);
+ c = *--p;
+ if (c == '-')
+ return (c);
+ }
+ }
+
+#define allowed_in_string(x) \
+ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
+ x != '{' && x != '}' && x != '<' && x != '>' && \
+ x != '!' && x != '=' && x != '/' && x != '#' && \
+ x != ','))
+
+ if (isalnum(c) || c == ':' || c == '_') {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
+ lungetc(c);
+ *p = '\0';
+ if ((token = lookup(buf)) == STRING)
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "yylex: strdup");
+ return (token);
+ }
+ if (c == '\n') {
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+ if (c == EOF)
+ return (0);
+ return (c);
+}
+
+int
+check_file_secrecy(int fd, const char *fname)
+{
+ struct stat st;
+
+ if (fstat(fd, &st)) {
+ warn("cannot stat %s", fname);
+ return (-1);
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ warnx("%s: owner not root or current user", fname);
+ return (-1);
+ }
+ if (st.st_mode & (S_IRWXG | S_IRWXO)) {
+ warnx("%s: group/world readable/writeable", fname);
+ return (-1);
+ }
+ return (0);
+}
+
+struct file *
+pushfile(const char *name, int secret)
+{
+ struct file *nfile;
+
+ if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
+ (nfile->name = strdup(name)) == NULL) {
+ warn("malloc");
+ return (NULL);
+ }
+ if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
+ nfile->stream = stdin;
+ free(nfile->name);
+ if ((nfile->name = strdup("stdin")) == NULL) {
+ warn("strdup");
+ free(nfile);
+ return (NULL);
+ }
+ } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
+ warn("%s", nfile->name);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ } else if (secret &&
+ check_file_secrecy(fileno(nfile->stream), nfile->name)) {
+ fclose(nfile->stream);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ }
+ nfile->lineno = 1;
+ TAILQ_INSERT_TAIL(&files, nfile, entry);
+ return (nfile);
+}
+
+int
+popfile(void)
+{
+ struct file *prev;
+
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
+ prev->errors += file->errors;
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file);
+ file = prev;
+ return (0);
+ }
+ return (EOF);
+}
+
+int
+parse_config(char *filename, struct pfctl *xpf)
+{
+ int errors = 0;
+ struct sym *sym;
+
+ pf = xpf;
+ errors = 0;
+ rulestate = PFCTL_STATE_NONE;
+ returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+ returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+ blockpolicy = PFRULE_DROP;
+ require_order = 1;
+
+ if ((file = pushfile(filename, 0)) == NULL) {
+ warn("cannot open the main config file!");
+ return (-1);
+ }
+
+ yyparse();
+ errors = file->errors;
+ popfile();
+
+ /* Free macros and check which have not been used. */
+ while ((sym = TAILQ_FIRST(&symhead))) {
+ if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
+ fprintf(stderr, "warning: macro '%s' not "
+ "used\n", sym->nam);
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+
+ return (errors ? -1 : 0);
+}
+
+int
+symset(const char *nam, const char *val, int persist)
+{
+ struct sym *sym;
+
+ for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
+ sym = TAILQ_NEXT(sym, entry))
+ ; /* nothing */
+
+ if (sym != NULL) {
+ if (sym->persist == 1)
+ return (0);
+ else {
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+ }
+ if ((sym = calloc(1, sizeof(*sym))) == NULL)
+ return (-1);
+
+ sym->nam = strdup(nam);
+ if (sym->nam == NULL) {
+ free(sym);
+ return (-1);
+ }
+ sym->val = strdup(val);
+ if (sym->val == NULL) {
+ free(sym->nam);
+ free(sym);
+ return (-1);
+ }
+ sym->used = 0;
+ sym->persist = persist;
+ TAILQ_INSERT_TAIL(&symhead, sym, entry);
+ return (0);
+}
+
+int
+pfctl_cmdline_symset(char *s)
+{
+ char *sym, *val;
+ int ret;
+
+ if ((val = strrchr(s, '=')) == NULL)
+ return (-1);
+
+ if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
+ err(1, "pfctl_cmdline_symset: malloc");
+
+ strlcpy(sym, s, strlen(s) - strlen(val) + 1);
+
+ ret = symset(sym, val + 1, 1);
+ free(sym);
+
+ return (ret);
+}
+
+char *
+symget(const char *nam)
+{
+ struct sym *sym;
+
+ TAILQ_FOREACH(sym, &symhead, entry)
+ if (strcmp(nam, sym->nam) == 0) {
+ sym->used = 1;
+ return (sym->val);
+ }
+ return (NULL);
+}
+
+void
+mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
+{
+ int i;
+ struct pf_rule *r;
+
+ for (i = 0; i < PF_RULESET_MAX; ++i) {
+ while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
+ dst->anchor->match++;
+ }
+ src->anchor->match = 0;
+ while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
+ r, entries);
+ }
+ }
+}
+
+void
+decide_address_family(struct node_host *n, sa_family_t *af)
+{
+ if (*af != 0 || n == NULL)
+ return;
+ *af = n->af;
+ while ((n = n->next) != NULL) {
+ if (n->af != *af) {
+ *af = 0;
+ return;
+ }
+ }
+}
+
+void
+remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
+{
+ struct node_host *n = *nh, *prev = NULL;
+
+ while (n != NULL) {
+ if (*af && n->af && n->af != *af) {
+ /* unlink and free n */
+ struct node_host *next = n->next;
+
+ /* adjust tail pointer */
+ if (n == (*nh)->tail)
+ (*nh)->tail = prev;
+ /* adjust previous node's next pointer */
+ if (prev == NULL)
+ *nh = next;
+ else
+ prev->next = next;
+ /* free node */
+ if (n->ifname != NULL)
+ free(n->ifname);
+ free(n);
+ n = next;
+ } else {
+ if (n->af && !*af)
+ *af = n->af;
+ prev = n;
+ n = n->next;
+ }
+ }
+}
+
+int
+invalid_redirect(struct node_host *nh, sa_family_t af)
+{
+ if (!af) {
+ struct node_host *n;
+
+ /* tables and dyniftl are ok without an address family */
+ for (n = nh; n != NULL; n = n->next) {
+ if (n->addr.type != PF_ADDR_TABLE &&
+ n->addr.type != PF_ADDR_DYNIFTL) {
+ yyerror("address family not given and "
+ "translation address expands to multiple "
+ "address families");
+ return (1);
+ }
+ }
+ }
+ if (nh == NULL) {
+ yyerror("no translation address with matching address family "
+ "found.");
+ return (1);
+ }
+ return (0);
+}
+
+int
+atoul(char *s, u_long *ulvalp)
+{
+ u_long ulval;
+ char *ep;
+
+ errno = 0;
+ ulval = strtoul(s, &ep, 0);
+ if (s[0] == '\0' || *ep != '\0')
+ return (-1);
+ if (errno == ERANGE && ulval == ULONG_MAX)
+ return (-1);
+ *ulvalp = ulval;
+ return (0);
+}
+
+int
+getservice(char *n)
+{
+ struct servent *s;
+ u_long ulval;
+
+ if (atoul(n, &ulval) == 0) {
+ if (ulval > 65535) {
+ yyerror("illegal port value %lu", ulval);
+ return (-1);
+ }
+ return (htons(ulval));
+ } else {
+ s = getservbyname(n, "tcp");
+ if (s == NULL)
+ s = getservbyname(n, "udp");
+ if (s == NULL) {
+ yyerror("unknown port %s", n);
+ return (-1);
+ }
+ return (s->s_port);
+ }
+}
+
+int
+rule_label(struct pf_rule *r, char *s)
+{
+ if (s) {
+ if (strlcpy(r->label, s, sizeof(r->label)) >=
+ sizeof(r->label)) {
+ yyerror("rule label too long (max %d chars)",
+ sizeof(r->label)-1);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+u_int16_t
+parseicmpspec(char *w, sa_family_t af)
+{
+ const struct icmpcodeent *p;
+ u_long ulval;
+ u_int8_t icmptype;
+
+ if (af == AF_INET)
+ icmptype = returnicmpdefault >> 8;
+ else
+ icmptype = returnicmp6default >> 8;
+
+ if (atoul(w, &ulval) == -1) {
+ if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
+ yyerror("unknown icmp code %s", w);
+ return (0);
+ }
+ ulval = p->code;
+ }
+ if (ulval > 255) {
+ yyerror("invalid icmp code %lu", ulval);
+ return (0);
+ }
+ return (icmptype << 8 | ulval);
+}
+
+int
+parseport(char *port, struct range *r, int extensions)
+{
+ char *p = strchr(port, ':');
+
+ if (p == NULL) {
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ return (0);
+ }
+ if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
+ *p = 0;
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_IRG;
+ return (0);
+ }
+ if ((extensions & PPORT_RANGE)) {
+ *p++ = 0;
+ if ((r->a = getservice(port)) == -1 ||
+ (r->b = getservice(p)) == -1)
+ return (-1);
+ if (r->a == r->b) {
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ } else
+ r->t = PF_OP_RRG;
+ return (0);
+ }
+ return (-1);
+}
+
+int
+pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
+{
+ struct loadanchors *la;
+
+ TAILQ_FOREACH(la, &loadanchorshead, entries) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "\nLoading anchor %s from %s\n",
+ la->anchorname, la->filename);
+ if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
+ la->anchorname, trans) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+rt_tableid_max(void)
+{
+#ifdef __FreeBSD__
+ int fibs;
+ size_t l = sizeof(fibs);
+
+ if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
+ fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */
+ /*
+ * As the OpenBSD code only compares > and not >= we need to adjust
+ * here given we only accept values of 0..n and want to avoid #ifdefs
+ * in the grammar.
+ */
+ return (fibs - 1);
+#else
+ return (RT_TABLEID_MAX);
+#endif
+}
+#line 4317 "pfctly.tab.c"
+
+#if YYDEBUG
+#include <stdio.h> /* needed for printf */
+#endif
+
+#include <stdlib.h> /* needed for malloc, etc */
+#include <string.h> /* needed for memset */
+
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+static int yygrowstack(YYSTACKDATA *data)
+{
+ int i;
+ unsigned newsize;
+ YYINT *newss;
+ YYSTYPE *newvs;
+
+ if ((newsize = data->stacksize) == 0)
+ newsize = YYINITSTACKSIZE;
+ else if (newsize >= YYMAXDEPTH)
+ return YYENOMEM;
+ else if ((newsize *= 2) > YYMAXDEPTH)
+ newsize = YYMAXDEPTH;
+
+ i = (int) (data->s_mark - data->s_base);
+ newss = (YYINT *)realloc(data->s_base, newsize * sizeof(*newss));
+ if (newss == 0)
+ return YYENOMEM;
+
+ data->s_base = newss;
+ data->s_mark = newss + i;
+
+ newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs));
+ if (newvs == 0)
+ return YYENOMEM;
+
+ data->l_base = newvs;
+ data->l_mark = newvs + i;
+
+ data->stacksize = newsize;
+ data->s_last = data->s_base + newsize - 1;
+ return 0;
+}
+
+#if YYPURE || defined(YY_NO_LEAKS)
+static void yyfreestack(YYSTACKDATA *data)
+{
+ free(data->s_base);
+ free(data->l_base);
+ memset(data, 0, sizeof(*data));
+}
+#else
+#define yyfreestack(data) /* nothing */
+#endif
+
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+
+int
+YYPARSE_DECL()
+{
+ int yym, yyn, yystate;
+#if YYDEBUG
+ const char *yys;
+
+ if ((yys = getenv("YYDEBUG")) != 0)
+ {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = YYEMPTY;
+ yystate = 0;
+
+#if YYPURE
+ memset(&yystack, 0, sizeof(yystack));
+#endif
+
+ if (yystack.s_base == NULL && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+ yystack.s_mark = yystack.s_base;
+ yystack.l_mark = yystack.l_base;
+ yystate = 0;
+ *yystack.s_mark = 0;
+
+yyloop:
+ if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+ if (yychar < 0)
+ {
+ if ((yychar = YYLEX) < 0) yychar = YYEOF;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = yyname[YYTRANSLATE(yychar)];
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ }
+ if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, shifting to state %d\n",
+ YYPREFIX, yystate, yytable[yyn]);
+#endif
+ if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM)
+ {
+ goto yyoverflow;
+ }
+ yystate = yytable[yyn];
+ *++yystack.s_mark = yytable[yyn];
+ *++yystack.l_mark = yylval;
+ yychar = YYEMPTY;
+ if (yyerrflag > 0) --yyerrflag;
+ goto yyloop;
+ }
+ if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag) goto yyinrecovery;
+
+ YYERROR_CALL("syntax error");
+
+ goto yyerrlab;
+
+yyerrlab:
+ ++yynerrs;
+
+yyinrecovery:
+ if (yyerrflag < 3)
+ {
+ yyerrflag = 3;
+ for (;;)
+ {
+ if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]);
+#endif
+ if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM)
+ {
+ goto yyoverflow;
+ }
+ yystate = yytable[yyn];
+ *++yystack.s_mark = yytable[yyn];
+ *++yystack.l_mark = yylval;
+ goto yyloop;
+ }
+ else
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: error recovery discarding state %d\n",
+ YYPREFIX, *yystack.s_mark);
+#endif
+ if (yystack.s_mark <= yystack.s_base) goto yyabort;
+ --yystack.s_mark;
+ --yystack.l_mark;
+ }
+ }
+ }
+ else
+ {
+ if (yychar == YYEOF) goto yyabort;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = yyname[YYTRANSLATE(yychar)];
+ printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ yychar = YYEMPTY;
+ goto yyloop;
+ }
+
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+ YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ if (yym)
+ yyval = yystack.l_mark[1-yym];
+ else
+ memset(&yyval, 0, sizeof yyval);
+ switch (yyn)
+ {
+case 17:
+#line 553 "../../freebsd/sbin/pfctl/parse.y"
+ { file->errors++; }
+break;
+case 18:
+#line 556 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct file *nfile;
+
+ if ((nfile = pushfile(yystack.l_mark[0].v.string, 0)) == NULL) {
+ yyerror("failed to include file %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+
+ file = nfile;
+ lungetc('\n');
+ }
+break;
+case 25:
+#line 583 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "none"))
+ yyval.v.i = 0;
+ else if (!strcmp(yystack.l_mark[0].v.string, "basic"))
+ yyval.v.i = PF_OPTIMIZE_BASIC;
+ else if (!strcmp(yystack.l_mark[0].v.string, "profile"))
+ yyval.v.i = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
+ else {
+ yyerror("unknown ruleset-optimization %s", yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ }
+break;
+case 26:
+#line 597 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (pfctl_set_optimization(pf, yystack.l_mark[0].v.string) != 0) {
+ yyerror("unknown optimization %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 27:
+#line 609 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!(pf->opts & PF_OPT_OPTIMIZE)) {
+ pf->opts |= PF_OPT_OPTIMIZE;
+ pf->optimize = yystack.l_mark[0].v.i;
+ }
+ }
+break;
+case 32:
+#line 619 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (pfctl_set_logif(pf, yystack.l_mark[0].v.string) != 0) {
+ yyerror("error setting loginterface %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 33:
+#line 631 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number == 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("hostid must be non-zero");
+ YYERROR;
+ }
+ if (pfctl_set_hostid(pf, yystack.l_mark[0].v.number) != 0) {
+ yyerror("error setting hostid %08x", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ }
+break;
+case 34:
+#line 641 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy drop\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_DROP;
+ }
+break;
+case 35:
+#line 648 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy return\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_RETURN;
+ }
+break;
+case 36:
+#line 655 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set require-order %s\n",
+ yystack.l_mark[0].v.number == 1 ? "yes" : "no");
+ require_order = yystack.l_mark[0].v.number;
+ }
+break;
+case 37:
+#line 661 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set fingerprints \"%s\"\n", yystack.l_mark[0].v.string);
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (!pf->anchor->name[0]) {
+ if (pfctl_file_fingerprints(pf->dev,
+ pf->opts, yystack.l_mark[0].v.string)) {
+ yyerror("error loading "
+ "fingerprints %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 38:
+#line 679 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ switch (yystack.l_mark[0].v.i) {
+ case 0:
+ printf("set state-policy floating\n");
+ break;
+ case PFRULE_IFBOUND:
+ printf("set state-policy if-bound\n");
+ break;
+ }
+ default_statelock = yystack.l_mark[0].v.i;
+ }
+break;
+case 39:
+#line 691 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (pfctl_set_debug(pf, yystack.l_mark[0].v.string) != 0) {
+ yyerror("error setting debuglevel %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 40:
+#line 703 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (expand_skip_interface(yystack.l_mark[0].v.interface) != 0) {
+ yyerror("error setting skip interface(s)");
+ YYERROR;
+ }
+ }
+break;
+case 41:
+#line 709 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (keep_state_defaults != NULL) {
+ yyerror("cannot redefine state-defaults");
+ YYERROR;
+ }
+ keep_state_defaults = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 42:
+#line 718 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = yystack.l_mark[0].v.string; }
+break;
+case 43:
+#line 719 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if ((yyval.v.string = strdup("all")) == NULL) {
+ err(1, "stringall: strdup");
+ }
+ }
+break;
+case 44:
+#line 726 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1)
+ err(1, "string: asprintf");
+ free(yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 46:
+#line 735 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1)
+ err(1, "string: asprintf");
+ free(yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 48:
+#line 744 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *s;
+ if (asprintf(&s, "%lld", (long long)yystack.l_mark[0].v.number) == -1) {
+ yyerror("string: asprintf");
+ YYERROR;
+ }
+ yyval.v.string = s;
+ }
+break;
+case 50:
+#line 755 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("%s = \"%s\"\n", yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string);
+ if (symset(yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string, 0) == -1)
+ err(1, "cannot store variable %s", yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 51:
+#line 765 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = yystack.l_mark[0].v.string; }
+break;
+case 52:
+#line 766 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = NULL; }
+break;
+case 57:
+#line 776 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char ta[PF_ANCHOR_NAME_SIZE];
+ struct pf_ruleset *rs;
+
+ /* steping into a brace anchor */
+ pf->asd++;
+ pf->bn++;
+ pf->brace = 1;
+
+ /* create a holding ruleset in the root */
+ snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
+ rs = pf_find_or_create_ruleset(ta);
+ if (rs == NULL)
+ err(1, "pfa_anchor: pf_find_or_create_ruleset");
+ pf->astack[pf->asd] = rs->anchor;
+ pf->anchor = rs->anchor;
+ }
+break;
+case 58:
+#line 793 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ pf->alast = pf->anchor;
+ pf->asd--;
+ pf->anchor = pf->astack[pf->asd];
+ }
+break;
+case 60:
+#line 803 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+ struct node_proto *proto;
+
+ if (check_rulestate(PFCTL_STATE_FILTER)) {
+ if (yystack.l_mark[-8].v.string)
+ free(yystack.l_mark[-8].v.string);
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-8].v.string && (yystack.l_mark[-8].v.string[0] == '_' || strstr(yystack.l_mark[-8].v.string, "/_") != NULL)) {
+ free(yystack.l_mark[-8].v.string);
+ yyerror("anchor names beginning with '_' "
+ "are reserved for internal use");
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ if (pf->astack[pf->asd + 1]) {
+ /* move inline rules into relative location */
+ pf_anchor_setup(&r,
+ &pf->astack[pf->asd]->ruleset,
+ yystack.l_mark[-8].v.string ? yystack.l_mark[-8].v.string : pf->alast->name);
+
+ if (r.anchor == NULL)
+ err(1, "anchorrule: unable to "
+ "create ruleset");
+
+ if (pf->alast != r.anchor) {
+ if (r.anchor->match) {
+ yyerror("inline anchor '%s' "
+ "already exists",
+ r.anchor->name);
+ YYERROR;
+ }
+ mv_rules(&pf->alast->ruleset,
+ &r.anchor->ruleset);
+ }
+ pf_remove_if_empty_ruleset(&pf->alast->ruleset);
+ pf->alast = r.anchor;
+ } else {
+ if (!yystack.l_mark[-8].v.string) {
+ yyerror("anchors without explicit "
+ "rules must specify a name");
+ YYERROR;
+ }
+ }
+ r.direction = yystack.l_mark[-7].v.i;
+ r.quick = yystack.l_mark[-6].v.logquick.quick;
+ r.af = yystack.l_mark[-4].v.i;
+ r.prob = yystack.l_mark[-1].v.filter_opts.prob;
+ r.rtableid = yystack.l_mark[-1].v.filter_opts.rtableid;
+
+ if (yystack.l_mark[-1].v.filter_opts.tag)
+ if (strlcpy(r.tagname, yystack.l_mark[-1].v.filter_opts.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.filter_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not;
+ if (rule_label(&r, yystack.l_mark[-1].v.filter_opts.label))
+ YYERROR;
+ free(yystack.l_mark[-1].v.filter_opts.label);
+ r.flags = yystack.l_mark[-1].v.filter_opts.flags.b1;
+ r.flagset = yystack.l_mark[-1].v.filter_opts.flags.b2;
+ if ((yystack.l_mark[-1].v.filter_opts.flags.b1 & yystack.l_mark[-1].v.filter_opts.flags.b2) != yystack.l_mark[-1].v.filter_opts.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2 || yystack.l_mark[-2].v.fromto.src_os) {
+ for (proto = yystack.l_mark[-3].v.proto; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && yystack.l_mark[-3].v.proto != NULL) {
+ if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if (yystack.l_mark[-2].v.fromto.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "applies to tcp");
+ YYERROR;
+ }
+ }
+
+ r.tos = yystack.l_mark[-1].v.filter_opts.tos;
+
+ if (yystack.l_mark[-1].v.filter_opts.keep.action) {
+ yyerror("cannot specify state handling "
+ "on anchors");
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-1].v.filter_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not;
+ if (yystack.l_mark[-1].v.filter_opts.marker & FOM_PRIO) {
+ if (yystack.l_mark[-1].v.filter_opts.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = yystack.l_mark[-1].v.filter_opts.prio;
+ }
+ if (yystack.l_mark[-1].v.filter_opts.marker & FOM_SETPRIO) {
+ r.set_prio[0] = yystack.l_mark[-1].v.filter_opts.set_prio[0];
+ r.set_prio[1] = yystack.l_mark[-1].v.filter_opts.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ decide_address_family(yystack.l_mark[-2].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-2].v.fromto.dst.host, &r.af);
+
+ expand_rule(&r, yystack.l_mark[-5].v.interface, NULL, yystack.l_mark[-3].v.proto, yystack.l_mark[-2].v.fromto.src_os,
+ yystack.l_mark[-2].v.fromto.src.host, yystack.l_mark[-2].v.fromto.src.port, yystack.l_mark[-2].v.fromto.dst.host, yystack.l_mark[-2].v.fromto.dst.port,
+ yystack.l_mark[-1].v.filter_opts.uid, yystack.l_mark[-1].v.filter_opts.gid, yystack.l_mark[-1].v.filter_opts.icmpspec,
+ pf->astack[pf->asd + 1] ? pf->alast->name : yystack.l_mark[-8].v.string);
+ free(yystack.l_mark[-8].v.string);
+ pf->astack[pf->asd + 1] = NULL;
+ }
+break;
+case 61:
+#line 935 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free(yystack.l_mark[-5].v.string);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_NAT;
+ r.af = yystack.l_mark[-3].v.i;
+ r.rtableid = yystack.l_mark[0].v.rtableid;
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ 0, 0, 0, yystack.l_mark[-5].v.string);
+ free(yystack.l_mark[-5].v.string);
+ }
+break;
+case 62:
+#line 956 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free(yystack.l_mark[-5].v.string);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_RDR;
+ r.af = yystack.l_mark[-3].v.i;
+ r.rtableid = yystack.l_mark[0].v.rtableid;
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ if (yystack.l_mark[-1].v.fromto.src.port != NULL) {
+ yyerror("source port parameter not supported"
+ " in rdr-anchor");
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.fromto.dst.port != NULL) {
+ if (yystack.l_mark[-1].v.fromto.dst.port->next != NULL) {
+ yyerror("destination port list "
+ "expansion not supported in "
+ "rdr-anchor");
+ YYERROR;
+ } else if (yystack.l_mark[-1].v.fromto.dst.port->op != PF_OP_EQ) {
+ yyerror("destination port operators"
+ " not supported in rdr-anchor");
+ YYERROR;
+ }
+ r.dst.port[0] = yystack.l_mark[-1].v.fromto.dst.port->port[0];
+ r.dst.port[1] = yystack.l_mark[-1].v.fromto.dst.port->port[1];
+ r.dst.port_op = yystack.l_mark[-1].v.fromto.dst.port->op;
+ }
+
+ expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ 0, 0, 0, yystack.l_mark[-5].v.string);
+ free(yystack.l_mark[-5].v.string);
+ }
+break;
+case 63:
+#line 998 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free(yystack.l_mark[-5].v.string);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_BINAT;
+ r.af = yystack.l_mark[-3].v.i;
+ r.rtableid = yystack.l_mark[0].v.rtableid;
+ if (yystack.l_mark[-2].v.proto != NULL) {
+ if (yystack.l_mark[-2].v.proto->next != NULL) {
+ yyerror("proto list expansion"
+ " not supported in binat-anchor");
+ YYERROR;
+ }
+ r.proto = yystack.l_mark[-2].v.proto->proto;
+ free(yystack.l_mark[-2].v.proto);
+ }
+
+ if (yystack.l_mark[-1].v.fromto.src.host != NULL || yystack.l_mark[-1].v.fromto.src.port != NULL ||
+ yystack.l_mark[-1].v.fromto.dst.host != NULL || yystack.l_mark[-1].v.fromto.dst.port != NULL) {
+ yyerror("fromto parameter not supported"
+ " in binat-anchor");
+ YYERROR;
+ }
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ pfctl_add_rule(pf, &r, yystack.l_mark[-5].v.string);
+ free(yystack.l_mark[-5].v.string);
+ }
+break;
+case 64:
+#line 1035 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct loadanchors *loadanchor;
+
+ if (strlen(pf->anchor->name) + 1 +
+ strlen(yystack.l_mark[-2].v.string) >= MAXPATHLEN) {
+ yyerror("anchorname %s too long, max %u\n",
+ yystack.l_mark[-2].v.string, MAXPATHLEN - 1);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ loadanchor = calloc(1, sizeof(struct loadanchors));
+ if (loadanchor == NULL)
+ err(1, "loadrule: calloc");
+ if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
+ NULL)
+ err(1, "loadrule: malloc");
+ if (pf->anchor->name[0])
+ snprintf(loadanchor->anchorname, MAXPATHLEN,
+ "%s/%s", pf->anchor->name, yystack.l_mark[-2].v.string);
+ else
+ strlcpy(loadanchor->anchorname, yystack.l_mark[-2].v.string, MAXPATHLEN);
+ if ((loadanchor->filename = strdup(yystack.l_mark[0].v.string)) == NULL)
+ err(1, "loadrule: strdup");
+
+ TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
+ entries);
+
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 65:
+#line 1066 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = yyval.v.b.w = 0;
+ if (yystack.l_mark[-1].v.i)
+ yyval.v.b.b1 = PF_NOSCRUB;
+ else
+ yyval.v.b.b1 = PF_SCRUB;
+ }
+break;
+case 66:
+#line 1076 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_SCRUB))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = yystack.l_mark[-7].v.b.b1;
+ r.direction = yystack.l_mark[-6].v.i;
+
+ r.log = yystack.l_mark[-5].v.logquick.log;
+ r.logif = yystack.l_mark[-5].v.logquick.logif;
+ if (yystack.l_mark[-5].v.logquick.quick) {
+ yyerror("scrub rules do not support 'quick'");
+ YYERROR;
+ }
+
+ r.af = yystack.l_mark[-3].v.i;
+ if (yystack.l_mark[0].v.scrub_opts.nodf)
+ r.rule_flag |= PFRULE_NODF;
+ if (yystack.l_mark[0].v.scrub_opts.randomid)
+ r.rule_flag |= PFRULE_RANDOMID;
+ if (yystack.l_mark[0].v.scrub_opts.reassemble_tcp) {
+ if (r.direction != PF_INOUT) {
+ yyerror("reassemble tcp rules can not "
+ "specify direction");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_REASSEMBLE_TCP;
+ }
+ if (yystack.l_mark[0].v.scrub_opts.minttl)
+ r.min_ttl = yystack.l_mark[0].v.scrub_opts.minttl;
+ if (yystack.l_mark[0].v.scrub_opts.maxmss)
+ r.max_mss = yystack.l_mark[0].v.scrub_opts.maxmss;
+ if (yystack.l_mark[0].v.scrub_opts.marker & SOM_SETTOS) {
+ r.rule_flag |= PFRULE_SET_TOS;
+ r.set_tos = yystack.l_mark[0].v.scrub_opts.settos;
+ }
+ if (yystack.l_mark[0].v.scrub_opts.fragcache)
+ r.rule_flag |= yystack.l_mark[0].v.scrub_opts.fragcache;
+ if (yystack.l_mark[0].v.scrub_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[0].v.scrub_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[0].v.scrub_opts.match_tag_not;
+ r.rtableid = yystack.l_mark[0].v.scrub_opts.rtableid;
+
+ expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ NULL, NULL, NULL, "");
+ }
+break;
+case 67:
+#line 1133 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ }
+break;
+case 68:
+#line 1138 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.scrub_opts = scrub_opts; }
+break;
+case 69:
+#line 1139 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ yyval.v.scrub_opts = scrub_opts;
+ }
+break;
+case 72:
+#line 1150 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.nodf) {
+ yyerror("no-df cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.nodf = 1;
+ }
+break;
+case 73:
+#line 1157 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_MINTTL) {
+ yyerror("min-ttl cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal min-ttl value %d", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MINTTL;
+ scrub_opts.minttl = yystack.l_mark[0].v.number;
+ }
+break;
+case 74:
+#line 1169 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_MAXMSS) {
+ yyerror("max-mss cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) {
+ yyerror("illegal max-mss value %d", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MAXMSS;
+ scrub_opts.maxmss = yystack.l_mark[0].v.number;
+ }
+break;
+case 75:
+#line 1181 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_SETTOS) {
+ yyerror("set-tos cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_SETTOS;
+ scrub_opts.settos = yystack.l_mark[0].v.number;
+ }
+break;
+case 76:
+#line 1189 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_FRAGCACHE) {
+ yyerror("fragcache cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_FRAGCACHE;
+ scrub_opts.fragcache = yystack.l_mark[0].v.i;
+ }
+break;
+case 77:
+#line 1197 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (strcasecmp(yystack.l_mark[0].v.string, "tcp") != 0) {
+ yyerror("scrub reassemble supports only tcp, "
+ "not '%s'", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ if (scrub_opts.reassemble_tcp) {
+ yyerror("reassemble tcp cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.reassemble_tcp = 1;
+ }
+break;
+case 78:
+#line 1211 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.randomid) {
+ yyerror("random-id cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.randomid = 1;
+ }
+break;
+case 79:
+#line 1218 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ scrub_opts.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 80:
+#line 1225 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ scrub_opts.match_tag = yystack.l_mark[0].v.string;
+ scrub_opts.match_tag_not = yystack.l_mark[-2].v.number;
+ }
+break;
+case 81:
+#line 1231 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; /* default */ }
+break;
+case 82:
+#line 1232 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 83:
+#line 1233 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 84:
+#line 1236 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+ struct node_host *h = NULL, *hh;
+ struct node_if *i, *j;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ for (i = yystack.l_mark[-2].v.interface; i; i = i->next) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = yystack.l_mark[-3].v.logquick.log;
+ r.logif = yystack.l_mark[-3].v.logquick.logif;
+ r.quick = yystack.l_mark[-3].v.logquick.quick;
+ r.af = yystack.l_mark[-1].v.i;
+ if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label))
+ YYERROR;
+ r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid;
+ j = calloc(1, sizeof(struct node_if));
+ if (j == NULL)
+ err(1, "antispoof: calloc");
+ if (strlcpy(j->ifname, i->ifname,
+ sizeof(j->ifname)) >= sizeof(j->ifname)) {
+ free(j);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ j->not = 1;
+ if (i->dynamic) {
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->addr.type = PF_ADDR_DYNIFTL;
+ set_ipmask(h, 128);
+ if (strlcpy(h->addr.v.ifname, i->ifname,
+ sizeof(h->addr.v.ifname)) >=
+ sizeof(h->addr.v.ifname)) {
+ free(h);
+ yyerror(
+ "interface name too long");
+ YYERROR;
+ }
+ hh = malloc(sizeof(*hh));
+ if (hh == NULL)
+ err(1, "address: malloc");
+ bcopy(h, hh, sizeof(*hh));
+ h->addr.iflags = PFI_AFLAG_NETWORK;
+ } else {
+ h = ifa_lookup(j->ifname,
+ PFI_AFLAG_NETWORK);
+ hh = NULL;
+ }
+
+ if (h != NULL)
+ expand_rule(&r, j, NULL, NULL, NULL, h,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, "");
+
+ if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = yystack.l_mark[-3].v.logquick.log;
+ r.logif = yystack.l_mark[-3].v.logquick.logif;
+ r.quick = yystack.l_mark[-3].v.logquick.quick;
+ r.af = yystack.l_mark[-1].v.i;
+ if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label))
+ YYERROR;
+ r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid;
+ if (hh != NULL)
+ h = hh;
+ else
+ h = ifa_lookup(i->ifname, 0);
+ if (h != NULL)
+ expand_rule(&r, NULL, NULL,
+ NULL, NULL, h, NULL, NULL,
+ NULL, NULL, NULL, NULL, "");
+ } else
+ free(hh);
+ }
+ free(yystack.l_mark[0].v.antispoof_opts.label);
+ }
+break;
+case 85:
+#line 1323 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; }
+break;
+case 86:
+#line 1324 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 87:
+#line 1327 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 88:
+#line 1328 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface;
+ yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface;
+ yyval.v.interface = yystack.l_mark[-3].v.interface;
+ }
+break;
+case 89:
+#line 1335 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; }
+break;
+case 90:
+#line 1336 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-1].v.interface->dynamic = 1;
+ yyval.v.interface = yystack.l_mark[-1].v.interface;
+ }
+break;
+case 91:
+#line 1342 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ }
+break;
+case 92:
+#line 1347 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.antispoof_opts = antispoof_opts; }
+break;
+case 93:
+#line 1348 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ yyval.v.antispoof_opts = antispoof_opts;
+ }
+break;
+case 96:
+#line 1359 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (antispoof_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ antispoof_opts.label = yystack.l_mark[0].v.string;
+ }
+break;
+case 97:
+#line 1366 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ antispoof_opts.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 98:
+#line 1375 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number = 1; }
+break;
+case 99:
+#line 1376 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number = 0; }
+break;
+case 100:
+#line 1379 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *h, *nh;
+ struct node_tinit *ti, *nti;
+
+ if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name too long, max %d chars",
+ PF_TABLE_NAME_SIZE - 1);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ if (pf->loadopt & PFCTL_FLAG_TABLE)
+ if (process_tabledef(yystack.l_mark[-2].v.string, &yystack.l_mark[0].v.table_opts)) {
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-2].v.string);
+ for (ti = SIMPLEQ_FIRST(&yystack.l_mark[0].v.table_opts.init_nodes);
+ ti != SIMPLEQ_END(&yystack.l_mark[0].v.table_opts.init_nodes); ti = nti) {
+ if (ti->file)
+ free(ti->file);
+ for (h = ti->host; h != NULL; h = nh) {
+ nh = h->next;
+ free(h);
+ }
+ nti = SIMPLEQ_NEXT(ti, entries);
+ free(ti);
+ }
+ }
+break;
+case 101:
+#line 1409 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ }
+break;
+case 102:
+#line 1414 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.table_opts = table_opts; }
+break;
+case 103:
+#line 1416 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ yyval.v.table_opts = table_opts;
+ }
+break;
+case 106:
+#line 1427 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "const"))
+ table_opts.flags |= PFR_TFLAG_CONST;
+ else if (!strcmp(yystack.l_mark[0].v.string, "persist"))
+ table_opts.flags |= PFR_TFLAG_PERSIST;
+ else if (!strcmp(yystack.l_mark[0].v.string, "counters"))
+ table_opts.flags |= PFR_TFLAG_COUNTERS;
+ else {
+ yyerror("invalid table option '%s'", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 107:
+#line 1441 "../../freebsd/sbin/pfctl/parse.y"
+ { table_opts.init_addr = 1; }
+break;
+case 108:
+#line 1442 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+ struct node_tinit *ti;
+
+ for (n = yystack.l_mark[-1].v.host; n != NULL; n = n->next) {
+ switch (n->addr.type) {
+ case PF_ADDR_ADDRMASK:
+ continue; /* ok */
+ case PF_ADDR_RANGE:
+ yyerror("address ranges are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_DYNIFTL:
+ yyerror("dynamic addresses are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_TABLE:
+ yyerror("tables cannot contain tables");
+ break;
+ case PF_ADDR_NOROUTE:
+ yyerror("\"no-route\" is not permitted "
+ "inside tables");
+ break;
+ case PF_ADDR_URPFFAILED:
+ yyerror("\"urpf-failed\" is not "
+ "permitted inside tables");
+ break;
+ default:
+ yyerror("unknown address type %d",
+ n->addr.type);
+ }
+ YYERROR;
+ }
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->host = yystack.l_mark[-1].v.host;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+break;
+case 109:
+#line 1482 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_tinit *ti;
+
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->file = yystack.l_mark[0].v.string;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+break;
+case 110:
+#line 1494 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE))
+ YYERROR;
+
+ memset(&a, 0, sizeof(a));
+ if (yystack.l_mark[-2].v.queue_opts.scheduler.qtype == ALTQT_NONE) {
+ yyerror("no scheduler specified!");
+ YYERROR;
+ }
+ a.scheduler = yystack.l_mark[-2].v.queue_opts.scheduler.qtype;
+ a.qlimit = yystack.l_mark[-2].v.queue_opts.qlimit;
+ a.tbrsize = yystack.l_mark[-2].v.queue_opts.tbrsize;
+ if (yystack.l_mark[0].v.queue == NULL && yystack.l_mark[-2].v.queue_opts.scheduler.qtype != ALTQT_CODEL) {
+ yyerror("no child queues specified");
+ YYERROR;
+ }
+ if (expand_altq(&a, yystack.l_mark[-3].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-2].v.queue_opts.queue_bwspec,
+ &yystack.l_mark[-2].v.queue_opts.scheduler))
+ YYERROR;
+ }
+break;
+case 111:
+#line 1518 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE)) {
+ free(yystack.l_mark[-3].v.string);
+ YYERROR;
+ }
+
+ memset(&a, 0, sizeof(a));
+
+ if (strlcpy(a.qname, yystack.l_mark[-3].v.string, sizeof(a.qname)) >=
+ sizeof(a.qname)) {
+ yyerror("queue name too long (max "
+ "%d chars)", PF_QNAME_SIZE-1);
+ free(yystack.l_mark[-3].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-3].v.string);
+ if (yystack.l_mark[-1].v.queue_opts.tbrsize) {
+ yyerror("cannot specify tbrsize for queue");
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.queue_opts.priority > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ a.priority = yystack.l_mark[-1].v.queue_opts.priority;
+ a.qlimit = yystack.l_mark[-1].v.queue_opts.qlimit;
+ a.scheduler = yystack.l_mark[-1].v.queue_opts.scheduler.qtype;
+ if (expand_queue(&a, yystack.l_mark[-2].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-1].v.queue_opts.queue_bwspec,
+ &yystack.l_mark[-1].v.queue_opts.scheduler)) {
+ yyerror("errors in queue definition");
+ YYERROR;
+ }
+ }
+break;
+case 112:
+#line 1555 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ }
+break;
+case 113:
+#line 1563 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue_opts = queue_opts; }
+break;
+case 114:
+#line 1564 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ yyval.v.queue_opts = queue_opts;
+ }
+break;
+case 117:
+#line 1578 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_BWSPEC) {
+ yyerror("bandwidth cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_BWSPEC;
+ queue_opts.queue_bwspec = yystack.l_mark[0].v.queue_bwspec;
+ }
+break;
+case 118:
+#line 1586 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_PRIORITY) {
+ yyerror("priority cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_PRIORITY;
+ queue_opts.priority = yystack.l_mark[0].v.number;
+ }
+break;
+case 119:
+#line 1598 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_QLIMIT) {
+ yyerror("qlimit cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) {
+ yyerror("qlimit out of range: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_QLIMIT;
+ queue_opts.qlimit = yystack.l_mark[0].v.number;
+ }
+break;
+case 120:
+#line 1610 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_SCHEDULER) {
+ yyerror("scheduler cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_SCHEDULER;
+ queue_opts.scheduler = yystack.l_mark[0].v.queue_options;
+ }
+break;
+case 121:
+#line 1618 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_TBRSIZE) {
+ yyerror("tbrsize cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) {
+ yyerror("tbrsize too big: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_TBRSIZE;
+ queue_opts.tbrsize = yystack.l_mark[0].v.number;
+ }
+break;
+case 122:
+#line 1632 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ double bps;
+ char *cp;
+
+ yyval.v.queue_bwspec.bw_percent = 0;
+
+ bps = strtod(yystack.l_mark[0].v.string, &cp);
+ if (cp != NULL) {
+ if (strlen(cp) > 1) {
+ char *cu = cp + 1;
+ if (!strcmp(cu, "Bit") ||
+ !strcmp(cu, "B") ||
+ !strcmp(cu, "bit") ||
+ !strcmp(cu, "b")) {
+ *cu = 0;
+ }
+ }
+ if (!strcmp(cp, "b"))
+ ; /* nothing */
+ else if (!strcmp(cp, "K"))
+ bps *= 1000;
+ else if (!strcmp(cp, "M"))
+ bps *= 1000 * 1000;
+ else if (!strcmp(cp, "G"))
+ bps *= 1000 * 1000 * 1000;
+ else if (!strcmp(cp, "%")) {
+ if (bps < 0 || bps > 100) {
+ yyerror("bandwidth spec "
+ "out of range");
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.queue_bwspec.bw_percent = bps;
+ bps = 0;
+ } else {
+ yyerror("unknown unit %s", cp);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.queue_bwspec.bw_absolute = (u_int32_t)bps;
+ }
+break;
+case 123:
+#line 1675 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("bandwidth number too big");
+ YYERROR;
+ }
+ yyval.v.queue_bwspec.bw_percent = 0;
+ yyval.v.queue_bwspec.bw_absolute = yystack.l_mark[0].v.number;
+ }
+break;
+case 124:
+#line 1685 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CBQ;
+ yyval.v.queue_options.data.cbq_opts.flags = 0;
+ }
+break;
+case 125:
+#line 1689 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CBQ;
+ yyval.v.queue_options.data.cbq_opts.flags = yystack.l_mark[-1].v.number;
+ }
+break;
+case 126:
+#line 1693 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_PRIQ;
+ yyval.v.queue_options.data.priq_opts.flags = 0;
+ }
+break;
+case 127:
+#line 1697 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_PRIQ;
+ yyval.v.queue_options.data.priq_opts.flags = yystack.l_mark[-1].v.number;
+ }
+break;
+case 128:
+#line 1701 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_HFSC;
+ bzero(&yyval.v.queue_options.data.hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+break;
+case 129:
+#line 1706 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_HFSC;
+ yyval.v.queue_options.data.hfsc_opts = yystack.l_mark[-1].v.hfsc_opts;
+ }
+break;
+case 130:
+#line 1710 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_FAIRQ;
+ bzero(&yyval.v.queue_options.data.fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+break;
+case 131:
+#line 1715 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_FAIRQ;
+ yyval.v.queue_options.data.fairq_opts = yystack.l_mark[-1].v.fairq_opts;
+ }
+break;
+case 132:
+#line 1719 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CODEL;
+ bzero(&yyval.v.queue_options.data.codel_opts,
+ sizeof(struct codel_opts));
+ }
+break;
+case 133:
+#line 1724 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CODEL;
+ yyval.v.queue_options.data.codel_opts = yystack.l_mark[-1].v.codel_opts;
+ }
+break;
+case 134:
+#line 1730 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 135:
+#line 1731 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 136:
+#line 1734 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ yyval.v.number = CBQCLF_DEFCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "borrow"))
+ yyval.v.number = CBQCLF_BORROW;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ yyval.v.number = CBQCLF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ yyval.v.number = CBQCLF_RED|CBQCLF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ yyval.v.number = CBQCLF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ yyval.v.number = CBQCLF_CODEL;
+ else {
+ yyerror("unknown cbq flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 137:
+#line 1756 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 138:
+#line 1757 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 139:
+#line 1760 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ yyval.v.number = PRCF_DEFAULTCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ yyval.v.number = PRCF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ yyval.v.number = PRCF_RED|PRCF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ yyval.v.number = PRCF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ yyval.v.number = PRCF_CODEL;
+ else {
+ yyerror("unknown priq flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 140:
+#line 1780 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+break;
+case 141:
+#line 1784 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.hfsc_opts = hfsc_opts;
+ }
+break;
+case 144:
+#line 1793 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m2 = yystack.l_mark[0].v.queue_bwspec;
+ hfsc_opts.linkshare.used = 1;
+ }
+break;
+case 145:
+#line 1802 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m1 = yystack.l_mark[-5].v.queue_bwspec;
+ hfsc_opts.linkshare.d = yystack.l_mark[-3].v.number;
+ hfsc_opts.linkshare.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ hfsc_opts.linkshare.used = 1;
+ }
+break;
+case 146:
+#line 1816 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m2 = yystack.l_mark[0].v.queue_bwspec;
+ hfsc_opts.realtime.used = 1;
+ }
+break;
+case 147:
+#line 1825 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m1 = yystack.l_mark[-5].v.queue_bwspec;
+ hfsc_opts.realtime.d = yystack.l_mark[-3].v.number;
+ hfsc_opts.realtime.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ hfsc_opts.realtime.used = 1;
+ }
+break;
+case 148:
+#line 1839 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m2 = yystack.l_mark[0].v.queue_bwspec;
+ hfsc_opts.upperlimit.used = 1;
+ }
+break;
+case 149:
+#line 1848 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m1 = yystack.l_mark[-5].v.queue_bwspec;
+ hfsc_opts.upperlimit.d = yystack.l_mark[-3].v.number;
+ hfsc_opts.upperlimit.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ hfsc_opts.upperlimit.used = 1;
+ }
+break;
+case 150:
+#line 1862 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ hfsc_opts.flags |= HFCF_DEFAULTCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ hfsc_opts.flags |= HFCF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ hfsc_opts.flags |= HFCF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ hfsc_opts.flags |= HFCF_CODEL;
+ else {
+ yyerror("unknown hfsc flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 151:
+#line 1882 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+break;
+case 152:
+#line 1886 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.fairq_opts = fairq_opts;
+ }
+break;
+case 155:
+#line 1895 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m2 = yystack.l_mark[0].v.queue_bwspec;
+ fairq_opts.linkshare.used = 1;
+ }
+break;
+case 156:
+#line 1903 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m1 = yystack.l_mark[-3].v.queue_bwspec;
+ fairq_opts.linkshare.d = yystack.l_mark[-2].v.number;
+ fairq_opts.linkshare.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ fairq_opts.linkshare.used = 1;
+ }
+break;
+case 157:
+#line 1913 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ fairq_opts.hogs_bw = yystack.l_mark[0].v.queue_bwspec;
+ }
+break;
+case 158:
+#line 1916 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ fairq_opts.nbuckets = yystack.l_mark[0].v.number;
+ }
+break;
+case 159:
+#line 1919 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ fairq_opts.flags |= FARF_DEFAULTCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ fairq_opts.flags |= FARF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ fairq_opts.flags |= FARF_RED|FARF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ fairq_opts.flags |= FARF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ fairq_opts.flags |= FARF_CODEL;
+ else {
+ yyerror("unknown fairq flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 160:
+#line 1939 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&codel_opts,
+ sizeof(struct codel_opts));
+ }
+break;
+case 161:
+#line 1943 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.codel_opts = codel_opts;
+ }
+break;
+case 164:
+#line 1952 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (codel_opts.interval) {
+ yyerror("interval already specified");
+ YYERROR;
+ }
+ codel_opts.interval = yystack.l_mark[0].v.number;
+ }
+break;
+case 165:
+#line 1959 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (codel_opts.target) {
+ yyerror("target already specified");
+ YYERROR;
+ }
+ codel_opts.target = yystack.l_mark[0].v.number;
+ }
+break;
+case 166:
+#line 1966 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ codel_opts.ecn = 1;
+ else {
+ yyerror("unknown codel option \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 167:
+#line 1978 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = NULL; }
+break;
+case 168:
+#line 1979 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = yystack.l_mark[0].v.queue; }
+break;
+case 169:
+#line 1980 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = yystack.l_mark[-1].v.queue; }
+break;
+case 170:
+#line 1983 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = yystack.l_mark[-1].v.queue; }
+break;
+case 171:
+#line 1984 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.queue->tail->next = yystack.l_mark[-1].v.queue;
+ yystack.l_mark[-3].v.queue->tail = yystack.l_mark[-1].v.queue;
+ yyval.v.queue = yystack.l_mark[-3].v.queue;
+ }
+break;
+case 172:
+#line 1991 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue = calloc(1, sizeof(struct node_queue));
+ if (yyval.v.queue == NULL)
+ err(1, "qassign_item: calloc");
+ if (strlcpy(yyval.v.queue->queue, yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)) >=
+ sizeof(yyval.v.queue->queue)) {
+ yyerror("queue name '%s' too long (max "
+ "%d chars)", yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)-1);
+ free(yystack.l_mark[0].v.string);
+ free(yyval.v.queue);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.queue->next = NULL;
+ yyval.v.queue->tail = yyval.v.queue;
+ }
+break;
+case 173:
+#line 2011 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+ struct node_state_opt *o;
+ struct node_proto *proto;
+ int srctrack = 0;
+ int statelock = 0;
+ int adaptive = 0;
+ int defaults = 0;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = yystack.l_mark[-8].v.b.b1;
+ switch (yystack.l_mark[-8].v.b.b2) {
+ case PFRULE_RETURNRST:
+ r.rule_flag |= PFRULE_RETURNRST;
+ r.return_ttl = yystack.l_mark[-8].v.b.w;
+ break;
+ case PFRULE_RETURNICMP:
+ r.rule_flag |= PFRULE_RETURNICMP;
+ r.return_icmp = yystack.l_mark[-8].v.b.w;
+ r.return_icmp6 = yystack.l_mark[-8].v.b.w2;
+ break;
+ case PFRULE_RETURN:
+ r.rule_flag |= PFRULE_RETURN;
+ r.return_icmp = yystack.l_mark[-8].v.b.w;
+ r.return_icmp6 = yystack.l_mark[-8].v.b.w2;
+ break;
+ }
+ r.direction = yystack.l_mark[-7].v.i;
+ r.log = yystack.l_mark[-6].v.logquick.log;
+ r.logif = yystack.l_mark[-6].v.logquick.logif;
+ r.quick = yystack.l_mark[-6].v.logquick.quick;
+ r.prob = yystack.l_mark[0].v.filter_opts.prob;
+ r.rtableid = yystack.l_mark[0].v.filter_opts.rtableid;
+
+ if (yystack.l_mark[0].v.filter_opts.marker & FOM_PRIO) {
+ if (yystack.l_mark[0].v.filter_opts.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = yystack.l_mark[0].v.filter_opts.prio;
+ }
+ if (yystack.l_mark[0].v.filter_opts.marker & FOM_SETPRIO) {
+ r.set_prio[0] = yystack.l_mark[0].v.filter_opts.set_prio[0];
+ r.set_prio[1] = yystack.l_mark[0].v.filter_opts.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ r.af = yystack.l_mark[-3].v.i;
+ if (yystack.l_mark[0].v.filter_opts.tag)
+ if (strlcpy(r.tagname, yystack.l_mark[0].v.filter_opts.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.filter_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[0].v.filter_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[0].v.filter_opts.match_tag_not;
+ if (rule_label(&r, yystack.l_mark[0].v.filter_opts.label))
+ YYERROR;
+ free(yystack.l_mark[0].v.filter_opts.label);
+ r.flags = yystack.l_mark[0].v.filter_opts.flags.b1;
+ r.flagset = yystack.l_mark[0].v.filter_opts.flags.b2;
+ if ((yystack.l_mark[0].v.filter_opts.flags.b1 & yystack.l_mark[0].v.filter_opts.flags.b2) != yystack.l_mark[0].v.filter_opts.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2 || yystack.l_mark[-1].v.fromto.src_os) {
+ for (proto = yystack.l_mark[-2].v.proto; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && yystack.l_mark[-2].v.proto != NULL) {
+ if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if (yystack.l_mark[-1].v.fromto.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "apply to tcp");
+ YYERROR;
+ }
+#if 0
+ if ((yystack.l_mark[0].v.filter_opts.flags.b1 & parse_flags("S")) == 0 &&
+ yystack.l_mark[-1].v.fromto.src_os) {
+ yyerror("OS fingerprinting requires "
+ "the SYN TCP flag (flags S/SA)");
+ YYERROR;
+ }
+#endif
+ }
+
+ r.tos = yystack.l_mark[0].v.filter_opts.tos;
+ r.keep_state = yystack.l_mark[0].v.filter_opts.keep.action;
+ o = yystack.l_mark[0].v.filter_opts.keep.options;
+
+ /* 'keep state' by default on pass rules. */
+ if (!r.keep_state && !r.action &&
+ !(yystack.l_mark[0].v.filter_opts.marker & FOM_KEEP)) {
+ r.keep_state = PF_STATE_NORMAL;
+ o = keep_state_defaults;
+ defaults = 1;
+ }
+
+ while (o) {
+ struct node_state_opt *p = o;
+
+ switch (o->type) {
+ case PF_STATE_OPT_MAX:
+ if (r.max_states) {
+ yyerror("state option 'max' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.max_states = o->data.max_states;
+ break;
+ case PF_STATE_OPT_NOSYNC:
+ if (r.rule_flag & PFRULE_NOSYNC) {
+ yyerror("state option 'sync' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_NOSYNC;
+ break;
+ case PF_STATE_OPT_SRCTRACK:
+ if (srctrack) {
+ yyerror("state option "
+ "'source-track' "
+ "multiple definitions");
+ YYERROR;
+ }
+ srctrack = o->data.src_track;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_STATES:
+ if (r.max_src_states) {
+ yyerror("state option "
+ "'max-src-states' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_states == 0) {
+ yyerror("'max-src-states' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_states =
+ o->data.max_src_states;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_OVERLOAD:
+ if (r.overload_tblname[0]) {
+ yyerror("multiple 'overload' "
+ "table definitions");
+ YYERROR;
+ }
+ if (strlcpy(r.overload_tblname,
+ o->data.overload.tblname,
+ PF_TABLE_NAME_SIZE) >=
+ PF_TABLE_NAME_SIZE) {
+ yyerror("state option: "
+ "strlcpy");
+ YYERROR;
+ }
+ r.flush = o->data.overload.flush;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN:
+ if (r.max_src_conn) {
+ yyerror("state option "
+ "'max-src-conn' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_conn == 0) {
+ yyerror("'max-src-conn' "
+ "must be > 0");
+ YYERROR;
+ }
+ r.max_src_conn =
+ o->data.max_src_conn;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN_RATE:
+ if (r.max_src_conn_rate.limit) {
+ yyerror("state option "
+ "'max-src-conn-rate' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (!o->data.max_src_conn_rate.limit ||
+ !o->data.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' "
+ "values must be > 0");
+ YYERROR;
+ }
+ if (o->data.max_src_conn_rate.limit >
+ PF_THRESHOLD_MAX) {
+ yyerror("'max-src-conn-rate' "
+ "maximum rate must be < %u",
+ PF_THRESHOLD_MAX);
+ YYERROR;
+ }
+ r.max_src_conn_rate.limit =
+ o->data.max_src_conn_rate.limit;
+ r.max_src_conn_rate.seconds =
+ o->data.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_NODES:
+ if (r.max_src_nodes) {
+ yyerror("state option "
+ "'max-src-nodes' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_nodes == 0) {
+ yyerror("'max-src-nodes' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_nodes =
+ o->data.max_src_nodes;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_STATELOCK:
+ if (statelock) {
+ yyerror("state locking option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ statelock = 1;
+ r.rule_flag |= o->data.statelock;
+ break;
+ case PF_STATE_OPT_SLOPPY:
+ if (r.rule_flag & PFRULE_STATESLOPPY) {
+ yyerror("state sloppy option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_STATESLOPPY;
+ break;
+ case PF_STATE_OPT_TIMEOUT:
+ if (o->data.timeout.number ==
+ PFTM_ADAPTIVE_START ||
+ o->data.timeout.number ==
+ PFTM_ADAPTIVE_END)
+ adaptive = 1;
+ if (r.timeout[o->data.timeout.number]) {
+ yyerror("state timeout %s "
+ "multiple definitions",
+ pf_timeouts[o->data.
+ timeout.number].name);
+ YYERROR;
+ }
+ r.timeout[o->data.timeout.number] =
+ o->data.timeout.seconds;
+ }
+ o = o->next;
+ if (!defaults)
+ free(p);
+ }
+
+ /* 'flags S/SA' by default on stateful rules */
+ if (!r.action && !r.flags && !r.flagset &&
+ !yystack.l_mark[0].v.filter_opts.fragment && !(yystack.l_mark[0].v.filter_opts.marker & FOM_FLAGS) &&
+ r.keep_state) {
+ r.flags = parse_flags("S");
+ r.flagset = parse_flags("SA");
+ }
+ if (!adaptive && r.max_states) {
+ r.timeout[PFTM_ADAPTIVE_START] =
+ (r.max_states / 10) * 6;
+ r.timeout[PFTM_ADAPTIVE_END] =
+ (r.max_states / 10) * 12;
+ }
+ if (r.rule_flag & PFRULE_SRCTRACK) {
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_nodes) {
+ yyerror("'max-src-nodes' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn) {
+ yyerror("'max-src-conn' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (r.timeout[PFTM_SRC_NODE] <
+ r.max_src_conn_rate.seconds)
+ r.timeout[PFTM_SRC_NODE] =
+ r.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ if (srctrack == PF_SRCTRACK_RULE)
+ r.rule_flag |= PFRULE_RULESRCTRACK;
+ }
+ if (r.keep_state && !statelock)
+ r.rule_flag |= default_statelock;
+
+ if (yystack.l_mark[0].v.filter_opts.fragment)
+ r.rule_flag |= PFRULE_FRAGMENT;
+ r.allow_opts = yystack.l_mark[0].v.filter_opts.allowopts;
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ if (yystack.l_mark[-4].v.route.rt) {
+ if (!r.direction) {
+ yyerror("direction must be explicit "
+ "with rules that specify routing");
+ YYERROR;
+ }
+ r.rt = yystack.l_mark[-4].v.route.rt;
+ r.rpool.opts = yystack.l_mark[-4].v.route.pool_opts;
+ if (yystack.l_mark[-4].v.route.key != NULL)
+ memcpy(&r.rpool.key, yystack.l_mark[-4].v.route.key,
+ sizeof(struct pf_poolhashkey));
+ }
+ if (r.rt && r.rt != PF_FASTROUTE) {
+ decide_address_family(yystack.l_mark[-4].v.route.host, &r.af);
+ remove_invalid_hosts(&yystack.l_mark[-4].v.route.host, &r.af);
+ if (yystack.l_mark[-4].v.route.host == NULL) {
+ yyerror("no routing address with "
+ "matching address family found.");
+ YYERROR;
+ }
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && (yystack.l_mark[-4].v.route.host->next != NULL ||
+ yystack.l_mark[-4].v.route.host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR(yystack.l_mark[-4].v.route.host->addr)))
+ r.rpool.opts |= PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table(yystack.l_mark[-4].v.route.host, "tables are only "
+ "supported in round-robin routing pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias(yystack.l_mark[-4].v.route.host, "interface (%s) "
+ "is only supported in round-robin "
+ "routing pools"))
+ YYERROR;
+ if (yystack.l_mark[-4].v.route.host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("r.rpool.opts must "
+ "be PF_POOL_ROUNDROBIN");
+ YYERROR;
+ }
+ }
+ }
+ if (yystack.l_mark[0].v.filter_opts.queues.qname != NULL) {
+ if (strlcpy(r.qname, yystack.l_mark[0].v.filter_opts.queues.qname,
+ sizeof(r.qname)) >= sizeof(r.qname)) {
+ yyerror("rule qname too long (max "
+ "%d chars)", sizeof(r.qname)-1);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.filter_opts.queues.qname);
+ }
+ if (yystack.l_mark[0].v.filter_opts.queues.pqname != NULL) {
+ if (strlcpy(r.pqname, yystack.l_mark[0].v.filter_opts.queues.pqname,
+ sizeof(r.pqname)) >= sizeof(r.pqname)) {
+ yyerror("rule pqname too long (max "
+ "%d chars)", sizeof(r.pqname)-1);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.filter_opts.queues.pqname);
+ }
+#ifdef __FreeBSD__
+ r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port;
+#else
+ if ((r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port)) {
+ if (r.direction == PF_OUT) {
+ if (yystack.l_mark[0].v.filter_opts.divert.addr) {
+ yyerror("address specified "
+ "for outgoing divert");
+ YYERROR;
+ }
+ bzero(&r.divert.addr,
+ sizeof(r.divert.addr));
+ } else {
+ if (!yystack.l_mark[0].v.filter_opts.divert.addr) {
+ yyerror("no address specified "
+ "for incoming divert");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.filter_opts.divert.addr->af != r.af) {
+ yyerror("address family "
+ "mismatch for divert");
+ YYERROR;
+ }
+ r.divert.addr =
+ yystack.l_mark[0].v.filter_opts.divert.addr->addr.v.a.addr;
+ }
+ }
+#endif
+
+ expand_rule(&r, yystack.l_mark[-5].v.interface, yystack.l_mark[-4].v.route.host, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ yystack.l_mark[0].v.filter_opts.uid, yystack.l_mark[0].v.filter_opts.gid, yystack.l_mark[0].v.filter_opts.icmpspec, "");
+ }
+break;
+case 174:
+#line 2435 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ }
+break;
+case 175:
+#line 2440 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.filter_opts = filter_opts; }
+break;
+case 176:
+#line 2441 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ yyval.v.filter_opts = filter_opts;
+ }
+break;
+case 179:
+#line 2452 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.uid)
+ yystack.l_mark[0].v.uid->tail->next = filter_opts.uid;
+ filter_opts.uid = yystack.l_mark[0].v.uid;
+ }
+break;
+case 180:
+#line 2457 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.gid)
+ yystack.l_mark[0].v.gid->tail->next = filter_opts.gid;
+ filter_opts.gid = yystack.l_mark[0].v.gid;
+ }
+break;
+case 181:
+#line 2462 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_FLAGS) {
+ yyerror("flags cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_FLAGS;
+ filter_opts.flags.b1 |= yystack.l_mark[0].v.b.b1;
+ filter_opts.flags.b2 |= yystack.l_mark[0].v.b.b2;
+ filter_opts.flags.w |= yystack.l_mark[0].v.b.w;
+ filter_opts.flags.w2 |= yystack.l_mark[0].v.b.w2;
+ }
+break;
+case 182:
+#line 2473 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_ICMP) {
+ yyerror("icmp-type cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_ICMP;
+ filter_opts.icmpspec = yystack.l_mark[0].v.icmp;
+ }
+break;
+case 183:
+#line 2481 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_PRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_PRIO;
+ filter_opts.prio = yystack.l_mark[0].v.number;
+ }
+break;
+case 184:
+#line 2493 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_TOS) {
+ yyerror("tos cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_TOS;
+ filter_opts.tos = yystack.l_mark[0].v.number;
+ }
+break;
+case 185:
+#line 2501 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_KEEP) {
+ yyerror("modulate or keep cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_KEEP;
+ filter_opts.keep.action = yystack.l_mark[0].v.keep_state.action;
+ filter_opts.keep.options = yystack.l_mark[0].v.keep_state.options;
+ }
+break;
+case 186:
+#line 2510 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.fragment = 1;
+ }
+break;
+case 187:
+#line 2513 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.allowopts = 1;
+ }
+break;
+case 188:
+#line 2516 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.label = yystack.l_mark[0].v.string;
+ }
+break;
+case 189:
+#line 2523 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.queues.qname) {
+ yyerror("queue cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.queues = yystack.l_mark[0].v.qassign;
+ }
+break;
+case 190:
+#line 2530 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.tag = yystack.l_mark[0].v.string;
+ }
+break;
+case 191:
+#line 2533 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.match_tag = yystack.l_mark[0].v.string;
+ filter_opts.match_tag_not = yystack.l_mark[-2].v.number;
+ }
+break;
+case 192:
+#line 2537 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ double p;
+
+ p = floor(yystack.l_mark[0].v.probability * UINT_MAX + 0.5);
+ if (p < 0.0 || p > UINT_MAX) {
+ yyerror("invalid probability: %lf", p);
+ YYERROR;
+ }
+ filter_opts.prob = (u_int32_t)p;
+ if (filter_opts.prob == 0)
+ filter_opts.prob = 1;
+ }
+break;
+case 193:
+#line 2549 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ filter_opts.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 194:
+#line 2556 "../../freebsd/sbin/pfctl/parse.y"
+ {
+#ifdef __FreeBSD__
+ filter_opts.divert.port = yystack.l_mark[0].v.range.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a));
+ YYERROR;
+ }
+#endif
+ }
+break;
+case 195:
+#line 2565 "../../freebsd/sbin/pfctl/parse.y"
+ {
+#ifndef __FreeBSD__
+ if ((filter_opts.divert.addr = host(yystack.l_mark[-2].v.string)) == NULL) {
+ yyerror("could not parse divert address: %s",
+ yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+#else
+ if (yystack.l_mark[-2].v.string)
+#endif
+ free(yystack.l_mark[-2].v.string);
+ filter_opts.divert.port = yystack.l_mark[0].v.range.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a));
+ YYERROR;
+ }
+ }
+break;
+case 196:
+#line 2583 "../../freebsd/sbin/pfctl/parse.y"
+ {
+#ifdef __FreeBSD__
+ yyerror("divert-reply has no meaning in FreeBSD pf(4)");
+ YYERROR;
+#else
+ filter_opts.divert.port = 1; /* some random value */
+#endif
+ }
+break;
+case 198:
+#line 2594 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.filter_opts = filter_opts; }
+break;
+case 199:
+#line 2595 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.filter_opts = filter_opts; }
+break;
+case 202:
+#line 2602 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_SETPRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_SETPRIO;
+ filter_opts.set_prio[0] = yystack.l_mark[0].v.b.b1;
+ filter_opts.set_prio[1] = yystack.l_mark[0].v.b.b2;
+ }
+break;
+case 203:
+#line 2611 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ yyval.v.b.b1 = yyval.v.b.b2 = yystack.l_mark[0].v.number;
+ }
+break;
+case 204:
+#line 2618 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > PF_PRIO_MAX ||
+ yystack.l_mark[-1].v.number < 0 || yystack.l_mark[-1].v.number > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ yyval.v.b.b1 = yystack.l_mark[-3].v.number;
+ yyval.v.b.b2 = yystack.l_mark[-1].v.number;
+ }
+break;
+case 205:
+#line 2629 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *e;
+ double p = strtod(yystack.l_mark[0].v.string, &e);
+
+ if (*e == '%') {
+ p *= 0.01;
+ e++;
+ }
+ if (*e) {
+ yyerror("invalid probability: %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.probability = p;
+ }
+break;
+case 206:
+#line 2645 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.probability = (double)yystack.l_mark[0].v.number;
+ }
+break;
+case 207:
+#line 2651 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = PF_PASS; yyval.v.b.b2 = yyval.v.b.w = 0; }
+break;
+case 208:
+#line 2652 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b = yystack.l_mark[0].v.b; yyval.v.b.b1 = PF_DROP; }
+break;
+case 209:
+#line 2655 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = blockpolicy;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 210:
+#line 2660 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_DROP;
+ yyval.v.b.w = 0;
+ yyval.v.b.w2 = 0;
+ }
+break;
+case 211:
+#line 2665 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNRST;
+ yyval.v.b.w = 0;
+ yyval.v.b.w2 = 0;
+ }
+break;
+case 212:
+#line 2670 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-1].v.number < 0 || yystack.l_mark[-1].v.number > 255) {
+ yyerror("illegal ttl value %d", yystack.l_mark[-1].v.number);
+ YYERROR;
+ }
+ yyval.v.b.b2 = PFRULE_RETURNRST;
+ yyval.v.b.w = yystack.l_mark[-1].v.number;
+ yyval.v.b.w2 = 0;
+ }
+break;
+case 213:
+#line 2679 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 214:
+#line 2684 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 215:
+#line 2689 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = yystack.l_mark[-1].v.number;
+ yyval.v.b.w2 = returnicmpdefault;
+ }
+break;
+case 216:
+#line 2694 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = yystack.l_mark[-1].v.number;
+ }
+break;
+case 217:
+#line 2699 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = yystack.l_mark[-3].v.number;
+ yyval.v.b.w2 = yystack.l_mark[-1].v.number;
+ }
+break;
+case 218:
+#line 2704 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURN;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 219:
+#line 2711 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET))) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 220:
+#line 2718 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_int8_t icmptype;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ icmptype = returnicmpdefault >> 8;
+ yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number);
+ }
+break;
+case 221:
+#line 2730 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET6))) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 222:
+#line 2737 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_int8_t icmptype;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ icmptype = returnicmp6default >> 8;
+ yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number);
+ }
+break;
+case 223:
+#line 2749 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_INOUT; }
+break;
+case 224:
+#line 2750 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_IN; }
+break;
+case 225:
+#line 2751 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OUT; }
+break;
+case 226:
+#line 2754 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.quick = 0; }
+break;
+case 227:
+#line 2755 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.quick = 1; }
+break;
+case 228:
+#line 2758 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = 0; yyval.v.logquick.quick = 0; yyval.v.logquick.logif = 0; }
+break;
+case 229:
+#line 2759 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 0; }
+break;
+case 230:
+#line 2760 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.quick = 1; yyval.v.logquick.log = 0; yyval.v.logquick.logif = 0; }
+break;
+case 231:
+#line 2761 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[-1].v.logquick; yyval.v.logquick.quick = 1; }
+break;
+case 232:
+#line 2762 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 1; }
+break;
+case 233:
+#line 2765 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG; yyval.v.logquick.logif = 0; }
+break;
+case 234:
+#line 2766 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.logquick.log = PF_LOG | yystack.l_mark[-1].v.logquick.log;
+ yyval.v.logquick.logif = yystack.l_mark[-1].v.logquick.logif;
+ }
+break;
+case 235:
+#line 2772 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[0].v.logquick; }
+break;
+case 236:
+#line 2773 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.logquick.log = yystack.l_mark[-2].v.logquick.log | yystack.l_mark[0].v.logquick.log;
+ yyval.v.logquick.logif = yystack.l_mark[0].v.logquick.logif;
+ if (yyval.v.logquick.logif == 0)
+ yyval.v.logquick.logif = yystack.l_mark[-2].v.logquick.logif;
+ }
+break;
+case 237:
+#line 2781 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG_ALL; yyval.v.logquick.logif = 0; }
+break;
+case 238:
+#line 2782 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; }
+break;
+case 239:
+#line 2783 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; }
+break;
+case 240:
+#line 2784 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const char *errstr;
+ u_int i;
+
+ yyval.v.logquick.log = 0;
+ if (strncmp(yystack.l_mark[0].v.string, "pflog", 5)) {
+ yyerror("%s: should be a pflog interface", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ i = strtonum(yystack.l_mark[0].v.string + 5, 0, 255, &errstr);
+ if (errstr) {
+ yyerror("%s: %s", yystack.l_mark[0].v.string, errstr);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.logquick.logif = i;
+ }
+break;
+case 241:
+#line 2805 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = NULL; }
+break;
+case 242:
+#line 2806 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; }
+break;
+case 243:
+#line 2807 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 244:
+#line 2810 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 245:
+#line 2811 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface;
+ yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface;
+ yyval.v.interface = yystack.l_mark[-3].v.interface;
+ }
+break;
+case 246:
+#line 2818 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; yyval.v.interface->not = yystack.l_mark[-1].v.number; }
+break;
+case 247:
+#line 2821 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+
+ yyval.v.interface = calloc(1, sizeof(struct node_if));
+ if (yyval.v.interface == NULL)
+ err(1, "if_item: calloc");
+ if (strlcpy(yyval.v.interface->ifname, yystack.l_mark[0].v.string, sizeof(yyval.v.interface->ifname)) >=
+ sizeof(yyval.v.interface->ifname)) {
+ free(yystack.l_mark[0].v.string);
+ free(yyval.v.interface);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+
+ if ((n = ifa_exists(yystack.l_mark[0].v.string)) != NULL)
+ yyval.v.interface->ifa_flags = n->ifa_flags;
+
+ free(yystack.l_mark[0].v.string);
+ yyval.v.interface->not = 0;
+ yyval.v.interface->next = NULL;
+ yyval.v.interface->tail = yyval.v.interface;
+ }
+break;
+case 248:
+#line 2845 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 249:
+#line 2846 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = AF_INET; }
+break;
+case 250:
+#line 2847 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = AF_INET6; }
+break;
+case 251:
+#line 2850 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = NULL; }
+break;
+case 252:
+#line 2851 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = yystack.l_mark[0].v.proto; }
+break;
+case 253:
+#line 2852 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = yystack.l_mark[-1].v.proto; }
+break;
+case 254:
+#line 2855 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = yystack.l_mark[-1].v.proto; }
+break;
+case 255:
+#line 2856 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.proto->tail->next = yystack.l_mark[-1].v.proto;
+ yystack.l_mark[-3].v.proto->tail = yystack.l_mark[-1].v.proto;
+ yyval.v.proto = yystack.l_mark[-3].v.proto;
+ }
+break;
+case 256:
+#line 2863 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_int8_t pr;
+
+ pr = (u_int8_t)yystack.l_mark[0].v.number;
+ if (pr == 0) {
+ yyerror("proto 0 cannot be used");
+ YYERROR;
+ }
+ yyval.v.proto = calloc(1, sizeof(struct node_proto));
+ if (yyval.v.proto == NULL)
+ err(1, "proto_item: calloc");
+ yyval.v.proto->proto = pr;
+ yyval.v.proto->next = NULL;
+ yyval.v.proto->tail = yyval.v.proto;
+ }
+break;
+case 257:
+#line 2880 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct protoent *p;
+
+ p = getprotobyname(yystack.l_mark[0].v.string);
+ if (p == NULL) {
+ yyerror("unknown protocol %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = p->p_proto;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 258:
+#line 2892 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("protocol outside range");
+ YYERROR;
+ }
+ }
+break;
+case 259:
+#line 2900 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.fromto.src.host = NULL;
+ yyval.v.fromto.src.port = NULL;
+ yyval.v.fromto.dst.host = NULL;
+ yyval.v.fromto.dst.port = NULL;
+ yyval.v.fromto.src_os = NULL;
+ }
+break;
+case 260:
+#line 2907 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.fromto.src = yystack.l_mark[-2].v.peer;
+ yyval.v.fromto.src_os = yystack.l_mark[-1].v.os;
+ yyval.v.fromto.dst = yystack.l_mark[0].v.peer;
+ }
+break;
+case 261:
+#line 2914 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = NULL; }
+break;
+case 262:
+#line 2915 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = yystack.l_mark[0].v.os; }
+break;
+case 263:
+#line 2916 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = yystack.l_mark[-1].v.os; }
+break;
+case 264:
+#line 2919 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.os = calloc(1, sizeof(struct node_os));
+ if (yyval.v.os == NULL)
+ err(1, "os: calloc");
+ yyval.v.os->os = yystack.l_mark[0].v.string;
+ yyval.v.os->tail = yyval.v.os;
+ }
+break;
+case 265:
+#line 2928 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = yystack.l_mark[-1].v.os; }
+break;
+case 266:
+#line 2929 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.os->tail->next = yystack.l_mark[-1].v.os;
+ yystack.l_mark[-3].v.os->tail = yystack.l_mark[-1].v.os;
+ yyval.v.os = yystack.l_mark[-3].v.os;
+ }
+break;
+case 267:
+#line 2936 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = NULL;
+ yyval.v.peer.port = NULL;
+ }
+break;
+case 268:
+#line 2940 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer = yystack.l_mark[0].v.peer;
+ }
+break;
+case 269:
+#line 2945 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = NULL;
+ yyval.v.peer.port = NULL;
+ }
+break;
+case 270:
+#line 2949 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (disallow_urpf_failed(yystack.l_mark[0].v.peer.host, "\"urpf-failed\" is "
+ "not permitted in a destination address"))
+ YYERROR;
+ yyval.v.peer = yystack.l_mark[0].v.peer;
+ }
+break;
+case 271:
+#line 2957 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = yystack.l_mark[0].v.host;
+ yyval.v.peer.port = NULL;
+ }
+break;
+case 272:
+#line 2961 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = yystack.l_mark[-2].v.host;
+ yyval.v.peer.port = yystack.l_mark[0].v.port;
+ }
+break;
+case 273:
+#line 2965 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = NULL;
+ yyval.v.peer.port = yystack.l_mark[0].v.port;
+ }
+break;
+case 276:
+#line 2975 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = NULL; }
+break;
+case 277:
+#line 2976 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 278:
+#line 2977 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 279:
+#line 2980 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 280:
+#line 2981 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = NULL; }
+break;
+case 281:
+#line 2984 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 282:
+#line 2985 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-1].v.host == NULL)
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ else if (yystack.l_mark[-3].v.host == NULL)
+ yyval.v.host = yystack.l_mark[-1].v.host;
+ else {
+ yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host;
+ yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail;
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ }
+ }
+break;
+case 283:
+#line 2998 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+
+ for (n = yystack.l_mark[0].v.host; n != NULL; n = n->next)
+ n->not = yystack.l_mark[-1].v.number;
+ yyval.v.host = yystack.l_mark[0].v.host;
+ }
+break;
+case 284:
+#line 3005 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "xhost: calloc");
+ yyval.v.host->addr.type = PF_ADDR_NOROUTE;
+ yyval.v.host->next = NULL;
+ yyval.v.host->not = yystack.l_mark[-1].v.number;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 285:
+#line 3014 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "xhost: calloc");
+ yyval.v.host->addr.type = PF_ADDR_URPFFAILED;
+ yyval.v.host->next = NULL;
+ yyval.v.host->not = yystack.l_mark[-1].v.number;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 286:
+#line 3025 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if ((yyval.v.host = host(yystack.l_mark[0].v.string)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(yystack.l_mark[0].v.string);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+
+ }
+break;
+case 287:
+#line 3035 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *b, *e;
+
+ if ((b = host(yystack.l_mark[-2].v.string)) == NULL || (e = host(yystack.l_mark[0].v.string)) == NULL) {
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ if (b->af != e->af ||
+ b->addr.type != PF_ADDR_ADDRMASK ||
+ e->addr.type != PF_ADDR_ADDRMASK ||
+ unmask(&b->addr.v.a.mask, b->af) !=
+ (b->af == AF_INET ? 32 : 128) ||
+ unmask(&e->addr.v.a.mask, e->af) !=
+ (e->af == AF_INET ? 32 : 128) ||
+ b->next != NULL || b->not ||
+ e->next != NULL || e->not) {
+ free(b);
+ free(e);
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ yyerror("invalid address range");
+ YYERROR;
+ }
+ memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
+ sizeof(b->addr.v.a.mask));
+ b->addr.type = PF_ADDR_RANGE;
+ yyval.v.host = b;
+ free(e);
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 288:
+#line 3068 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *buf;
+
+ if (asprintf(&buf, "%s/%lld", yystack.l_mark[-2].v.string, (long long)yystack.l_mark[0].v.number) == -1)
+ err(1, "host: asprintf");
+ free(yystack.l_mark[-2].v.string);
+ if ((yyval.v.host = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+break;
+case 289:
+#line 3082 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *buf;
+
+ /* ie. for 10/8 parsing */
+#ifdef __FreeBSD__
+ if (asprintf(&buf, "%lld/%lld", (long long)yystack.l_mark[-2].v.number, (long long)yystack.l_mark[0].v.number) == -1)
+#else
+ if (asprintf(&buf, "%lld/%lld", yystack.l_mark[-2].v.number, yystack.l_mark[0].v.number) == -1)
+#endif
+ err(1, "host: asprintf");
+ if ((yyval.v.host = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+break;
+case 291:
+#line 3101 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 128) {
+ yyerror("bit number too big");
+ YYERROR;
+ }
+ yyval.v.host = yystack.l_mark[-2].v.host;
+ for (n = yystack.l_mark[-2].v.host; n != NULL; n = n->next)
+ set_ipmask(n, yystack.l_mark[0].v.number);
+ }
+break;
+case 292:
+#line 3112 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (strlen(yystack.l_mark[-1].v.string) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "host: calloc");
+ yyval.v.host->addr.type = PF_ADDR_TABLE;
+ if (strlcpy(yyval.v.host->addr.v.tblname, yystack.l_mark[-1].v.string,
+ sizeof(yyval.v.host->addr.v.tblname)) >=
+ sizeof(yyval.v.host->addr.v.tblname))
+ errx(1, "host: strlcpy");
+ free(yystack.l_mark[-1].v.string);
+ yyval.v.host->next = NULL;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 294:
+#line 3133 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_long ulval;
+
+ if (atoul(yystack.l_mark[0].v.string, &ulval) == -1) {
+ yyerror("%s is not a number", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ } else
+ yyval.v.number = ulval;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 295:
+#line 3146 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ int flags = 0;
+ char *p, *op;
+
+ op = yystack.l_mark[-1].v.string;
+ if (!isalpha(op[0])) {
+ yyerror("invalid interface name '%s'", op);
+ free(op);
+ YYERROR;
+ }
+ while ((p = strrchr(yystack.l_mark[-1].v.string, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ yyerror("interface %s has bad modifier",
+ yystack.l_mark[-1].v.string);
+ free(op);
+ YYERROR;
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
+ free(op);
+ yyerror("illegal combination of "
+ "interface modifiers");
+ YYERROR;
+ }
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "address: calloc");
+ yyval.v.host->af = 0;
+ set_ipmask(yyval.v.host, 128);
+ yyval.v.host->addr.type = PF_ADDR_DYNIFTL;
+ yyval.v.host->addr.iflags = flags;
+ if (strlcpy(yyval.v.host->addr.v.ifname, yystack.l_mark[-1].v.string,
+ sizeof(yyval.v.host->addr.v.ifname)) >=
+ sizeof(yyval.v.host->addr.v.ifname)) {
+ free(op);
+ free(yyval.v.host);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ free(op);
+ yyval.v.host->next = NULL;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 296:
+#line 3200 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.port = yystack.l_mark[0].v.port; }
+break;
+case 297:
+#line 3201 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.port = yystack.l_mark[-1].v.port; }
+break;
+case 298:
+#line 3204 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.port = yystack.l_mark[-1].v.port; }
+break;
+case 299:
+#line 3205 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.port->tail->next = yystack.l_mark[-1].v.port;
+ yystack.l_mark[-3].v.port->tail = yystack.l_mark[-1].v.port;
+ yyval.v.port = yystack.l_mark[-3].v.port;
+ }
+break;
+case 300:
+#line 3212 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.port = calloc(1, sizeof(struct node_port));
+ if (yyval.v.port == NULL)
+ err(1, "port_item: calloc");
+ yyval.v.port->port[0] = yystack.l_mark[0].v.range.a;
+ yyval.v.port->port[1] = yystack.l_mark[0].v.range.b;
+ if (yystack.l_mark[0].v.range.t)
+ yyval.v.port->op = PF_OP_RRG;
+ else
+ yyval.v.port->op = PF_OP_EQ;
+ yyval.v.port->next = NULL;
+ yyval.v.port->tail = yyval.v.port;
+ }
+break;
+case 301:
+#line 3225 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.range.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ yyval.v.port = calloc(1, sizeof(struct node_port));
+ if (yyval.v.port == NULL)
+ err(1, "port_item: calloc");
+ yyval.v.port->port[0] = yystack.l_mark[0].v.range.a;
+ yyval.v.port->port[1] = yystack.l_mark[0].v.range.b;
+ yyval.v.port->op = yystack.l_mark[-1].v.i;
+ yyval.v.port->next = NULL;
+ yyval.v.port->tail = yyval.v.port;
+ }
+break;
+case 302:
+#line 3240 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.range.t || yystack.l_mark[0].v.range.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ yyval.v.port = calloc(1, sizeof(struct node_port));
+ if (yyval.v.port == NULL)
+ err(1, "port_item: calloc");
+ yyval.v.port->port[0] = yystack.l_mark[-2].v.range.a;
+ yyval.v.port->port[1] = yystack.l_mark[0].v.range.a;
+ yyval.v.port->op = yystack.l_mark[-1].v.i;
+ yyval.v.port->next = NULL;
+ yyval.v.port->tail = yyval.v.port;
+ }
+break;
+case 303:
+#line 3257 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, 0) == -1) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 304:
+#line 3266 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE) == -1) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 305:
+#line 3275 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.uid = yystack.l_mark[0].v.uid; }
+break;
+case 306:
+#line 3276 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.uid = yystack.l_mark[-1].v.uid; }
+break;
+case 307:
+#line 3279 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.uid = yystack.l_mark[-1].v.uid; }
+break;
+case 308:
+#line 3280 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.uid->tail->next = yystack.l_mark[-1].v.uid;
+ yystack.l_mark[-3].v.uid->tail = yystack.l_mark[-1].v.uid;
+ yyval.v.uid = yystack.l_mark[-3].v.uid;
+ }
+break;
+case 309:
+#line 3287 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.uid = calloc(1, sizeof(struct node_uid));
+ if (yyval.v.uid == NULL)
+ err(1, "uid_item: calloc");
+ yyval.v.uid->uid[0] = yystack.l_mark[0].v.number;
+ yyval.v.uid->uid[1] = yystack.l_mark[0].v.number;
+ yyval.v.uid->op = PF_OP_EQ;
+ yyval.v.uid->next = NULL;
+ yyval.v.uid->tail = yyval.v.uid;
+ }
+break;
+case 310:
+#line 3297 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number == UID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.uid = calloc(1, sizeof(struct node_uid));
+ if (yyval.v.uid == NULL)
+ err(1, "uid_item: calloc");
+ yyval.v.uid->uid[0] = yystack.l_mark[0].v.number;
+ yyval.v.uid->uid[1] = yystack.l_mark[0].v.number;
+ yyval.v.uid->op = yystack.l_mark[-1].v.i;
+ yyval.v.uid->next = NULL;
+ yyval.v.uid->tail = yyval.v.uid;
+ }
+break;
+case 311:
+#line 3312 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.number == UID_MAX || yystack.l_mark[0].v.number == UID_MAX) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.uid = calloc(1, sizeof(struct node_uid));
+ if (yyval.v.uid == NULL)
+ err(1, "uid_item: calloc");
+ yyval.v.uid->uid[0] = yystack.l_mark[-2].v.number;
+ yyval.v.uid->uid[1] = yystack.l_mark[0].v.number;
+ yyval.v.uid->op = yystack.l_mark[-1].v.i;
+ yyval.v.uid->next = NULL;
+ yyval.v.uid->tail = yyval.v.uid;
+ }
+break;
+case 312:
+#line 3329 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "unknown"))
+ yyval.v.number = UID_MAX;
+ else {
+ struct passwd *pw;
+
+ if ((pw = getpwnam(yystack.l_mark[0].v.string)) == NULL) {
+ yyerror("unknown user %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = pw->pw_uid;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 313:
+#line 3344 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= UID_MAX) {
+ yyerror("illegal uid value %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number;
+ }
+break;
+case 314:
+#line 3353 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.gid = yystack.l_mark[0].v.gid; }
+break;
+case 315:
+#line 3354 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.gid = yystack.l_mark[-1].v.gid; }
+break;
+case 316:
+#line 3357 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.gid = yystack.l_mark[-1].v.gid; }
+break;
+case 317:
+#line 3358 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.gid->tail->next = yystack.l_mark[-1].v.gid;
+ yystack.l_mark[-3].v.gid->tail = yystack.l_mark[-1].v.gid;
+ yyval.v.gid = yystack.l_mark[-3].v.gid;
+ }
+break;
+case 318:
+#line 3365 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.gid = calloc(1, sizeof(struct node_gid));
+ if (yyval.v.gid == NULL)
+ err(1, "gid_item: calloc");
+ yyval.v.gid->gid[0] = yystack.l_mark[0].v.number;
+ yyval.v.gid->gid[1] = yystack.l_mark[0].v.number;
+ yyval.v.gid->op = PF_OP_EQ;
+ yyval.v.gid->next = NULL;
+ yyval.v.gid->tail = yyval.v.gid;
+ }
+break;
+case 319:
+#line 3375 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number == GID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.gid = calloc(1, sizeof(struct node_gid));
+ if (yyval.v.gid == NULL)
+ err(1, "gid_item: calloc");
+ yyval.v.gid->gid[0] = yystack.l_mark[0].v.number;
+ yyval.v.gid->gid[1] = yystack.l_mark[0].v.number;
+ yyval.v.gid->op = yystack.l_mark[-1].v.i;
+ yyval.v.gid->next = NULL;
+ yyval.v.gid->tail = yyval.v.gid;
+ }
+break;
+case 320:
+#line 3390 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.number == GID_MAX || yystack.l_mark[0].v.number == GID_MAX) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.gid = calloc(1, sizeof(struct node_gid));
+ if (yyval.v.gid == NULL)
+ err(1, "gid_item: calloc");
+ yyval.v.gid->gid[0] = yystack.l_mark[-2].v.number;
+ yyval.v.gid->gid[1] = yystack.l_mark[0].v.number;
+ yyval.v.gid->op = yystack.l_mark[-1].v.i;
+ yyval.v.gid->next = NULL;
+ yyval.v.gid->tail = yyval.v.gid;
+ }
+break;
+case 321:
+#line 3407 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "unknown"))
+ yyval.v.number = GID_MAX;
+ else {
+ struct group *grp;
+
+ if ((grp = getgrnam(yystack.l_mark[0].v.string)) == NULL) {
+ yyerror("unknown group %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = grp->gr_gid;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 322:
+#line 3422 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= GID_MAX) {
+ yyerror("illegal gid value %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number;
+ }
+break;
+case 323:
+#line 3431 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ int f;
+
+ if ((f = parse_flags(yystack.l_mark[0].v.string)) < 0) {
+ yyerror("bad flags %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.b.b1 = f;
+ }
+break;
+case 324:
+#line 3444 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = yystack.l_mark[-2].v.b.b1; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; }
+break;
+case 325:
+#line 3445 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; }
+break;
+case 326:
+#line 3446 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 0; yyval.v.b.b2 = 0; }
+break;
+case 327:
+#line 3449 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[0].v.icmp; }
+break;
+case 328:
+#line 3450 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 329:
+#line 3451 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[0].v.icmp; }
+break;
+case 330:
+#line 3452 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 331:
+#line 3455 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 332:
+#line 3456 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp;
+ yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp;
+ yyval.v.icmp = yystack.l_mark[-3].v.icmp;
+ }
+break;
+case 333:
+#line 3463 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 334:
+#line 3464 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp;
+ yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp;
+ yyval.v.icmp = yystack.l_mark[-3].v.icmp;
+ }
+break;
+case 335:
+#line 3471 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[0].v.number;
+ yyval.v.icmp->code = 0;
+ yyval.v.icmp->proto = IPPROTO_ICMP;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 336:
+#line 3481 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET)) == NULL) {
+ yyerror("unknown icmp-code %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+
+ free(yystack.l_mark[0].v.string);
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = p->code + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMP;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 337:
+#line 3500 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = yystack.l_mark[0].v.number + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMP;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 338:
+#line 3516 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[0].v.number;
+ yyval.v.icmp->code = 0;
+ yyval.v.icmp->proto = IPPROTO_ICMPV6;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 339:
+#line 3526 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET6)) == NULL) {
+ yyerror("unknown icmp6-code %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = p->code + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMPV6;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 340:
+#line 3545 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = yystack.l_mark[0].v.number + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMPV6;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 341:
+#line 3561 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET)) == NULL) {
+ yyerror("unknown icmp-type %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = p->type + 1;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 342:
+#line 3572 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp-type %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number + 1;
+ }
+break;
+case 343:
+#line 3581 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET6)) ==
+ NULL) {
+ yyerror("unknown icmp6-type %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = p->type + 1;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 344:
+#line 3593 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp6-type %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number + 1;
+ }
+break;
+case 345:
+#line 3602 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "lowdelay"))
+ yyval.v.number = IPTOS_LOWDELAY;
+ else if (!strcmp(yystack.l_mark[0].v.string, "throughput"))
+ yyval.v.number = IPTOS_THROUGHPUT;
+ else if (!strcmp(yystack.l_mark[0].v.string, "reliability"))
+ yyval.v.number = IPTOS_RELIABILITY;
+ else if (yystack.l_mark[0].v.string[0] == '0' && yystack.l_mark[0].v.string[1] == 'x')
+ yyval.v.number = strtoul(yystack.l_mark[0].v.string, NULL, 16);
+ else
+ yyval.v.number = 256; /* flag bad argument */
+ if (yyval.v.number < 0 || yyval.v.number > 255) {
+ yyerror("illegal tos value %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 346:
+#line 3620 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.number = yystack.l_mark[0].v.number;
+ if (yyval.v.number < 0 || yyval.v.number > 255) {
+ yyerror("illegal tos value %s", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ }
+break;
+case 347:
+#line 3629 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_SRCTRACK; }
+break;
+case 348:
+#line 3630 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_SRCTRACK_GLOBAL; }
+break;
+case 349:
+#line 3631 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_SRCTRACK_RULE; }
+break;
+case 350:
+#line 3634 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.i = PFRULE_IFBOUND;
+ }
+break;
+case 351:
+#line 3637 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.i = 0;
+ }
+break;
+case 352:
+#line 3642 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = 0;
+ yyval.v.keep_state.options = NULL;
+ }
+break;
+case 353:
+#line 3646 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = PF_STATE_NORMAL;
+ yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 354:
+#line 3650 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = PF_STATE_MODULATE;
+ yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 355:
+#line 3654 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = PF_STATE_SYNPROXY;
+ yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 356:
+#line 3660 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 357:
+#line 3661 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_FLUSH; }
+break;
+case 358:
+#line 3662 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.i = PF_FLUSH | PF_FLUSH_GLOBAL;
+ }
+break;
+case 359:
+#line 3667 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.state_opt = yystack.l_mark[-1].v.state_opt; }
+break;
+case 360:
+#line 3668 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.state_opt = NULL; }
+break;
+case 361:
+#line 3671 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.state_opt = yystack.l_mark[0].v.state_opt; }
+break;
+case 362:
+#line 3672 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-2].v.state_opt->tail->next = yystack.l_mark[0].v.state_opt;
+ yystack.l_mark[-2].v.state_opt->tail = yystack.l_mark[0].v.state_opt;
+ yyval.v.state_opt = yystack.l_mark[-2].v.state_opt;
+ }
+break;
+case 363:
+#line 3679 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX;
+ yyval.v.state_opt->data.max_states = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 364:
+#line 3692 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_NOSYNC;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 365:
+#line 3700 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_STATES;
+ yyval.v.state_opt->data.max_src_states = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 366:
+#line 3713 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN;
+ yyval.v.state_opt->data.max_src_conn = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 367:
+#line 3726 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.number < 0 || yystack.l_mark[-2].v.number > UINT_MAX ||
+ yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
+ yyval.v.state_opt->data.max_src_conn_rate.limit = yystack.l_mark[-2].v.number;
+ yyval.v.state_opt->data.max_src_conn_rate.seconds = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 368:
+#line 3741 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ if (strlcpy(yyval.v.state_opt->data.overload.tblname, yystack.l_mark[-2].v.string,
+ PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
+ errx(1, "state_opt_item: strlcpy");
+ free(yystack.l_mark[-2].v.string);
+ yyval.v.state_opt->type = PF_STATE_OPT_OVERLOAD;
+ yyval.v.state_opt->data.overload.flush = yystack.l_mark[0].v.i;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 369:
+#line 3759 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_NODES;
+ yyval.v.state_opt->data.max_src_nodes = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 370:
+#line 3772 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_SRCTRACK;
+ yyval.v.state_opt->data.src_track = yystack.l_mark[0].v.i;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 371:
+#line 3781 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_STATELOCK;
+ yyval.v.state_opt->data.statelock = yystack.l_mark[0].v.i;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 372:
+#line 3790 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_SLOPPY;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 373:
+#line 3798 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ int i;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ for (i = 0; pf_timeouts[i].name &&
+ strcmp(pf_timeouts[i].name, yystack.l_mark[-1].v.string); ++i)
+ ; /* nothing */
+ if (!pf_timeouts[i].name) {
+ yyerror("illegal timeout name %s", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ if (strchr(pf_timeouts[i].name, '.') == NULL) {
+ yyerror("illegal state timeout %s", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-1].v.string);
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_TIMEOUT;
+ yyval.v.state_opt->data.timeout.number = pf_timeouts[i].timeout;
+ yyval.v.state_opt->data.timeout.seconds = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 374:
+#line 3830 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.string = yystack.l_mark[0].v.string;
+ }
+break;
+case 375:
+#line 3835 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.qassign.qname = yystack.l_mark[0].v.string;
+ yyval.v.qassign.pqname = NULL;
+ }
+break;
+case 376:
+#line 3839 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.qassign.qname = yystack.l_mark[-1].v.string;
+ yyval.v.qassign.pqname = NULL;
+ }
+break;
+case 377:
+#line 3843 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.qassign.qname = yystack.l_mark[-3].v.string;
+ yyval.v.qassign.pqname = yystack.l_mark[-1].v.string;
+ }
+break;
+case 378:
+#line 3849 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 379:
+#line 3850 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 1; }
+break;
+case 380:
+#line 3853 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE|PPORT_STAR) == -1) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 381:
+#line 3862 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 382:
+#line 3863 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 383:
+#line 3866 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 384:
+#line 3867 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host;
+ yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail;
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ }
+break;
+case 385:
+#line 3874 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.redirection = NULL; }
+break;
+case 386:
+#line 3875 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[0].v.host;
+ yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0;
+ }
+break;
+case 387:
+#line 3882 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[-2].v.host;
+ yyval.v.redirection->rport = yystack.l_mark[0].v.range;
+ }
+break;
+case 388:
+#line 3892 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey));
+ if (yyval.v.hashkey == NULL)
+ err(1, "hashkey: calloc");
+ yyval.v.hashkey->key32[0] = arc4random();
+ yyval.v.hashkey->key32[1] = arc4random();
+ yyval.v.hashkey->key32[2] = arc4random();
+ yyval.v.hashkey->key32[3] = arc4random();
+ }
+break;
+case 389:
+#line 3902 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strncmp(yystack.l_mark[0].v.string, "0x", 2)) {
+ if (strlen(yystack.l_mark[0].v.string) != 34) {
+ free(yystack.l_mark[0].v.string);
+ yyerror("hex key must be 128 bits "
+ "(32 hex digits) long");
+ YYERROR;
+ }
+ yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey));
+ if (yyval.v.hashkey == NULL)
+ err(1, "hashkey: calloc");
+
+ if (sscanf(yystack.l_mark[0].v.string, "0x%8x%8x%8x%8x",
+ &yyval.v.hashkey->key32[0], &yyval.v.hashkey->key32[1],
+ &yyval.v.hashkey->key32[2], &yyval.v.hashkey->key32[3]) != 4) {
+ free(yyval.v.hashkey);
+ free(yystack.l_mark[0].v.string);
+ yyerror("invalid hex key");
+ YYERROR;
+ }
+ } else {
+ MD5_CTX context;
+
+ yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey));
+ if (yyval.v.hashkey == NULL)
+ err(1, "hashkey: calloc");
+ MD5Init(&context);
+ MD5Update(&context, (unsigned char *)yystack.l_mark[0].v.string,
+ strlen(yystack.l_mark[0].v.string));
+ MD5Final((unsigned char *)yyval.v.hashkey, &context);
+ HTONL(yyval.v.hashkey->key32[0]);
+ HTONL(yyval.v.hashkey->key32[1]);
+ HTONL(yyval.v.hashkey->key32[2]);
+ HTONL(yyval.v.hashkey->key32[3]);
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 390:
+#line 3941 "../../freebsd/sbin/pfctl/parse.y"
+ { bzero(&pool_opts, sizeof pool_opts); }
+break;
+case 391:
+#line 3943 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.pool_opts = pool_opts; }
+break;
+case 392:
+#line 3944 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&pool_opts, sizeof pool_opts);
+ yyval.v.pool_opts = pool_opts;
+ }
+break;
+case 395:
+#line 3954 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_BITMASK;
+ }
+break;
+case 396:
+#line 3961 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_RANDOM;
+ }
+break;
+case 397:
+#line 3968 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_SRCHASH;
+ pool_opts.key = yystack.l_mark[0].v.hashkey;
+ }
+break;
+case 398:
+#line 3976 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_ROUNDROBIN;
+ }
+break;
+case 399:
+#line 3983 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.staticport) {
+ yyerror("static-port cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.staticport = 1;
+ }
+break;
+case 400:
+#line 3990 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & POM_STICKYADDRESS) {
+ yyerror("sticky-address cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.marker |= POM_STICKYADDRESS;
+ pool_opts.opts |= PF_POOL_STICKYADDR;
+ }
+break;
+case 401:
+#line 4000 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.redirection = NULL; }
+break;
+case 402:
+#line 4001 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[0].v.host;
+ yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0;
+ }
+break;
+case 403:
+#line 4008 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[-2].v.host;
+ yyval.v.redirection->rport = yystack.l_mark[0].v.range;
+ }
+break;
+case 404:
+#line 4017 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; }
+break;
+case 405:
+#line 4018 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 1; yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; }
+break;
+case 406:
+#line 4019 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 1; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; }
+break;
+case 407:
+#line 4020 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; }
+break;
+case 408:
+#line 4023 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if (yystack.l_mark[-2].v.i)
+ yyval.v.b.b1 = PF_NONAT;
+ else
+ yyval.v.b.b1 = PF_NAT;
+ yyval.v.b.b2 = yystack.l_mark[0].v.b.b1;
+ yyval.v.b.w = yystack.l_mark[0].v.b.b2;
+ yyval.v.b.w2 = yystack.l_mark[0].v.b.w2;
+ }
+break;
+case 409:
+#line 4036 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if (yystack.l_mark[-2].v.i)
+ yyval.v.b.b1 = PF_NORDR;
+ else
+ yyval.v.b.b1 = PF_RDR;
+ yyval.v.b.b2 = yystack.l_mark[0].v.b.b1;
+ yyval.v.b.w = yystack.l_mark[0].v.b.b2;
+ yyval.v.b.w2 = yystack.l_mark[0].v.b.w2;
+ }
+break;
+case 410:
+#line 4053 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = yystack.l_mark[-9].v.b.b1;
+ r.natpass = yystack.l_mark[-9].v.b.b2;
+ r.log = yystack.l_mark[-9].v.b.w;
+ r.logif = yystack.l_mark[-9].v.b.w2;
+ r.af = yystack.l_mark[-7].v.i;
+
+ if (!r.af) {
+ if (yystack.l_mark[-5].v.fromto.src.host && yystack.l_mark[-5].v.fromto.src.host->af &&
+ !yystack.l_mark[-5].v.fromto.src.host->ifindex)
+ r.af = yystack.l_mark[-5].v.fromto.src.host->af;
+ else if (yystack.l_mark[-5].v.fromto.dst.host && yystack.l_mark[-5].v.fromto.dst.host->af &&
+ !yystack.l_mark[-5].v.fromto.dst.host->ifindex)
+ r.af = yystack.l_mark[-5].v.fromto.dst.host->af;
+ }
+
+ if (yystack.l_mark[-4].v.string != NULL)
+ if (strlcpy(r.tagname, yystack.l_mark[-4].v.string, PF_TAG_NAME_SIZE) >=
+ PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-3].v.tagged.name)
+ if (strlcpy(r.match_tagname, yystack.l_mark[-3].v.tagged.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[-3].v.tagged.neg;
+ r.rtableid = yystack.l_mark[-2].v.rtableid;
+
+ if (r.action == PF_NONAT || r.action == PF_NORDR) {
+ if (yystack.l_mark[-1].v.redirection != NULL) {
+ yyerror("translation rule with 'no' "
+ "does not need '->'");
+ YYERROR;
+ }
+ } else {
+ if (yystack.l_mark[-1].v.redirection == NULL || yystack.l_mark[-1].v.redirection->host == NULL) {
+ yyerror("translation rule requires '-> "
+ "address'");
+ YYERROR;
+ }
+ if (!r.af && ! yystack.l_mark[-1].v.redirection->host->ifindex)
+ r.af = yystack.l_mark[-1].v.redirection->host->af;
+
+ remove_invalid_hosts(&yystack.l_mark[-1].v.redirection->host, &r.af);
+ if (invalid_redirect(yystack.l_mark[-1].v.redirection->host, r.af))
+ YYERROR;
+ if (check_netmask(yystack.l_mark[-1].v.redirection->host, r.af))
+ YYERROR;
+
+ r.rpool.proxy_port[0] = ntohs(yystack.l_mark[-1].v.redirection->rport.a);
+
+ switch (r.action) {
+ case PF_RDR:
+ if (!yystack.l_mark[-1].v.redirection->rport.b && yystack.l_mark[-1].v.redirection->rport.t &&
+ yystack.l_mark[-5].v.fromto.dst.port != NULL) {
+ r.rpool.proxy_port[1] =
+ ntohs(yystack.l_mark[-1].v.redirection->rport.a) +
+ (ntohs(
+ yystack.l_mark[-5].v.fromto.dst.port->port[1]) -
+ ntohs(
+ yystack.l_mark[-5].v.fromto.dst.port->port[0]));
+ } else
+ r.rpool.proxy_port[1] =
+ ntohs(yystack.l_mark[-1].v.redirection->rport.b);
+ break;
+ case PF_NAT:
+ r.rpool.proxy_port[1] =
+ ntohs(yystack.l_mark[-1].v.redirection->rport.b);
+ if (!r.rpool.proxy_port[0] &&
+ !r.rpool.proxy_port[1]) {
+ r.rpool.proxy_port[0] =
+ PF_NAT_PROXY_PORT_LOW;
+ r.rpool.proxy_port[1] =
+ PF_NAT_PROXY_PORT_HIGH;
+ } else if (!r.rpool.proxy_port[1])
+ r.rpool.proxy_port[1] =
+ r.rpool.proxy_port[0];
+ break;
+ default:
+ break;
+ }
+
+ r.rpool.opts = yystack.l_mark[0].v.pool_opts.type;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && (yystack.l_mark[-1].v.redirection->host->next != NULL ||
+ yystack.l_mark[-1].v.redirection->host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR(yystack.l_mark[-1].v.redirection->host->addr)))
+ r.rpool.opts = PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table(yystack.l_mark[-1].v.redirection->host, "tables are only "
+ "supported in round-robin redirection "
+ "pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias(yystack.l_mark[-1].v.redirection->host, "interface (%s) "
+ "is only supported in round-robin "
+ "redirection pools"))
+ YYERROR;
+ if (yystack.l_mark[-1].v.redirection->host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("only round-robin "
+ "valid for multiple "
+ "redirection addresses");
+ YYERROR;
+ }
+ }
+ }
+
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ memcpy(&r.rpool.key, yystack.l_mark[0].v.pool_opts.key,
+ sizeof(struct pf_poolhashkey));
+
+ if (yystack.l_mark[0].v.pool_opts.opts)
+ r.rpool.opts |= yystack.l_mark[0].v.pool_opts.opts;
+
+ if (yystack.l_mark[0].v.pool_opts.staticport) {
+ if (r.action != PF_NAT) {
+ yyerror("the 'static-port' option is "
+ "only valid with nat rules");
+ YYERROR;
+ }
+ if (r.rpool.proxy_port[0] !=
+ PF_NAT_PROXY_PORT_LOW &&
+ r.rpool.proxy_port[1] !=
+ PF_NAT_PROXY_PORT_HIGH) {
+ yyerror("the 'static-port' option can't"
+ " be used when specifying a port"
+ " range");
+ YYERROR;
+ }
+ r.rpool.proxy_port[0] = 0;
+ r.rpool.proxy_port[1] = 0;
+ }
+
+ expand_rule(&r, yystack.l_mark[-8].v.interface, yystack.l_mark[-1].v.redirection == NULL ? NULL : yystack.l_mark[-1].v.redirection->host, yystack.l_mark[-6].v.proto,
+ yystack.l_mark[-5].v.fromto.src_os, yystack.l_mark[-5].v.fromto.src.host, yystack.l_mark[-5].v.fromto.src.port, yystack.l_mark[-5].v.fromto.dst.host,
+ yystack.l_mark[-5].v.fromto.dst.port, 0, 0, 0, "");
+ free(yystack.l_mark[-1].v.redirection);
+ }
+break;
+case 411:
+#line 4212 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule binat;
+ struct pf_pooladdr *pa;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+ if (disallow_urpf_failed(yystack.l_mark[-4].v.host, "\"urpf-failed\" is not "
+ "permitted as a binat destination"))
+ YYERROR;
+
+ memset(&binat, 0, sizeof(binat));
+
+ if (yystack.l_mark[-12].v.i && yystack.l_mark[-10].v.b.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if (yystack.l_mark[-12].v.i)
+ binat.action = PF_NOBINAT;
+ else
+ binat.action = PF_BINAT;
+ binat.natpass = yystack.l_mark[-10].v.b.b1;
+ binat.log = yystack.l_mark[-10].v.b.b2;
+ binat.logif = yystack.l_mark[-10].v.b.w2;
+ binat.af = yystack.l_mark[-8].v.i;
+ if (!binat.af && yystack.l_mark[-5].v.host != NULL && yystack.l_mark[-5].v.host->af)
+ binat.af = yystack.l_mark[-5].v.host->af;
+ if (!binat.af && yystack.l_mark[-4].v.host != NULL && yystack.l_mark[-4].v.host->af)
+ binat.af = yystack.l_mark[-4].v.host->af;
+
+ if (!binat.af && yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host)
+ binat.af = yystack.l_mark[0].v.redirection->host->af;
+ if (!binat.af) {
+ yyerror("address family (inet/inet6) "
+ "undefined");
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-9].v.interface != NULL) {
+ memcpy(binat.ifname, yystack.l_mark[-9].v.interface->ifname,
+ sizeof(binat.ifname));
+ binat.ifnot = yystack.l_mark[-9].v.interface->not;
+ free(yystack.l_mark[-9].v.interface);
+ }
+
+ if (yystack.l_mark[-3].v.string != NULL)
+ if (strlcpy(binat.tagname, yystack.l_mark[-3].v.string,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if (yystack.l_mark[-2].v.tagged.name)
+ if (strlcpy(binat.match_tagname, yystack.l_mark[-2].v.tagged.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ binat.match_tag_not = yystack.l_mark[-2].v.tagged.neg;
+ binat.rtableid = yystack.l_mark[-1].v.rtableid;
+
+ if (yystack.l_mark[-7].v.proto != NULL) {
+ binat.proto = yystack.l_mark[-7].v.proto->proto;
+ free(yystack.l_mark[-7].v.proto);
+ }
+
+ if (yystack.l_mark[-5].v.host != NULL && disallow_table(yystack.l_mark[-5].v.host, "invalid use of "
+ "table <%s> as the source address of a binat rule"))
+ YYERROR;
+ if (yystack.l_mark[-5].v.host != NULL && disallow_alias(yystack.l_mark[-5].v.host, "invalid use of "
+ "interface (%s) as the source address of a binat "
+ "rule"))
+ YYERROR;
+ if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_table(
+ yystack.l_mark[0].v.redirection->host, "invalid use of table <%s> as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+ if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_alias(
+ yystack.l_mark[0].v.redirection->host, "invalid use of interface (%s) as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+
+ if (yystack.l_mark[-5].v.host != NULL) {
+ if (yystack.l_mark[-5].v.host->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if (yystack.l_mark[-5].v.host->addr.type == PF_ADDR_DYNIFTL)
+ yystack.l_mark[-5].v.host->af = binat.af;
+ if (yystack.l_mark[-5].v.host->af != binat.af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask(yystack.l_mark[-5].v.host, binat.af))
+ YYERROR;
+ memcpy(&binat.src.addr, &yystack.l_mark[-5].v.host->addr,
+ sizeof(binat.src.addr));
+ free(yystack.l_mark[-5].v.host);
+ }
+ if (yystack.l_mark[-4].v.host != NULL) {
+ if (yystack.l_mark[-4].v.host->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if (yystack.l_mark[-4].v.host->af != binat.af && yystack.l_mark[-4].v.host->af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask(yystack.l_mark[-4].v.host, binat.af))
+ YYERROR;
+ memcpy(&binat.dst.addr, &yystack.l_mark[-4].v.host->addr,
+ sizeof(binat.dst.addr));
+ binat.dst.neg = yystack.l_mark[-4].v.host->not;
+ free(yystack.l_mark[-4].v.host);
+ }
+
+ if (binat.action == PF_NOBINAT) {
+ if (yystack.l_mark[0].v.redirection != NULL) {
+ yyerror("'no binat' rule does not need"
+ " '->'");
+ YYERROR;
+ }
+ } else {
+ if (yystack.l_mark[0].v.redirection == NULL || yystack.l_mark[0].v.redirection->host == NULL) {
+ yyerror("'binat' rule requires"
+ " '-> address'");
+ YYERROR;
+ }
+
+ remove_invalid_hosts(&yystack.l_mark[0].v.redirection->host, &binat.af);
+ if (invalid_redirect(yystack.l_mark[0].v.redirection->host, binat.af))
+ YYERROR;
+ if (yystack.l_mark[0].v.redirection->host->next != NULL) {
+ yyerror("binat rule must redirect to "
+ "a single address");
+ YYERROR;
+ }
+ if (check_netmask(yystack.l_mark[0].v.redirection->host, binat.af))
+ YYERROR;
+
+ if (!PF_AZERO(&binat.src.addr.v.a.mask,
+ binat.af) &&
+ !PF_AEQ(&binat.src.addr.v.a.mask,
+ &yystack.l_mark[0].v.redirection->host->addr.v.a.mask, binat.af)) {
+ yyerror("'binat' source mask and "
+ "redirect mask must be the same");
+ YYERROR;
+ }
+
+ TAILQ_INIT(&binat.rpool.list);
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "binat: calloc");
+ pa->addr = yystack.l_mark[0].v.redirection->host->addr;
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&binat.rpool.list,
+ pa, entries);
+
+ free(yystack.l_mark[0].v.redirection);
+ }
+
+ pfctl_add_rule(pf, &binat, "");
+ }
+break;
+case 412:
+#line 4377 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = NULL; }
+break;
+case 413:
+#line 4378 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = yystack.l_mark[0].v.string; }
+break;
+case 414:
+#line 4381 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.tagged.neg = 0; yyval.v.tagged.name = NULL; }
+break;
+case 415:
+#line 4382 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.tagged.neg = yystack.l_mark[-2].v.number; yyval.v.tagged.name = yystack.l_mark[0].v.string; }
+break;
+case 416:
+#line 4385 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.rtableid = -1; }
+break;
+case 417:
+#line 4386 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ yyval.v.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 418:
+#line 4395 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "route_host: calloc");
+ yyval.v.host->ifname = yystack.l_mark[0].v.string;
+ set_ipmask(yyval.v.host, 128);
+ yyval.v.host->next = NULL;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 419:
+#line 4404 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = yystack.l_mark[-1].v.host;
+ yyval.v.host->ifname = yystack.l_mark[-2].v.string;
+ }
+break;
+case 420:
+#line 4410 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 421:
+#line 4411 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.host->af == 0)
+ yystack.l_mark[-3].v.host->af = yystack.l_mark[-1].v.host->af;
+ if (yystack.l_mark[-3].v.host->af != yystack.l_mark[-1].v.host->af) {
+ yyerror("all pool addresses must be in the "
+ "same address family");
+ YYERROR;
+ }
+ yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host;
+ yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail;
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ }
+break;
+case 422:
+#line 4425 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 423:
+#line 4426 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 424:
+#line 4429 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = NULL;
+ yyval.v.route.rt = 0;
+ yyval.v.route.pool_opts = 0;
+ }
+break;
+case 425:
+#line 4434 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = NULL;
+ yyval.v.route.rt = PF_FASTROUTE;
+ yyval.v.route.pool_opts = 0;
+ }
+break;
+case 426:
+#line 4439 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = yystack.l_mark[-1].v.host;
+ yyval.v.route.rt = PF_ROUTETO;
+ yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts;
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key;
+ }
+break;
+case 427:
+#line 4446 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = yystack.l_mark[-1].v.host;
+ yyval.v.route.rt = PF_REPLYTO;
+ yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts;
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key;
+ }
+break;
+case 428:
+#line 4453 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = yystack.l_mark[-1].v.host;
+ yyval.v.route.rt = PF_DUPTO;
+ yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts;
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key;
+ }
+break;
+case 429:
+#line 4463 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number, 0) != 0) {
+ yyerror("unknown timeout %s", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-1].v.string);
+ }
+break;
+case 430:
+#line 4479 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, "interval", yystack.l_mark[0].v.number, 0) != 0)
+ YYERROR;
+ }
+break;
+case 433:
+#line 4496 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_limit(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number) != 0) {
+ yyerror("unable to set limit %s %u", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-1].v.string);
+ }
+break;
+case 438:
+#line 4522 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number = 0; }
+break;
+case 439:
+#line 4523 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "yes"))
+ yyval.v.number = 1;
+ else {
+ yyerror("invalid value '%s', expected 'yes' "
+ "or 'no'", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 440:
+#line 4536 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_EQ; }
+break;
+case 441:
+#line 4537 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_NE; }
+break;
+case 442:
+#line 4538 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_LE; }
+break;
+case 443:
+#line 4539 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_LT; }
+break;
+case 444:
+#line 4540 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_GE; }
+break;
+case 445:
+#line 4541 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_GT; }
+break;
+#line 9257 "pfctly.tab.c"
+ }
+ yystack.s_mark -= yym;
+ yystate = *yystack.s_mark;
+ yystack.l_mark -= yym;
+ yym = yylhs[yyn];
+ if (yystate == 0 && yym == 0)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yystack.s_mark = YYFINAL;
+ *++yystack.l_mark = yyval;
+ if (yychar < 0)
+ {
+ if ((yychar = YYLEX) < 0) yychar = YYEOF;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = yyname[YYTRANSLATE(yychar)];
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, YYFINAL, yychar, yys);
+ }
+#endif
+ }
+ if (yychar == YYEOF) goto yyaccept;
+ goto yyloop;
+ }
+ if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yystack.s_mark, yystate);
+#endif
+ if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM)
+ {
+ goto yyoverflow;
+ }
+ *++yystack.s_mark = (YYINT) yystate;
+ *++yystack.l_mark = yyval;
+ goto yyloop;
+
+yyoverflow:
+ YYERROR_CALL("yacc stack overflow");
+
+yyabort:
+ yyfreestack(&yystack);
+ return (1);
+
+yyaccept:
+ yyfreestack(&yystack);
+ return (0);
+}
diff --git a/freebsd/sbin/pfctl/parse.h b/freebsd/sbin/pfctl/parse.h
new file mode 100644
index 00000000..929f9956
--- /dev/null
+++ b/freebsd/sbin/pfctl/parse.h
@@ -0,0 +1,337 @@
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_PFCTLY_PFCTLY_TAB_H_INCLUDED
+# define YY_PFCTLY_PFCTLY_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int pfctlydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ PASS = 258,
+ BLOCK = 259,
+ SCRUB = 260,
+ RETURN = 261,
+ IN = 262,
+ OS = 263,
+ OUT = 264,
+ LOG = 265,
+ QUICK = 266,
+ ON = 267,
+ FROM = 268,
+ TO = 269,
+ FLAGS = 270,
+ RETURNRST = 271,
+ RETURNICMP = 272,
+ RETURNICMP6 = 273,
+ PROTO = 274,
+ INET = 275,
+ INET6 = 276,
+ ALL = 277,
+ ANY = 278,
+ ICMPTYPE = 279,
+ ICMP6TYPE = 280,
+ CODE = 281,
+ KEEP = 282,
+ MODULATE = 283,
+ STATE = 284,
+ PORT = 285,
+ RDR = 286,
+ NAT = 287,
+ BINAT = 288,
+ ARROW = 289,
+ NODF = 290,
+ MINTTL = 291,
+ ERROR = 292,
+ ALLOWOPTS = 293,
+ FASTROUTE = 294,
+ FILENAME = 295,
+ ROUTETO = 296,
+ DUPTO = 297,
+ REPLYTO = 298,
+ NO = 299,
+ LABEL = 300,
+ NOROUTE = 301,
+ URPFFAILED = 302,
+ FRAGMENT = 303,
+ USER = 304,
+ GROUP = 305,
+ MAXMSS = 306,
+ MAXIMUM = 307,
+ TTL = 308,
+ TOS = 309,
+ DROP = 310,
+ TABLE = 311,
+ REASSEMBLE = 312,
+ FRAGDROP = 313,
+ FRAGCROP = 314,
+ ANCHOR = 315,
+ NATANCHOR = 316,
+ RDRANCHOR = 317,
+ BINATANCHOR = 318,
+ SET = 319,
+ OPTIMIZATION = 320,
+ TIMEOUT = 321,
+ LIMIT = 322,
+ LOGINTERFACE = 323,
+ BLOCKPOLICY = 324,
+ RANDOMID = 325,
+ REQUIREORDER = 326,
+ SYNPROXY = 327,
+ FINGERPRINTS = 328,
+ NOSYNC = 329,
+ DEBUG = 330,
+ SKIP = 331,
+ HOSTID = 332,
+ ANTISPOOF = 333,
+ FOR = 334,
+ INCLUDE = 335,
+ BITMASK = 336,
+ RANDOM = 337,
+ SOURCEHASH = 338,
+ ROUNDROBIN = 339,
+ STATICPORT = 340,
+ PROBABILITY = 341,
+ ALTQ = 342,
+ CBQ = 343,
+ CODEL = 344,
+ PRIQ = 345,
+ HFSC = 346,
+ FAIRQ = 347,
+ BANDWIDTH = 348,
+ TBRSIZE = 349,
+ LINKSHARE = 350,
+ REALTIME = 351,
+ UPPERLIMIT = 352,
+ QUEUE = 353,
+ PRIORITY = 354,
+ QLIMIT = 355,
+ HOGS = 356,
+ BUCKETS = 357,
+ RTABLE = 358,
+ TARGET = 359,
+ INTERVAL = 360,
+ LOAD = 361,
+ RULESET_OPTIMIZATION = 362,
+ PRIO = 363,
+ STICKYADDRESS = 364,
+ MAXSRCSTATES = 365,
+ MAXSRCNODES = 366,
+ SOURCETRACK = 367,
+ GLOBAL = 368,
+ RULE = 369,
+ MAXSRCCONN = 370,
+ MAXSRCCONNRATE = 371,
+ OVERLOAD = 372,
+ FLUSH = 373,
+ SLOPPY = 374,
+ TAGGED = 375,
+ TAG = 376,
+ IFBOUND = 377,
+ FLOATING = 378,
+ STATEPOLICY = 379,
+ STATEDEFAULTS = 380,
+ ROUTE = 381,
+ SETTOS = 382,
+ DIVERTTO = 383,
+ DIVERTREPLY = 384,
+ STRING = 385,
+ NUMBER = 386,
+ PORTBINARY = 387
+ };
+#endif
+/* Tokens. */
+#define PASS 258
+#define BLOCK 259
+#define SCRUB 260
+#define RETURN 261
+#define IN 262
+#define OS 263
+#define OUT 264
+#define LOG 265
+#define QUICK 266
+#define ON 267
+#define FROM 268
+#define TO 269
+#define FLAGS 270
+#define RETURNRST 271
+#define RETURNICMP 272
+#define RETURNICMP6 273
+#define PROTO 274
+#define INET 275
+#define INET6 276
+#define ALL 277
+#define ANY 278
+#define ICMPTYPE 279
+#define ICMP6TYPE 280
+#define CODE 281
+#define KEEP 282
+#define MODULATE 283
+#define STATE 284
+#define PORT 285
+#define RDR 286
+#define NAT 287
+#define BINAT 288
+#define ARROW 289
+#define NODF 290
+#define MINTTL 291
+#define ERROR 292
+#define ALLOWOPTS 293
+#define FASTROUTE 294
+#define FILENAME 295
+#define ROUTETO 296
+#define DUPTO 297
+#define REPLYTO 298
+#define NO 299
+#define LABEL 300
+#define NOROUTE 301
+#define URPFFAILED 302
+#define FRAGMENT 303
+#define USER 304
+#define GROUP 305
+#define MAXMSS 306
+#define MAXIMUM 307
+#define TTL 308
+#define TOS 309
+#define DROP 310
+#define TABLE 311
+#define REASSEMBLE 312
+#define FRAGDROP 313
+#define FRAGCROP 314
+#define ANCHOR 315
+#define NATANCHOR 316
+#define RDRANCHOR 317
+#define BINATANCHOR 318
+#define SET 319
+#define OPTIMIZATION 320
+#define TIMEOUT 321
+#define LIMIT 322
+#define LOGINTERFACE 323
+#define BLOCKPOLICY 324
+#define RANDOMID 325
+#define REQUIREORDER 326
+#define SYNPROXY 327
+#define FINGERPRINTS 328
+#define NOSYNC 329
+#define DEBUG 330
+#define SKIP 331
+#define HOSTID 332
+#define ANTISPOOF 333
+#define FOR 334
+#define INCLUDE 335
+#define BITMASK 336
+#define RANDOM 337
+#define SOURCEHASH 338
+#define ROUNDROBIN 339
+#define STATICPORT 340
+#define PROBABILITY 341
+#define ALTQ 342
+#define CBQ 343
+#define CODEL 344
+#define PRIQ 345
+#define HFSC 346
+#define FAIRQ 347
+#define BANDWIDTH 348
+#define TBRSIZE 349
+#define LINKSHARE 350
+#define REALTIME 351
+#define UPPERLIMIT 352
+#define QUEUE 353
+#define PRIORITY 354
+#define QLIMIT 355
+#define HOGS 356
+#define BUCKETS 357
+#define RTABLE 358
+#define TARGET 359
+#define INTERVAL 360
+#define LOAD 361
+#define RULESET_OPTIMIZATION 362
+#define PRIO 363
+#define STICKYADDRESS 364
+#define MAXSRCSTATES 365
+#define MAXSRCNODES 366
+#define SOURCETRACK 367
+#define GLOBAL 368
+#define RULE 369
+#define MAXSRCCONN 370
+#define MAXSRCCONNRATE 371
+#define OVERLOAD 372
+#define FLUSH 373
+#define SLOPPY 374
+#define TAGGED 375
+#define TAG 376
+#define IFBOUND 377
+#define FLOATING 378
+#define STATEPOLICY 379
+#define STATEDEFAULTS 380
+#define ROUTE 381
+#define SETTOS 382
+#define DIVERTTO 383
+#define DIVERTREPLY 384
+#define STRING 385
+#define NUMBER 386
+#define PORTBINARY 387
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE pfctlylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int pfctlyparse (void *YYPARSE_PARAM);
+#else
+int pfctlyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int pfctlyparse (void);
+#else
+int pfctlyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_PFCTLY_PFCTLY_TAB_H_INCLUDED */
diff --git a/freebsd/sbin/pfctl/parse.y b/freebsd/sbin/pfctl/parse.y
new file mode 100644
index 00000000..33edd3e5
--- /dev/null
+++ b/freebsd/sbin/pfctl/parse.y
@@ -0,0 +1,6290 @@
+/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */
+
+/*
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
+ * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
+ * Copyright (c) 2001 Theo de Raadt. All rights reserved.
+ * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+%{
+#ifdef __rtems__
+#include <machine/rtems-bsd-user-space.h>
+#endif /* __rtems__ */
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset
+#define pf_anchor_setup _bsd_pf_anchor_setup
+#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <err.h>
+#include <limits.h>
+#include <pwd.h>
+#include <grp.h>
+#include <md5.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-parse-data.h"
+#endif /* __rtems__ */
+
+static struct pfctl *pf = NULL;
+static int debug = 0;
+static int rulestate = 0;
+static u_int16_t returnicmpdefault =
+ (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+static u_int16_t returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+static int blockpolicy = PFRULE_DROP;
+static int require_order = 1;
+static int default_statelock;
+
+static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
+static struct file {
+ TAILQ_ENTRY(file) entry;
+ FILE *stream;
+ char *name;
+ int lineno;
+ int errors;
+} *file;
+struct file *pushfile(const char *, int);
+int popfile(void);
+int check_file_secrecy(int, const char *);
+int yyparse(void);
+int yylex(void);
+int yyerror(const char *, ...);
+int kw_cmp(const void *, const void *);
+int lookup(char *);
+int lgetc(int);
+int lungetc(int);
+int findeol(void);
+
+static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
+struct sym {
+ TAILQ_ENTRY(sym) entry;
+ int used;
+ int persist;
+ char *nam;
+ char *val;
+};
+int symset(const char *, const char *, int);
+char *symget(const char *);
+
+int atoul(char *, u_long *);
+
+enum {
+ PFCTL_STATE_NONE,
+ PFCTL_STATE_OPTION,
+ PFCTL_STATE_SCRUB,
+ PFCTL_STATE_QUEUE,
+ PFCTL_STATE_NAT,
+ PFCTL_STATE_FILTER
+};
+
+struct node_proto {
+ u_int8_t proto;
+ struct node_proto *next;
+ struct node_proto *tail;
+};
+
+struct node_port {
+ u_int16_t port[2];
+ u_int8_t op;
+ struct node_port *next;
+ struct node_port *tail;
+};
+
+struct node_uid {
+ uid_t uid[2];
+ u_int8_t op;
+ struct node_uid *next;
+ struct node_uid *tail;
+};
+
+struct node_gid {
+ gid_t gid[2];
+ u_int8_t op;
+ struct node_gid *next;
+ struct node_gid *tail;
+};
+
+struct node_icmp {
+ u_int8_t code;
+ u_int8_t type;
+ u_int8_t proto;
+ struct node_icmp *next;
+ struct node_icmp *tail;
+};
+
+enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
+ PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
+ PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
+ PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
+ PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
+
+enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
+
+struct node_state_opt {
+ int type;
+ union {
+ u_int32_t max_states;
+ u_int32_t max_src_states;
+ u_int32_t max_src_conn;
+ struct {
+ u_int32_t limit;
+ u_int32_t seconds;
+ } max_src_conn_rate;
+ struct {
+ u_int8_t flush;
+ char tblname[PF_TABLE_NAME_SIZE];
+ } overload;
+ u_int32_t max_src_nodes;
+ u_int8_t src_track;
+ u_int32_t statelock;
+ struct {
+ int number;
+ u_int32_t seconds;
+ } timeout;
+ } data;
+ struct node_state_opt *next;
+ struct node_state_opt *tail;
+};
+
+struct peer {
+ struct node_host *host;
+ struct node_port *port;
+};
+
+static struct node_queue {
+ char queue[PF_QNAME_SIZE];
+ char parent[PF_QNAME_SIZE];
+ char ifname[IFNAMSIZ];
+ int scheduler;
+ struct node_queue *next;
+ struct node_queue *tail;
+} *queues = NULL;
+
+struct node_qassign {
+ char *qname;
+ char *pqname;
+};
+
+static struct filter_opts {
+ int marker;
+#define FOM_FLAGS 0x01
+#define FOM_ICMP 0x02
+#define FOM_TOS 0x04
+#define FOM_KEEP 0x08
+#define FOM_SRCTRACK 0x10
+#define FOM_SETPRIO 0x0400
+#define FOM_PRIO 0x2000
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } flags;
+ struct node_icmp *icmpspec;
+ u_int32_t tos;
+ u_int32_t prob;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep;
+ int fragment;
+ int allowopts;
+ char *label;
+ struct node_qassign queues;
+ char *tag;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+ u_int8_t prio;
+ u_int8_t set_prio[2];
+ struct {
+ struct node_host *addr;
+ u_int16_t port;
+ } divert;
+} filter_opts;
+
+static struct antispoof_opts {
+ char *label;
+ u_int rtableid;
+} antispoof_opts;
+
+static struct scrub_opts {
+ int marker;
+#define SOM_MINTTL 0x01
+#define SOM_MAXMSS 0x02
+#define SOM_FRAGCACHE 0x04
+#define SOM_SETTOS 0x08
+ int nodf;
+ int minttl;
+ int maxmss;
+ int settos;
+ int fragcache;
+ int randomid;
+ int reassemble_tcp;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+} scrub_opts;
+
+static struct queue_opts {
+ int marker;
+#define QOM_BWSPEC 0x01
+#define QOM_SCHEDULER 0x02
+#define QOM_PRIORITY 0x04
+#define QOM_TBRSIZE 0x08
+#define QOM_QLIMIT 0x10
+ struct node_queue_bw queue_bwspec;
+ struct node_queue_opt scheduler;
+ int priority;
+ int tbrsize;
+ int qlimit;
+} queue_opts;
+
+static struct table_opts {
+ int flags;
+ int init_addr;
+ struct node_tinithead init_nodes;
+} table_opts;
+
+static struct pool_opts {
+ int marker;
+#define POM_TYPE 0x01
+#define POM_STICKYADDRESS 0x02
+ u_int8_t opts;
+ int type;
+ int staticport;
+ struct pf_poolhashkey *key;
+
+} pool_opts;
+
+static struct codel_opts codel_opts;
+static struct node_hfsc_opts hfsc_opts;
+static struct node_fairq_opts fairq_opts;
+static struct node_state_opt *keep_state_defaults = NULL;
+
+int disallow_table(struct node_host *, const char *);
+int disallow_urpf_failed(struct node_host *, const char *);
+int disallow_alias(struct node_host *, const char *);
+int rule_consistent(struct pf_rule *, int);
+int filter_consistent(struct pf_rule *, int);
+int nat_consistent(struct pf_rule *);
+int rdr_consistent(struct pf_rule *);
+int process_tabledef(char *, struct table_opts *);
+void expand_label_str(char *, size_t, const char *, const char *);
+void expand_label_if(const char *, char *, size_t, const char *);
+void expand_label_addr(const char *, char *, size_t, u_int8_t,
+ struct node_host *);
+void expand_label_port(const char *, char *, size_t,
+ struct node_port *);
+void expand_label_proto(const char *, char *, size_t, u_int8_t);
+void expand_label_nr(const char *, char *, size_t);
+void expand_label(char *, size_t, const char *, u_int8_t,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, u_int8_t);
+void expand_rule(struct pf_rule *, struct node_if *,
+ struct node_host *, struct node_proto *, struct node_os *,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, struct node_uid *, struct node_gid *,
+ struct node_icmp *, const char *);
+int expand_altq(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw bwspec,
+ struct node_queue_opt *);
+int expand_queue(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw,
+ struct node_queue_opt *);
+int expand_skip_interface(struct node_if *);
+
+int check_rulestate(int);
+int getservice(char *);
+int rule_label(struct pf_rule *, char *);
+int rt_tableid_max(void);
+
+void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
+void decide_address_family(struct node_host *, sa_family_t *);
+void remove_invalid_hosts(struct node_host **, sa_family_t *);
+int invalid_redirect(struct node_host *, sa_family_t);
+u_int16_t parseicmpspec(char *, sa_family_t);
+
+static TAILQ_HEAD(loadanchorshead, loadanchors)
+ loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
+
+struct loadanchors {
+ TAILQ_ENTRY(loadanchors) entries;
+ char *anchorname;
+ char *filename;
+};
+
+typedef struct {
+ union {
+ int64_t number;
+ double probability;
+ int i;
+ char *string;
+ u_int rtableid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } b;
+ struct range {
+ int a;
+ int b;
+ int t;
+ } range;
+ struct node_if *interface;
+ struct node_proto *proto;
+ struct node_icmp *icmp;
+ struct node_host *host;
+ struct node_os *os;
+ struct node_port *port;
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct node_state_opt *state_opt;
+ struct peer peer;
+ struct {
+ struct peer src, dst;
+ struct node_os *src_os;
+ } fromto;
+ struct {
+ struct node_host *host;
+ u_int8_t rt;
+ u_int8_t pool_opts;
+ sa_family_t af;
+ struct pf_poolhashkey *key;
+ } route;
+ struct redirection {
+ struct node_host *host;
+ struct range rport;
+ } *redirection;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep_state;
+ struct {
+ u_int8_t log;
+ u_int8_t logif;
+ u_int8_t quick;
+ } logquick;
+ struct {
+ int neg;
+ char *name;
+ } tagged;
+ struct pf_poolhashkey *hashkey;
+ struct node_queue *queue;
+ struct node_queue_opt queue_options;
+ struct node_queue_bw queue_bwspec;
+ struct node_qassign qassign;
+ struct filter_opts filter_opts;
+ struct antispoof_opts antispoof_opts;
+ struct queue_opts queue_opts;
+ struct scrub_opts scrub_opts;
+ struct table_opts table_opts;
+ struct pool_opts pool_opts;
+ struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ struct codel_opts codel_opts;
+ } v;
+ int lineno;
+} YYSTYPE;
+
+#define PPORT_RANGE 1
+#define PPORT_STAR 2
+int parseport(char *, struct range *r, int);
+
+#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
+ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
+ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
+
+%}
+
+%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
+%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
+%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
+%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
+%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
+%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
+%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
+%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
+%token ANTISPOOF FOR INCLUDE
+%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
+%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
+%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
+%token LOAD RULESET_OPTIMIZATION PRIO
+%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
+%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
+%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
+%token DIVERTTO DIVERTREPLY
+%token <v.string> STRING
+%token <v.number> NUMBER
+%token <v.i> PORTBINARY
+%type <v.interface> interface if_list if_item_not if_item
+%type <v.number> number icmptype icmp6type uid gid
+%type <v.number> tos not yesno
+%type <v.probability> probability
+%type <v.i> no dir af fragcache optimizer
+%type <v.i> sourcetrack flush unaryop statelock
+%type <v.b> action nataction natpasslog scrubaction
+%type <v.b> flags flag blockspec prio
+%type <v.range> portplain portstar portrange
+%type <v.hashkey> hashkey
+%type <v.proto> proto proto_list proto_item
+%type <v.number> protoval
+%type <v.icmp> icmpspec
+%type <v.icmp> icmp_list icmp_item
+%type <v.icmp> icmp6_list icmp6_item
+%type <v.number> reticmpspec reticmp6spec
+%type <v.fromto> fromto
+%type <v.peer> ipportspec from to
+%type <v.host> ipspec toipspec xhost host dynaddr host_list
+%type <v.host> redir_host_list redirspec
+%type <v.host> route_host route_host_list routespec
+%type <v.os> os xos os_list
+%type <v.port> portspec port_list port_item
+%type <v.uid> uids uid_list uid_item
+%type <v.gid> gids gid_list gid_item
+%type <v.route> route
+%type <v.redirection> redirection redirpool
+%type <v.string> label stringall tag anchorname
+%type <v.string> string varstring numberstring
+%type <v.keep_state> keep
+%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
+%type <v.logquick> logquick quick log logopts logopt
+%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if
+%type <v.qassign> qname
+%type <v.queue> qassign qassign_list qassign_item
+%type <v.queue_options> scheduler
+%type <v.number> cbqflags_list cbqflags_item
+%type <v.number> priqflags_list priqflags_item
+%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts
+%type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts
+%type <v.codel_opts> codelopts_list codelopts_item codel_opts
+%type <v.queue_bwspec> bandwidth
+%type <v.filter_opts> filter_opts filter_opt filter_opts_l
+%type <v.filter_opts> filter_sets filter_set filter_sets_l
+%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l
+%type <v.queue_opts> queue_opts queue_opt queue_opts_l
+%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l
+%type <v.table_opts> table_opts table_opt table_opts_l
+%type <v.pool_opts> pool_opts pool_opt pool_opts_l
+%type <v.tagged> tagged
+%type <v.rtableid> rtable
+%%
+
+ruleset : /* empty */
+ | ruleset include '\n'
+ | ruleset '\n'
+ | ruleset option '\n'
+ | ruleset scrubrule '\n'
+ | ruleset natrule '\n'
+ | ruleset binatrule '\n'
+ | ruleset pfrule '\n'
+ | ruleset anchorrule '\n'
+ | ruleset loadrule '\n'
+ | ruleset altqif '\n'
+ | ruleset queuespec '\n'
+ | ruleset varset '\n'
+ | ruleset antispoof '\n'
+ | ruleset tabledef '\n'
+ | '{' fakeanchor '}' '\n';
+ | ruleset error '\n' { file->errors++; }
+ ;
+
+include : INCLUDE STRING {
+ struct file *nfile;
+
+ if ((nfile = pushfile($2, 0)) == NULL) {
+ yyerror("failed to include file %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+
+ file = nfile;
+ lungetc('\n');
+ }
+ ;
+
+/*
+ * apply to previouslys specified rule: must be careful to note
+ * what that is: pf or nat or binat or rdr
+ */
+fakeanchor : fakeanchor '\n'
+ | fakeanchor anchorrule '\n'
+ | fakeanchor binatrule '\n'
+ | fakeanchor natrule '\n'
+ | fakeanchor pfrule '\n'
+ | fakeanchor error '\n'
+ ;
+
+optimizer : string {
+ if (!strcmp($1, "none"))
+ $$ = 0;
+ else if (!strcmp($1, "basic"))
+ $$ = PF_OPTIMIZE_BASIC;
+ else if (!strcmp($1, "profile"))
+ $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
+ else {
+ yyerror("unknown ruleset-optimization %s", $1);
+ YYERROR;
+ }
+ }
+ ;
+
+option : SET OPTIMIZATION STRING {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (pfctl_set_optimization(pf, $3) != 0) {
+ yyerror("unknown optimization %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET RULESET_OPTIMIZATION optimizer {
+ if (!(pf->opts & PF_OPT_OPTIMIZE)) {
+ pf->opts |= PF_OPT_OPTIMIZE;
+ pf->optimize = $3;
+ }
+ }
+ | SET TIMEOUT timeout_spec
+ | SET TIMEOUT '{' optnl timeout_list '}'
+ | SET LIMIT limit_spec
+ | SET LIMIT '{' optnl limit_list '}'
+ | SET LOGINTERFACE stringall {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (pfctl_set_logif(pf, $3) != 0) {
+ yyerror("error setting loginterface %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET HOSTID number {
+ if ($3 == 0 || $3 > UINT_MAX) {
+ yyerror("hostid must be non-zero");
+ YYERROR;
+ }
+ if (pfctl_set_hostid(pf, $3) != 0) {
+ yyerror("error setting hostid %08x", $3);
+ YYERROR;
+ }
+ }
+ | SET BLOCKPOLICY DROP {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy drop\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_DROP;
+ }
+ | SET BLOCKPOLICY RETURN {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy return\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_RETURN;
+ }
+ | SET REQUIREORDER yesno {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set require-order %s\n",
+ $3 == 1 ? "yes" : "no");
+ require_order = $3;
+ }
+ | SET FINGERPRINTS STRING {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set fingerprints \"%s\"\n", $3);
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (!pf->anchor->name[0]) {
+ if (pfctl_file_fingerprints(pf->dev,
+ pf->opts, $3)) {
+ yyerror("error loading "
+ "fingerprints %s", $3);
+ free($3);
+ YYERROR;
+ }
+ }
+ free($3);
+ }
+ | SET STATEPOLICY statelock {
+ if (pf->opts & PF_OPT_VERBOSE)
+ switch ($3) {
+ case 0:
+ printf("set state-policy floating\n");
+ break;
+ case PFRULE_IFBOUND:
+ printf("set state-policy if-bound\n");
+ break;
+ }
+ default_statelock = $3;
+ }
+ | SET DEBUG STRING {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (pfctl_set_debug(pf, $3) != 0) {
+ yyerror("error setting debuglevel %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET SKIP interface {
+ if (expand_skip_interface($3) != 0) {
+ yyerror("error setting skip interface(s)");
+ YYERROR;
+ }
+ }
+ | SET STATEDEFAULTS state_opt_list {
+ if (keep_state_defaults != NULL) {
+ yyerror("cannot redefine state-defaults");
+ YYERROR;
+ }
+ keep_state_defaults = $3;
+ }
+ ;
+
+stringall : STRING { $$ = $1; }
+ | ALL {
+ if (($$ = strdup("all")) == NULL) {
+ err(1, "stringall: strdup");
+ }
+ }
+ ;
+
+string : STRING string {
+ if (asprintf(&$$, "%s %s", $1, $2) == -1)
+ err(1, "string: asprintf");
+ free($1);
+ free($2);
+ }
+ | STRING
+ ;
+
+varstring : numberstring varstring {
+ if (asprintf(&$$, "%s %s", $1, $2) == -1)
+ err(1, "string: asprintf");
+ free($1);
+ free($2);
+ }
+ | numberstring
+ ;
+
+numberstring : NUMBER {
+ char *s;
+ if (asprintf(&s, "%lld", (long long)$1) == -1) {
+ yyerror("string: asprintf");
+ YYERROR;
+ }
+ $$ = s;
+ }
+ | STRING
+ ;
+
+varset : STRING '=' varstring {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("%s = \"%s\"\n", $1, $3);
+ if (symset($1, $3, 0) == -1)
+ err(1, "cannot store variable %s", $1);
+ free($1);
+ free($3);
+ }
+ ;
+
+anchorname : STRING { $$ = $1; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+pfa_anchorlist : /* empty */
+ | pfa_anchorlist '\n'
+ | pfa_anchorlist pfrule '\n'
+ | pfa_anchorlist anchorrule '\n'
+ ;
+
+pfa_anchor : '{'
+ {
+ char ta[PF_ANCHOR_NAME_SIZE];
+ struct pf_ruleset *rs;
+
+ /* steping into a brace anchor */
+ pf->asd++;
+ pf->bn++;
+ pf->brace = 1;
+
+ /* create a holding ruleset in the root */
+ snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
+ rs = pf_find_or_create_ruleset(ta);
+ if (rs == NULL)
+ err(1, "pfa_anchor: pf_find_or_create_ruleset");
+ pf->astack[pf->asd] = rs->anchor;
+ pf->anchor = rs->anchor;
+ } '\n' pfa_anchorlist '}'
+ {
+ pf->alast = pf->anchor;
+ pf->asd--;
+ pf->anchor = pf->astack[pf->asd];
+ }
+ | /* empty */
+ ;
+
+anchorrule : ANCHOR anchorname dir quick interface af proto fromto
+ filter_opts pfa_anchor
+ {
+ struct pf_rule r;
+ struct node_proto *proto;
+
+ if (check_rulestate(PFCTL_STATE_FILTER)) {
+ if ($2)
+ free($2);
+ YYERROR;
+ }
+
+ if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
+ free($2);
+ yyerror("anchor names beginning with '_' "
+ "are reserved for internal use");
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ if (pf->astack[pf->asd + 1]) {
+ /* move inline rules into relative location */
+ pf_anchor_setup(&r,
+ &pf->astack[pf->asd]->ruleset,
+ $2 ? $2 : pf->alast->name);
+
+ if (r.anchor == NULL)
+ err(1, "anchorrule: unable to "
+ "create ruleset");
+
+ if (pf->alast != r.anchor) {
+ if (r.anchor->match) {
+ yyerror("inline anchor '%s' "
+ "already exists",
+ r.anchor->name);
+ YYERROR;
+ }
+ mv_rules(&pf->alast->ruleset,
+ &r.anchor->ruleset);
+ }
+ pf_remove_if_empty_ruleset(&pf->alast->ruleset);
+ pf->alast = r.anchor;
+ } else {
+ if (!$2) {
+ yyerror("anchors without explicit "
+ "rules must specify a name");
+ YYERROR;
+ }
+ }
+ r.direction = $3;
+ r.quick = $4.quick;
+ r.af = $6;
+ r.prob = $9.prob;
+ r.rtableid = $9.rtableid;
+
+ if ($9.tag)
+ if (strlcpy(r.tagname, $9.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if ($9.match_tag)
+ if (strlcpy(r.match_tagname, $9.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $9.match_tag_not;
+ if (rule_label(&r, $9.label))
+ YYERROR;
+ free($9.label);
+ r.flags = $9.flags.b1;
+ r.flagset = $9.flags.b2;
+ if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
+ for (proto = $7; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && $7 != NULL) {
+ if ($9.flags.b1 || $9.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if ($8.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "applies to tcp");
+ YYERROR;
+ }
+ }
+
+ r.tos = $9.tos;
+
+ if ($9.keep.action) {
+ yyerror("cannot specify state handling "
+ "on anchors");
+ YYERROR;
+ }
+
+ if ($9.match_tag)
+ if (strlcpy(r.match_tagname, $9.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $9.match_tag_not;
+ if ($9.marker & FOM_PRIO) {
+ if ($9.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = $9.prio;
+ }
+ if ($9.marker & FOM_SETPRIO) {
+ r.set_prio[0] = $9.set_prio[0];
+ r.set_prio[1] = $9.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ decide_address_family($8.src.host, &r.af);
+ decide_address_family($8.dst.host, &r.af);
+
+ expand_rule(&r, $5, NULL, $7, $8.src_os,
+ $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
+ $9.uid, $9.gid, $9.icmpspec,
+ pf->astack[pf->asd + 1] ? pf->alast->name : $2);
+ free($2);
+ pf->astack[pf->asd + 1] = NULL;
+ }
+ | NATANCHOR string interface af proto fromto rtable {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_NAT;
+ r.af = $4;
+ r.rtableid = $7;
+
+ decide_address_family($6.src.host, &r.af);
+ decide_address_family($6.dst.host, &r.af);
+
+ expand_rule(&r, $3, NULL, $5, $6.src_os,
+ $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
+ 0, 0, 0, $2);
+ free($2);
+ }
+ | RDRANCHOR string interface af proto fromto rtable {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_RDR;
+ r.af = $4;
+ r.rtableid = $7;
+
+ decide_address_family($6.src.host, &r.af);
+ decide_address_family($6.dst.host, &r.af);
+
+ if ($6.src.port != NULL) {
+ yyerror("source port parameter not supported"
+ " in rdr-anchor");
+ YYERROR;
+ }
+ if ($6.dst.port != NULL) {
+ if ($6.dst.port->next != NULL) {
+ yyerror("destination port list "
+ "expansion not supported in "
+ "rdr-anchor");
+ YYERROR;
+ } else if ($6.dst.port->op != PF_OP_EQ) {
+ yyerror("destination port operators"
+ " not supported in rdr-anchor");
+ YYERROR;
+ }
+ r.dst.port[0] = $6.dst.port->port[0];
+ r.dst.port[1] = $6.dst.port->port[1];
+ r.dst.port_op = $6.dst.port->op;
+ }
+
+ expand_rule(&r, $3, NULL, $5, $6.src_os,
+ $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
+ 0, 0, 0, $2);
+ free($2);
+ }
+ | BINATANCHOR string interface af proto fromto rtable {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_BINAT;
+ r.af = $4;
+ r.rtableid = $7;
+ if ($5 != NULL) {
+ if ($5->next != NULL) {
+ yyerror("proto list expansion"
+ " not supported in binat-anchor");
+ YYERROR;
+ }
+ r.proto = $5->proto;
+ free($5);
+ }
+
+ if ($6.src.host != NULL || $6.src.port != NULL ||
+ $6.dst.host != NULL || $6.dst.port != NULL) {
+ yyerror("fromto parameter not supported"
+ " in binat-anchor");
+ YYERROR;
+ }
+
+ decide_address_family($6.src.host, &r.af);
+ decide_address_family($6.dst.host, &r.af);
+
+ pfctl_add_rule(pf, &r, $2);
+ free($2);
+ }
+ ;
+
+loadrule : LOAD ANCHOR string FROM string {
+ struct loadanchors *loadanchor;
+
+ if (strlen(pf->anchor->name) + 1 +
+ strlen($3) >= MAXPATHLEN) {
+ yyerror("anchorname %s too long, max %u\n",
+ $3, MAXPATHLEN - 1);
+ free($3);
+ YYERROR;
+ }
+ loadanchor = calloc(1, sizeof(struct loadanchors));
+ if (loadanchor == NULL)
+ err(1, "loadrule: calloc");
+ if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
+ NULL)
+ err(1, "loadrule: malloc");
+ if (pf->anchor->name[0])
+ snprintf(loadanchor->anchorname, MAXPATHLEN,
+ "%s/%s", pf->anchor->name, $3);
+ else
+ strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
+ if ((loadanchor->filename = strdup($5)) == NULL)
+ err(1, "loadrule: strdup");
+
+ TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
+ entries);
+
+ free($3);
+ free($5);
+ };
+
+scrubaction : no SCRUB {
+ $$.b2 = $$.w = 0;
+ if ($1)
+ $$.b1 = PF_NOSCRUB;
+ else
+ $$.b1 = PF_SCRUB;
+ }
+ ;
+
+scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_SCRUB))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = $1.b1;
+ r.direction = $2;
+
+ r.log = $3.log;
+ r.logif = $3.logif;
+ if ($3.quick) {
+ yyerror("scrub rules do not support 'quick'");
+ YYERROR;
+ }
+
+ r.af = $5;
+ if ($8.nodf)
+ r.rule_flag |= PFRULE_NODF;
+ if ($8.randomid)
+ r.rule_flag |= PFRULE_RANDOMID;
+ if ($8.reassemble_tcp) {
+ if (r.direction != PF_INOUT) {
+ yyerror("reassemble tcp rules can not "
+ "specify direction");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_REASSEMBLE_TCP;
+ }
+ if ($8.minttl)
+ r.min_ttl = $8.minttl;
+ if ($8.maxmss)
+ r.max_mss = $8.maxmss;
+ if ($8.marker & SOM_SETTOS) {
+ r.rule_flag |= PFRULE_SET_TOS;
+ r.set_tos = $8.settos;
+ }
+ if ($8.fragcache)
+ r.rule_flag |= $8.fragcache;
+ if ($8.match_tag)
+ if (strlcpy(r.match_tagname, $8.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $8.match_tag_not;
+ r.rtableid = $8.rtableid;
+
+ expand_rule(&r, $4, NULL, $6, $7.src_os,
+ $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
+ NULL, NULL, NULL, "");
+ }
+ ;
+
+scrub_opts : {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ }
+ scrub_opts_l
+ { $$ = scrub_opts; }
+ | /* empty */ {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ $$ = scrub_opts;
+ }
+ ;
+
+scrub_opts_l : scrub_opts_l scrub_opt
+ | scrub_opt
+ ;
+
+scrub_opt : NODF {
+ if (scrub_opts.nodf) {
+ yyerror("no-df cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.nodf = 1;
+ }
+ | MINTTL NUMBER {
+ if (scrub_opts.marker & SOM_MINTTL) {
+ yyerror("min-ttl cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 255) {
+ yyerror("illegal min-ttl value %d", $2);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MINTTL;
+ scrub_opts.minttl = $2;
+ }
+ | MAXMSS NUMBER {
+ if (scrub_opts.marker & SOM_MAXMSS) {
+ yyerror("max-mss cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 65535) {
+ yyerror("illegal max-mss value %d", $2);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MAXMSS;
+ scrub_opts.maxmss = $2;
+ }
+ | SETTOS tos {
+ if (scrub_opts.marker & SOM_SETTOS) {
+ yyerror("set-tos cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_SETTOS;
+ scrub_opts.settos = $2;
+ }
+ | fragcache {
+ if (scrub_opts.marker & SOM_FRAGCACHE) {
+ yyerror("fragcache cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_FRAGCACHE;
+ scrub_opts.fragcache = $1;
+ }
+ | REASSEMBLE STRING {
+ if (strcasecmp($2, "tcp") != 0) {
+ yyerror("scrub reassemble supports only tcp, "
+ "not '%s'", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ if (scrub_opts.reassemble_tcp) {
+ yyerror("reassemble tcp cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.reassemble_tcp = 1;
+ }
+ | RANDOMID {
+ if (scrub_opts.randomid) {
+ yyerror("random-id cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.randomid = 1;
+ }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ scrub_opts.rtableid = $2;
+ }
+ | not TAGGED string {
+ scrub_opts.match_tag = $3;
+ scrub_opts.match_tag_not = $1;
+ }
+ ;
+
+fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ }
+ | FRAGMENT FRAGCROP { $$ = 0; }
+ | FRAGMENT FRAGDROP { $$ = 0; }
+ ;
+
+antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
+ struct pf_rule r;
+ struct node_host *h = NULL, *hh;
+ struct node_if *i, *j;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ for (i = $3; i; i = i->next) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = $2.log;
+ r.logif = $2.logif;
+ r.quick = $2.quick;
+ r.af = $4;
+ if (rule_label(&r, $5.label))
+ YYERROR;
+ r.rtableid = $5.rtableid;
+ j = calloc(1, sizeof(struct node_if));
+ if (j == NULL)
+ err(1, "antispoof: calloc");
+ if (strlcpy(j->ifname, i->ifname,
+ sizeof(j->ifname)) >= sizeof(j->ifname)) {
+ free(j);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ j->not = 1;
+ if (i->dynamic) {
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->addr.type = PF_ADDR_DYNIFTL;
+ set_ipmask(h, 128);
+ if (strlcpy(h->addr.v.ifname, i->ifname,
+ sizeof(h->addr.v.ifname)) >=
+ sizeof(h->addr.v.ifname)) {
+ free(h);
+ yyerror(
+ "interface name too long");
+ YYERROR;
+ }
+ hh = malloc(sizeof(*hh));
+ if (hh == NULL)
+ err(1, "address: malloc");
+ bcopy(h, hh, sizeof(*hh));
+ h->addr.iflags = PFI_AFLAG_NETWORK;
+ } else {
+ h = ifa_lookup(j->ifname,
+ PFI_AFLAG_NETWORK);
+ hh = NULL;
+ }
+
+ if (h != NULL)
+ expand_rule(&r, j, NULL, NULL, NULL, h,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, "");
+
+ if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = $2.log;
+ r.logif = $2.logif;
+ r.quick = $2.quick;
+ r.af = $4;
+ if (rule_label(&r, $5.label))
+ YYERROR;
+ r.rtableid = $5.rtableid;
+ if (hh != NULL)
+ h = hh;
+ else
+ h = ifa_lookup(i->ifname, 0);
+ if (h != NULL)
+ expand_rule(&r, NULL, NULL,
+ NULL, NULL, h, NULL, NULL,
+ NULL, NULL, NULL, NULL, "");
+ } else
+ free(hh);
+ }
+ free($5.label);
+ }
+ ;
+
+antispoof_ifspc : FOR antispoof_if { $$ = $2; }
+ | FOR '{' optnl antispoof_iflst '}' { $$ = $4; }
+ ;
+
+antispoof_iflst : antispoof_if optnl { $$ = $1; }
+ | antispoof_iflst comma antispoof_if optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+antispoof_if : if_item { $$ = $1; }
+ | '(' if_item ')' {
+ $2->dynamic = 1;
+ $$ = $2;
+ }
+ ;
+
+antispoof_opts : {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ }
+ antispoof_opts_l
+ { $$ = antispoof_opts; }
+ | /* empty */ {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ $$ = antispoof_opts;
+ }
+ ;
+
+antispoof_opts_l : antispoof_opts_l antispoof_opt
+ | antispoof_opt
+ ;
+
+antispoof_opt : label {
+ if (antispoof_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ antispoof_opts.label = $1;
+ }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ antispoof_opts.rtableid = $2;
+ }
+ ;
+
+not : '!' { $$ = 1; }
+ | /* empty */ { $$ = 0; }
+ ;
+
+tabledef : TABLE '<' STRING '>' table_opts {
+ struct node_host *h, *nh;
+ struct node_tinit *ti, *nti;
+
+ if (strlen($3) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name too long, max %d chars",
+ PF_TABLE_NAME_SIZE - 1);
+ free($3);
+ YYERROR;
+ }
+ if (pf->loadopt & PFCTL_FLAG_TABLE)
+ if (process_tabledef($3, &$5)) {
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
+ ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
+ if (ti->file)
+ free(ti->file);
+ for (h = ti->host; h != NULL; h = nh) {
+ nh = h->next;
+ free(h);
+ }
+ nti = SIMPLEQ_NEXT(ti, entries);
+ free(ti);
+ }
+ }
+ ;
+
+table_opts : {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ }
+ table_opts_l
+ { $$ = table_opts; }
+ | /* empty */
+ {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ $$ = table_opts;
+ }
+ ;
+
+table_opts_l : table_opts_l table_opt
+ | table_opt
+ ;
+
+table_opt : STRING {
+ if (!strcmp($1, "const"))
+ table_opts.flags |= PFR_TFLAG_CONST;
+ else if (!strcmp($1, "persist"))
+ table_opts.flags |= PFR_TFLAG_PERSIST;
+ else if (!strcmp($1, "counters"))
+ table_opts.flags |= PFR_TFLAG_COUNTERS;
+ else {
+ yyerror("invalid table option '%s'", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | '{' optnl '}' { table_opts.init_addr = 1; }
+ | '{' optnl host_list '}' {
+ struct node_host *n;
+ struct node_tinit *ti;
+
+ for (n = $3; n != NULL; n = n->next) {
+ switch (n->addr.type) {
+ case PF_ADDR_ADDRMASK:
+ continue; /* ok */
+ case PF_ADDR_RANGE:
+ yyerror("address ranges are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_DYNIFTL:
+ yyerror("dynamic addresses are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_TABLE:
+ yyerror("tables cannot contain tables");
+ break;
+ case PF_ADDR_NOROUTE:
+ yyerror("\"no-route\" is not permitted "
+ "inside tables");
+ break;
+ case PF_ADDR_URPFFAILED:
+ yyerror("\"urpf-failed\" is not "
+ "permitted inside tables");
+ break;
+ default:
+ yyerror("unknown address type %d",
+ n->addr.type);
+ }
+ YYERROR;
+ }
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->host = $3;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+ | FILENAME STRING {
+ struct node_tinit *ti;
+
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->file = $2;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+ ;
+
+altqif : ALTQ interface queue_opts QUEUE qassign {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE))
+ YYERROR;
+
+ memset(&a, 0, sizeof(a));
+ if ($3.scheduler.qtype == ALTQT_NONE) {
+ yyerror("no scheduler specified!");
+ YYERROR;
+ }
+ a.scheduler = $3.scheduler.qtype;
+ a.qlimit = $3.qlimit;
+ a.tbrsize = $3.tbrsize;
+ if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
+ yyerror("no child queues specified");
+ YYERROR;
+ }
+ if (expand_altq(&a, $2, $5, $3.queue_bwspec,
+ &$3.scheduler))
+ YYERROR;
+ }
+ ;
+
+queuespec : QUEUE STRING interface queue_opts qassign {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&a, 0, sizeof(a));
+
+ if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
+ sizeof(a.qname)) {
+ yyerror("queue name too long (max "
+ "%d chars)", PF_QNAME_SIZE-1);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ if ($4.tbrsize) {
+ yyerror("cannot specify tbrsize for queue");
+ YYERROR;
+ }
+ if ($4.priority > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ a.priority = $4.priority;
+ a.qlimit = $4.qlimit;
+ a.scheduler = $4.scheduler.qtype;
+ if (expand_queue(&a, $3, $5, $4.queue_bwspec,
+ &$4.scheduler)) {
+ yyerror("errors in queue definition");
+ YYERROR;
+ }
+ }
+ ;
+
+queue_opts : {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ }
+ queue_opts_l
+ { $$ = queue_opts; }
+ | /* empty */ {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ $$ = queue_opts;
+ }
+ ;
+
+queue_opts_l : queue_opts_l queue_opt
+ | queue_opt
+ ;
+
+queue_opt : BANDWIDTH bandwidth {
+ if (queue_opts.marker & QOM_BWSPEC) {
+ yyerror("bandwidth cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_BWSPEC;
+ queue_opts.queue_bwspec = $2;
+ }
+ | PRIORITY NUMBER {
+ if (queue_opts.marker & QOM_PRIORITY) {
+ yyerror("priority cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_PRIORITY;
+ queue_opts.priority = $2;
+ }
+ | QLIMIT NUMBER {
+ if (queue_opts.marker & QOM_QLIMIT) {
+ yyerror("qlimit cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 65535) {
+ yyerror("qlimit out of range: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_QLIMIT;
+ queue_opts.qlimit = $2;
+ }
+ | scheduler {
+ if (queue_opts.marker & QOM_SCHEDULER) {
+ yyerror("scheduler cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_SCHEDULER;
+ queue_opts.scheduler = $1;
+ }
+ | TBRSIZE NUMBER {
+ if (queue_opts.marker & QOM_TBRSIZE) {
+ yyerror("tbrsize cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 65535) {
+ yyerror("tbrsize too big: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_TBRSIZE;
+ queue_opts.tbrsize = $2;
+ }
+ ;
+
+bandwidth : STRING {
+ double bps;
+ char *cp;
+
+ $$.bw_percent = 0;
+
+ bps = strtod($1, &cp);
+ if (cp != NULL) {
+ if (strlen(cp) > 1) {
+ char *cu = cp + 1;
+ if (!strcmp(cu, "Bit") ||
+ !strcmp(cu, "B") ||
+ !strcmp(cu, "bit") ||
+ !strcmp(cu, "b")) {
+ *cu = 0;
+ }
+ }
+ if (!strcmp(cp, "b"))
+ ; /* nothing */
+ else if (!strcmp(cp, "K"))
+ bps *= 1000;
+ else if (!strcmp(cp, "M"))
+ bps *= 1000 * 1000;
+ else if (!strcmp(cp, "G"))
+ bps *= 1000 * 1000 * 1000;
+ else if (!strcmp(cp, "%")) {
+ if (bps < 0 || bps > 100) {
+ yyerror("bandwidth spec "
+ "out of range");
+ free($1);
+ YYERROR;
+ }
+ $$.bw_percent = bps;
+ bps = 0;
+ } else {
+ yyerror("unknown unit %s", cp);
+ free($1);
+ YYERROR;
+ }
+ }
+ free($1);
+ $$.bw_absolute = (u_int32_t)bps;
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > UINT_MAX) {
+ yyerror("bandwidth number too big");
+ YYERROR;
+ }
+ $$.bw_percent = 0;
+ $$.bw_absolute = $1;
+ }
+ ;
+
+scheduler : CBQ {
+ $$.qtype = ALTQT_CBQ;
+ $$.data.cbq_opts.flags = 0;
+ }
+ | CBQ '(' cbqflags_list ')' {
+ $$.qtype = ALTQT_CBQ;
+ $$.data.cbq_opts.flags = $3;
+ }
+ | PRIQ {
+ $$.qtype = ALTQT_PRIQ;
+ $$.data.priq_opts.flags = 0;
+ }
+ | PRIQ '(' priqflags_list ')' {
+ $$.qtype = ALTQT_PRIQ;
+ $$.data.priq_opts.flags = $3;
+ }
+ | HFSC {
+ $$.qtype = ALTQT_HFSC;
+ bzero(&$$.data.hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+ | HFSC '(' hfsc_opts ')' {
+ $$.qtype = ALTQT_HFSC;
+ $$.data.hfsc_opts = $3;
+ }
+ | FAIRQ {
+ $$.qtype = ALTQT_FAIRQ;
+ bzero(&$$.data.fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ | FAIRQ '(' fairq_opts ')' {
+ $$.qtype = ALTQT_FAIRQ;
+ $$.data.fairq_opts = $3;
+ }
+ | CODEL {
+ $$.qtype = ALTQT_CODEL;
+ bzero(&$$.data.codel_opts,
+ sizeof(struct codel_opts));
+ }
+ | CODEL '(' codel_opts ')' {
+ $$.qtype = ALTQT_CODEL;
+ $$.data.codel_opts = $3;
+ }
+ ;
+
+cbqflags_list : cbqflags_item { $$ |= $1; }
+ | cbqflags_list comma cbqflags_item { $$ |= $3; }
+ ;
+
+cbqflags_item : STRING {
+ if (!strcmp($1, "default"))
+ $$ = CBQCLF_DEFCLASS;
+ else if (!strcmp($1, "borrow"))
+ $$ = CBQCLF_BORROW;
+ else if (!strcmp($1, "red"))
+ $$ = CBQCLF_RED;
+ else if (!strcmp($1, "ecn"))
+ $$ = CBQCLF_RED|CBQCLF_ECN;
+ else if (!strcmp($1, "rio"))
+ $$ = CBQCLF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = CBQCLF_CODEL;
+ else {
+ yyerror("unknown cbq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+priqflags_list : priqflags_item { $$ |= $1; }
+ | priqflags_list comma priqflags_item { $$ |= $3; }
+ ;
+
+priqflags_item : STRING {
+ if (!strcmp($1, "default"))
+ $$ = PRCF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ $$ = PRCF_RED;
+ else if (!strcmp($1, "ecn"))
+ $$ = PRCF_RED|PRCF_ECN;
+ else if (!strcmp($1, "rio"))
+ $$ = PRCF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = PRCF_CODEL;
+ else {
+ yyerror("unknown priq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+hfsc_opts : {
+ bzero(&hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+ hfscopts_list {
+ $$ = hfsc_opts;
+ }
+ ;
+
+hfscopts_list : hfscopts_item
+ | hfscopts_list comma hfscopts_item
+ ;
+
+hfscopts_item : LINKSHARE bandwidth {
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m2 = $2;
+ hfsc_opts.linkshare.used = 1;
+ }
+ | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'
+ {
+ if ($5 < 0 || $5 > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m1 = $3;
+ hfsc_opts.linkshare.d = $5;
+ hfsc_opts.linkshare.m2 = $7;
+ hfsc_opts.linkshare.used = 1;
+ }
+ | REALTIME bandwidth {
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m2 = $2;
+ hfsc_opts.realtime.used = 1;
+ }
+ | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'
+ {
+ if ($5 < 0 || $5 > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m1 = $3;
+ hfsc_opts.realtime.d = $5;
+ hfsc_opts.realtime.m2 = $7;
+ hfsc_opts.realtime.used = 1;
+ }
+ | UPPERLIMIT bandwidth {
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m2 = $2;
+ hfsc_opts.upperlimit.used = 1;
+ }
+ | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'
+ {
+ if ($5 < 0 || $5 > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m1 = $3;
+ hfsc_opts.upperlimit.d = $5;
+ hfsc_opts.upperlimit.m2 = $7;
+ hfsc_opts.upperlimit.used = 1;
+ }
+ | STRING {
+ if (!strcmp($1, "default"))
+ hfsc_opts.flags |= HFCF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ hfsc_opts.flags |= HFCF_RED;
+ else if (!strcmp($1, "ecn"))
+ hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
+ else if (!strcmp($1, "rio"))
+ hfsc_opts.flags |= HFCF_RIO;
+ else if (!strcmp($1, "codel"))
+ hfsc_opts.flags |= HFCF_CODEL;
+ else {
+ yyerror("unknown hfsc flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+fairq_opts : {
+ bzero(&fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ fairqopts_list {
+ $$ = fairq_opts;
+ }
+ ;
+
+fairqopts_list : fairqopts_item
+ | fairqopts_list comma fairqopts_item
+ ;
+
+fairqopts_item : LINKSHARE bandwidth {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m2 = $2;
+ fairq_opts.linkshare.used = 1;
+ }
+ | LINKSHARE '(' bandwidth number bandwidth ')' {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m1 = $3;
+ fairq_opts.linkshare.d = $4;
+ fairq_opts.linkshare.m2 = $5;
+ fairq_opts.linkshare.used = 1;
+ }
+ | HOGS bandwidth {
+ fairq_opts.hogs_bw = $2;
+ }
+ | BUCKETS number {
+ fairq_opts.nbuckets = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "default"))
+ fairq_opts.flags |= FARF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ fairq_opts.flags |= FARF_RED;
+ else if (!strcmp($1, "ecn"))
+ fairq_opts.flags |= FARF_RED|FARF_ECN;
+ else if (!strcmp($1, "rio"))
+ fairq_opts.flags |= FARF_RIO;
+ else if (!strcmp($1, "codel"))
+ fairq_opts.flags |= FARF_CODEL;
+ else {
+ yyerror("unknown fairq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+codel_opts : {
+ bzero(&codel_opts,
+ sizeof(struct codel_opts));
+ }
+ codelopts_list {
+ $$ = codel_opts;
+ }
+ ;
+
+codelopts_list : codelopts_item
+ | codelopts_list comma codelopts_item
+ ;
+
+codelopts_item : INTERVAL number {
+ if (codel_opts.interval) {
+ yyerror("interval already specified");
+ YYERROR;
+ }
+ codel_opts.interval = $2;
+ }
+ | TARGET number {
+ if (codel_opts.target) {
+ yyerror("target already specified");
+ YYERROR;
+ }
+ codel_opts.target = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "ecn"))
+ codel_opts.ecn = 1;
+ else {
+ yyerror("unknown codel option \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+qassign : /* empty */ { $$ = NULL; }
+ | qassign_item { $$ = $1; }
+ | '{' optnl qassign_list '}' { $$ = $3; }
+ ;
+
+qassign_list : qassign_item optnl { $$ = $1; }
+ | qassign_list comma qassign_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+qassign_item : STRING {
+ $$ = calloc(1, sizeof(struct node_queue));
+ if ($$ == NULL)
+ err(1, "qassign_item: calloc");
+ if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
+ sizeof($$->queue)) {
+ yyerror("queue name '%s' too long (max "
+ "%d chars)", $1, sizeof($$->queue)-1);
+ free($1);
+ free($$);
+ YYERROR;
+ }
+ free($1);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+pfrule : action dir logquick interface route af proto fromto
+ filter_opts
+ {
+ struct pf_rule r;
+ struct node_state_opt *o;
+ struct node_proto *proto;
+ int srctrack = 0;
+ int statelock = 0;
+ int adaptive = 0;
+ int defaults = 0;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = $1.b1;
+ switch ($1.b2) {
+ case PFRULE_RETURNRST:
+ r.rule_flag |= PFRULE_RETURNRST;
+ r.return_ttl = $1.w;
+ break;
+ case PFRULE_RETURNICMP:
+ r.rule_flag |= PFRULE_RETURNICMP;
+ r.return_icmp = $1.w;
+ r.return_icmp6 = $1.w2;
+ break;
+ case PFRULE_RETURN:
+ r.rule_flag |= PFRULE_RETURN;
+ r.return_icmp = $1.w;
+ r.return_icmp6 = $1.w2;
+ break;
+ }
+ r.direction = $2;
+ r.log = $3.log;
+ r.logif = $3.logif;
+ r.quick = $3.quick;
+ r.prob = $9.prob;
+ r.rtableid = $9.rtableid;
+
+ if ($9.marker & FOM_PRIO) {
+ if ($9.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = $9.prio;
+ }
+ if ($9.marker & FOM_SETPRIO) {
+ r.set_prio[0] = $9.set_prio[0];
+ r.set_prio[1] = $9.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ r.af = $6;
+ if ($9.tag)
+ if (strlcpy(r.tagname, $9.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if ($9.match_tag)
+ if (strlcpy(r.match_tagname, $9.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $9.match_tag_not;
+ if (rule_label(&r, $9.label))
+ YYERROR;
+ free($9.label);
+ r.flags = $9.flags.b1;
+ r.flagset = $9.flags.b2;
+ if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
+ for (proto = $7; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && $7 != NULL) {
+ if ($9.flags.b1 || $9.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if ($8.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "apply to tcp");
+ YYERROR;
+ }
+#if 0
+ if (($9.flags.b1 & parse_flags("S")) == 0 &&
+ $8.src_os) {
+ yyerror("OS fingerprinting requires "
+ "the SYN TCP flag (flags S/SA)");
+ YYERROR;
+ }
+#endif
+ }
+
+ r.tos = $9.tos;
+ r.keep_state = $9.keep.action;
+ o = $9.keep.options;
+
+ /* 'keep state' by default on pass rules. */
+ if (!r.keep_state && !r.action &&
+ !($9.marker & FOM_KEEP)) {
+ r.keep_state = PF_STATE_NORMAL;
+ o = keep_state_defaults;
+ defaults = 1;
+ }
+
+ while (o) {
+ struct node_state_opt *p = o;
+
+ switch (o->type) {
+ case PF_STATE_OPT_MAX:
+ if (r.max_states) {
+ yyerror("state option 'max' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.max_states = o->data.max_states;
+ break;
+ case PF_STATE_OPT_NOSYNC:
+ if (r.rule_flag & PFRULE_NOSYNC) {
+ yyerror("state option 'sync' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_NOSYNC;
+ break;
+ case PF_STATE_OPT_SRCTRACK:
+ if (srctrack) {
+ yyerror("state option "
+ "'source-track' "
+ "multiple definitions");
+ YYERROR;
+ }
+ srctrack = o->data.src_track;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_STATES:
+ if (r.max_src_states) {
+ yyerror("state option "
+ "'max-src-states' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_states == 0) {
+ yyerror("'max-src-states' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_states =
+ o->data.max_src_states;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_OVERLOAD:
+ if (r.overload_tblname[0]) {
+ yyerror("multiple 'overload' "
+ "table definitions");
+ YYERROR;
+ }
+ if (strlcpy(r.overload_tblname,
+ o->data.overload.tblname,
+ PF_TABLE_NAME_SIZE) >=
+ PF_TABLE_NAME_SIZE) {
+ yyerror("state option: "
+ "strlcpy");
+ YYERROR;
+ }
+ r.flush = o->data.overload.flush;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN:
+ if (r.max_src_conn) {
+ yyerror("state option "
+ "'max-src-conn' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_conn == 0) {
+ yyerror("'max-src-conn' "
+ "must be > 0");
+ YYERROR;
+ }
+ r.max_src_conn =
+ o->data.max_src_conn;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN_RATE:
+ if (r.max_src_conn_rate.limit) {
+ yyerror("state option "
+ "'max-src-conn-rate' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (!o->data.max_src_conn_rate.limit ||
+ !o->data.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' "
+ "values must be > 0");
+ YYERROR;
+ }
+ if (o->data.max_src_conn_rate.limit >
+ PF_THRESHOLD_MAX) {
+ yyerror("'max-src-conn-rate' "
+ "maximum rate must be < %u",
+ PF_THRESHOLD_MAX);
+ YYERROR;
+ }
+ r.max_src_conn_rate.limit =
+ o->data.max_src_conn_rate.limit;
+ r.max_src_conn_rate.seconds =
+ o->data.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_NODES:
+ if (r.max_src_nodes) {
+ yyerror("state option "
+ "'max-src-nodes' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_nodes == 0) {
+ yyerror("'max-src-nodes' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_nodes =
+ o->data.max_src_nodes;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_STATELOCK:
+ if (statelock) {
+ yyerror("state locking option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ statelock = 1;
+ r.rule_flag |= o->data.statelock;
+ break;
+ case PF_STATE_OPT_SLOPPY:
+ if (r.rule_flag & PFRULE_STATESLOPPY) {
+ yyerror("state sloppy option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_STATESLOPPY;
+ break;
+ case PF_STATE_OPT_TIMEOUT:
+ if (o->data.timeout.number ==
+ PFTM_ADAPTIVE_START ||
+ o->data.timeout.number ==
+ PFTM_ADAPTIVE_END)
+ adaptive = 1;
+ if (r.timeout[o->data.timeout.number]) {
+ yyerror("state timeout %s "
+ "multiple definitions",
+ pf_timeouts[o->data.
+ timeout.number].name);
+ YYERROR;
+ }
+ r.timeout[o->data.timeout.number] =
+ o->data.timeout.seconds;
+ }
+ o = o->next;
+ if (!defaults)
+ free(p);
+ }
+
+ /* 'flags S/SA' by default on stateful rules */
+ if (!r.action && !r.flags && !r.flagset &&
+ !$9.fragment && !($9.marker & FOM_FLAGS) &&
+ r.keep_state) {
+ r.flags = parse_flags("S");
+ r.flagset = parse_flags("SA");
+ }
+ if (!adaptive && r.max_states) {
+ r.timeout[PFTM_ADAPTIVE_START] =
+ (r.max_states / 10) * 6;
+ r.timeout[PFTM_ADAPTIVE_END] =
+ (r.max_states / 10) * 12;
+ }
+ if (r.rule_flag & PFRULE_SRCTRACK) {
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_nodes) {
+ yyerror("'max-src-nodes' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn) {
+ yyerror("'max-src-conn' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (r.timeout[PFTM_SRC_NODE] <
+ r.max_src_conn_rate.seconds)
+ r.timeout[PFTM_SRC_NODE] =
+ r.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ if (srctrack == PF_SRCTRACK_RULE)
+ r.rule_flag |= PFRULE_RULESRCTRACK;
+ }
+ if (r.keep_state && !statelock)
+ r.rule_flag |= default_statelock;
+
+ if ($9.fragment)
+ r.rule_flag |= PFRULE_FRAGMENT;
+ r.allow_opts = $9.allowopts;
+
+ decide_address_family($8.src.host, &r.af);
+ decide_address_family($8.dst.host, &r.af);
+
+ if ($5.rt) {
+ if (!r.direction) {
+ yyerror("direction must be explicit "
+ "with rules that specify routing");
+ YYERROR;
+ }
+ r.rt = $5.rt;
+ r.rpool.opts = $5.pool_opts;
+ if ($5.key != NULL)
+ memcpy(&r.rpool.key, $5.key,
+ sizeof(struct pf_poolhashkey));
+ }
+ if (r.rt && r.rt != PF_FASTROUTE) {
+ decide_address_family($5.host, &r.af);
+ remove_invalid_hosts(&$5.host, &r.af);
+ if ($5.host == NULL) {
+ yyerror("no routing address with "
+ "matching address family found.");
+ YYERROR;
+ }
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && ($5.host->next != NULL ||
+ $5.host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($5.host->addr)))
+ r.rpool.opts |= PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table($5.host, "tables are only "
+ "supported in round-robin routing pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($5.host, "interface (%s) "
+ "is only supported in round-robin "
+ "routing pools"))
+ YYERROR;
+ if ($5.host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("r.rpool.opts must "
+ "be PF_POOL_ROUNDROBIN");
+ YYERROR;
+ }
+ }
+ }
+ if ($9.queues.qname != NULL) {
+ if (strlcpy(r.qname, $9.queues.qname,
+ sizeof(r.qname)) >= sizeof(r.qname)) {
+ yyerror("rule qname too long (max "
+ "%d chars)", sizeof(r.qname)-1);
+ YYERROR;
+ }
+ free($9.queues.qname);
+ }
+ if ($9.queues.pqname != NULL) {
+ if (strlcpy(r.pqname, $9.queues.pqname,
+ sizeof(r.pqname)) >= sizeof(r.pqname)) {
+ yyerror("rule pqname too long (max "
+ "%d chars)", sizeof(r.pqname)-1);
+ YYERROR;
+ }
+ free($9.queues.pqname);
+ }
+#ifdef __FreeBSD__
+ r.divert.port = $9.divert.port;
+#else
+ if ((r.divert.port = $9.divert.port)) {
+ if (r.direction == PF_OUT) {
+ if ($9.divert.addr) {
+ yyerror("address specified "
+ "for outgoing divert");
+ YYERROR;
+ }
+ bzero(&r.divert.addr,
+ sizeof(r.divert.addr));
+ } else {
+ if (!$9.divert.addr) {
+ yyerror("no address specified "
+ "for incoming divert");
+ YYERROR;
+ }
+ if ($9.divert.addr->af != r.af) {
+ yyerror("address family "
+ "mismatch for divert");
+ YYERROR;
+ }
+ r.divert.addr =
+ $9.divert.addr->addr.v.a.addr;
+ }
+ }
+#endif
+
+ expand_rule(&r, $4, $5.host, $7, $8.src_os,
+ $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
+ $9.uid, $9.gid, $9.icmpspec, "");
+ }
+ ;
+
+filter_opts : {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ }
+ filter_opts_l
+ { $$ = filter_opts; }
+ | /* empty */ {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ $$ = filter_opts;
+ }
+ ;
+
+filter_opts_l : filter_opts_l filter_opt
+ | filter_opt
+ ;
+
+filter_opt : USER uids {
+ if (filter_opts.uid)
+ $2->tail->next = filter_opts.uid;
+ filter_opts.uid = $2;
+ }
+ | GROUP gids {
+ if (filter_opts.gid)
+ $2->tail->next = filter_opts.gid;
+ filter_opts.gid = $2;
+ }
+ | flags {
+ if (filter_opts.marker & FOM_FLAGS) {
+ yyerror("flags cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_FLAGS;
+ filter_opts.flags.b1 |= $1.b1;
+ filter_opts.flags.b2 |= $1.b2;
+ filter_opts.flags.w |= $1.w;
+ filter_opts.flags.w2 |= $1.w2;
+ }
+ | icmpspec {
+ if (filter_opts.marker & FOM_ICMP) {
+ yyerror("icmp-type cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_ICMP;
+ filter_opts.icmpspec = $1;
+ }
+ | PRIO NUMBER {
+ if (filter_opts.marker & FOM_PRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_PRIO;
+ filter_opts.prio = $2;
+ }
+ | TOS tos {
+ if (filter_opts.marker & FOM_TOS) {
+ yyerror("tos cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_TOS;
+ filter_opts.tos = $2;
+ }
+ | keep {
+ if (filter_opts.marker & FOM_KEEP) {
+ yyerror("modulate or keep cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_KEEP;
+ filter_opts.keep.action = $1.action;
+ filter_opts.keep.options = $1.options;
+ }
+ | FRAGMENT {
+ filter_opts.fragment = 1;
+ }
+ | ALLOWOPTS {
+ filter_opts.allowopts = 1;
+ }
+ | label {
+ if (filter_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.label = $1;
+ }
+ | qname {
+ if (filter_opts.queues.qname) {
+ yyerror("queue cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.queues = $1;
+ }
+ | TAG string {
+ filter_opts.tag = $2;
+ }
+ | not TAGGED string {
+ filter_opts.match_tag = $3;
+ filter_opts.match_tag_not = $1;
+ }
+ | PROBABILITY probability {
+ double p;
+
+ p = floor($2 * UINT_MAX + 0.5);
+ if (p < 0.0 || p > UINT_MAX) {
+ yyerror("invalid probability: %lf", p);
+ YYERROR;
+ }
+ filter_opts.prob = (u_int32_t)p;
+ if (filter_opts.prob == 0)
+ filter_opts.prob = 1;
+ }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ filter_opts.rtableid = $2;
+ }
+ | DIVERTTO portplain {
+#ifdef __FreeBSD__
+ filter_opts.divert.port = $2.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs($2.a));
+ YYERROR;
+ }
+#endif
+ }
+ | DIVERTTO STRING PORT portplain {
+#ifndef __FreeBSD__
+ if ((filter_opts.divert.addr = host($2)) == NULL) {
+ yyerror("could not parse divert address: %s",
+ $2);
+ free($2);
+ YYERROR;
+ }
+#else
+ if ($2)
+#endif
+ free($2);
+ filter_opts.divert.port = $4.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs($4.a));
+ YYERROR;
+ }
+ }
+ | DIVERTREPLY {
+#ifdef __FreeBSD__
+ yyerror("divert-reply has no meaning in FreeBSD pf(4)");
+ YYERROR;
+#else
+ filter_opts.divert.port = 1; /* some random value */
+#endif
+ }
+ | filter_sets
+ ;
+
+filter_sets : SET '(' filter_sets_l ')' { $$ = filter_opts; }
+ | SET filter_set { $$ = filter_opts; }
+ ;
+
+filter_sets_l : filter_sets_l comma filter_set
+ | filter_set
+ ;
+
+filter_set : prio {
+ if (filter_opts.marker & FOM_SETPRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_SETPRIO;
+ filter_opts.set_prio[0] = $1.b1;
+ filter_opts.set_prio[1] = $1.b2;
+ }
+prio : PRIO NUMBER {
+ if ($2 < 0 || $2 > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ $$.b1 = $$.b2 = $2;
+ }
+ | PRIO '(' NUMBER comma NUMBER ')' {
+ if ($3 < 0 || $3 > PF_PRIO_MAX ||
+ $5 < 0 || $5 > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ $$.b1 = $3;
+ $$.b2 = $5;
+ }
+ ;
+
+probability : STRING {
+ char *e;
+ double p = strtod($1, &e);
+
+ if (*e == '%') {
+ p *= 0.01;
+ e++;
+ }
+ if (*e) {
+ yyerror("invalid probability: %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$ = p;
+ }
+ | NUMBER {
+ $$ = (double)$1;
+ }
+ ;
+
+
+action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
+ | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; }
+ ;
+
+blockspec : /* empty */ {
+ $$.b2 = blockpolicy;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ | DROP {
+ $$.b2 = PFRULE_DROP;
+ $$.w = 0;
+ $$.w2 = 0;
+ }
+ | RETURNRST {
+ $$.b2 = PFRULE_RETURNRST;
+ $$.w = 0;
+ $$.w2 = 0;
+ }
+ | RETURNRST '(' TTL NUMBER ')' {
+ if ($4 < 0 || $4 > 255) {
+ yyerror("illegal ttl value %d", $4);
+ YYERROR;
+ }
+ $$.b2 = PFRULE_RETURNRST;
+ $$.w = $4;
+ $$.w2 = 0;
+ }
+ | RETURNICMP {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ | RETURNICMP6 {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ | RETURNICMP '(' reticmpspec ')' {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = $3;
+ $$.w2 = returnicmpdefault;
+ }
+ | RETURNICMP6 '(' reticmp6spec ')' {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = returnicmpdefault;
+ $$.w2 = $3;
+ }
+ | RETURNICMP '(' reticmpspec comma reticmp6spec ')' {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = $3;
+ $$.w2 = $5;
+ }
+ | RETURN {
+ $$.b2 = PFRULE_RETURN;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ ;
+
+reticmpspec : STRING {
+ if (!($$ = parseicmpspec($1, AF_INET))) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | NUMBER {
+ u_int8_t icmptype;
+
+ if ($1 < 0 || $1 > 255) {
+ yyerror("invalid icmp code %lu", $1);
+ YYERROR;
+ }
+ icmptype = returnicmpdefault >> 8;
+ $$ = (icmptype << 8 | $1);
+ }
+ ;
+
+reticmp6spec : STRING {
+ if (!($$ = parseicmpspec($1, AF_INET6))) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | NUMBER {
+ u_int8_t icmptype;
+
+ if ($1 < 0 || $1 > 255) {
+ yyerror("invalid icmp code %lu", $1);
+ YYERROR;
+ }
+ icmptype = returnicmp6default >> 8;
+ $$ = (icmptype << 8 | $1);
+ }
+ ;
+
+dir : /* empty */ { $$ = PF_INOUT; }
+ | IN { $$ = PF_IN; }
+ | OUT { $$ = PF_OUT; }
+ ;
+
+quick : /* empty */ { $$.quick = 0; }
+ | QUICK { $$.quick = 1; }
+ ;
+
+logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; }
+ | log { $$ = $1; $$.quick = 0; }
+ | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; }
+ | log QUICK { $$ = $1; $$.quick = 1; }
+ | QUICK log { $$ = $2; $$.quick = 1; }
+ ;
+
+log : LOG { $$.log = PF_LOG; $$.logif = 0; }
+ | LOG '(' logopts ')' {
+ $$.log = PF_LOG | $3.log;
+ $$.logif = $3.logif;
+ }
+ ;
+
+logopts : logopt { $$ = $1; }
+ | logopts comma logopt {
+ $$.log = $1.log | $3.log;
+ $$.logif = $3.logif;
+ if ($$.logif == 0)
+ $$.logif = $1.logif;
+ }
+ ;
+
+logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; }
+ | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
+ | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
+ | TO string {
+ const char *errstr;
+ u_int i;
+
+ $$.log = 0;
+ if (strncmp($2, "pflog", 5)) {
+ yyerror("%s: should be a pflog interface", $2);
+ free($2);
+ YYERROR;
+ }
+ i = strtonum($2 + 5, 0, 255, &errstr);
+ if (errstr) {
+ yyerror("%s: %s", $2, errstr);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ $$.logif = i;
+ }
+ ;
+
+interface : /* empty */ { $$ = NULL; }
+ | ON if_item_not { $$ = $2; }
+ | ON '{' optnl if_list '}' { $$ = $4; }
+ ;
+
+if_list : if_item_not optnl { $$ = $1; }
+ | if_list comma if_item_not optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+if_item_not : not if_item { $$ = $2; $$->not = $1; }
+ ;
+
+if_item : STRING {
+ struct node_host *n;
+
+ $$ = calloc(1, sizeof(struct node_if));
+ if ($$ == NULL)
+ err(1, "if_item: calloc");
+ if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
+ sizeof($$->ifname)) {
+ free($1);
+ free($$);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+
+ if ((n = ifa_exists($1)) != NULL)
+ $$->ifa_flags = n->ifa_flags;
+
+ free($1);
+ $$->not = 0;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+af : /* empty */ { $$ = 0; }
+ | INET { $$ = AF_INET; }
+ | INET6 { $$ = AF_INET6; }
+ ;
+
+proto : /* empty */ { $$ = NULL; }
+ | PROTO proto_item { $$ = $2; }
+ | PROTO '{' optnl proto_list '}' { $$ = $4; }
+ ;
+
+proto_list : proto_item optnl { $$ = $1; }
+ | proto_list comma proto_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+proto_item : protoval {
+ u_int8_t pr;
+
+ pr = (u_int8_t)$1;
+ if (pr == 0) {
+ yyerror("proto 0 cannot be used");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_proto));
+ if ($$ == NULL)
+ err(1, "proto_item: calloc");
+ $$->proto = pr;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+protoval : STRING {
+ struct protoent *p;
+
+ p = getprotobyname($1);
+ if (p == NULL) {
+ yyerror("unknown protocol %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = p->p_proto;
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > 255) {
+ yyerror("protocol outside range");
+ YYERROR;
+ }
+ }
+ ;
+
+fromto : ALL {
+ $$.src.host = NULL;
+ $$.src.port = NULL;
+ $$.dst.host = NULL;
+ $$.dst.port = NULL;
+ $$.src_os = NULL;
+ }
+ | from os to {
+ $$.src = $1;
+ $$.src_os = $2;
+ $$.dst = $3;
+ }
+ ;
+
+os : /* empty */ { $$ = NULL; }
+ | OS xos { $$ = $2; }
+ | OS '{' optnl os_list '}' { $$ = $4; }
+ ;
+
+xos : STRING {
+ $$ = calloc(1, sizeof(struct node_os));
+ if ($$ == NULL)
+ err(1, "os: calloc");
+ $$->os = $1;
+ $$->tail = $$;
+ }
+ ;
+
+os_list : xos optnl { $$ = $1; }
+ | os_list comma xos optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+from : /* empty */ {
+ $$.host = NULL;
+ $$.port = NULL;
+ }
+ | FROM ipportspec {
+ $$ = $2;
+ }
+ ;
+
+to : /* empty */ {
+ $$.host = NULL;
+ $$.port = NULL;
+ }
+ | TO ipportspec {
+ if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
+ "not permitted in a destination address"))
+ YYERROR;
+ $$ = $2;
+ }
+ ;
+
+ipportspec : ipspec {
+ $$.host = $1;
+ $$.port = NULL;
+ }
+ | ipspec PORT portspec {
+ $$.host = $1;
+ $$.port = $3;
+ }
+ | PORT portspec {
+ $$.host = NULL;
+ $$.port = $2;
+ }
+ ;
+
+optnl : '\n' optnl
+ |
+ ;
+
+ipspec : ANY { $$ = NULL; }
+ | xhost { $$ = $1; }
+ | '{' optnl host_list '}' { $$ = $3; }
+ ;
+
+toipspec : TO ipspec { $$ = $2; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+host_list : ipspec optnl { $$ = $1; }
+ | host_list comma ipspec optnl {
+ if ($3 == NULL)
+ $$ = $1;
+ else if ($1 == NULL)
+ $$ = $3;
+ else {
+ $1->tail->next = $3;
+ $1->tail = $3->tail;
+ $$ = $1;
+ }
+ }
+ ;
+
+xhost : not host {
+ struct node_host *n;
+
+ for (n = $2; n != NULL; n = n->next)
+ n->not = $1;
+ $$ = $2;
+ }
+ | not NOROUTE {
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "xhost: calloc");
+ $$->addr.type = PF_ADDR_NOROUTE;
+ $$->next = NULL;
+ $$->not = $1;
+ $$->tail = $$;
+ }
+ | not URPFFAILED {
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "xhost: calloc");
+ $$->addr.type = PF_ADDR_URPFFAILED;
+ $$->next = NULL;
+ $$->not = $1;
+ $$->tail = $$;
+ }
+ ;
+
+host : STRING {
+ if (($$ = host($1)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free($1);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free($1);
+
+ }
+ | STRING '-' STRING {
+ struct node_host *b, *e;
+
+ if ((b = host($1)) == NULL || (e = host($3)) == NULL) {
+ free($1);
+ free($3);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ if (b->af != e->af ||
+ b->addr.type != PF_ADDR_ADDRMASK ||
+ e->addr.type != PF_ADDR_ADDRMASK ||
+ unmask(&b->addr.v.a.mask, b->af) !=
+ (b->af == AF_INET ? 32 : 128) ||
+ unmask(&e->addr.v.a.mask, e->af) !=
+ (e->af == AF_INET ? 32 : 128) ||
+ b->next != NULL || b->not ||
+ e->next != NULL || e->not) {
+ free(b);
+ free(e);
+ free($1);
+ free($3);
+ yyerror("invalid address range");
+ YYERROR;
+ }
+ memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
+ sizeof(b->addr.v.a.mask));
+ b->addr.type = PF_ADDR_RANGE;
+ $$ = b;
+ free(e);
+ free($1);
+ free($3);
+ }
+ | STRING '/' NUMBER {
+ char *buf;
+
+ if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1)
+ err(1, "host: asprintf");
+ free($1);
+ if (($$ = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+ | NUMBER '/' NUMBER {
+ char *buf;
+
+ /* ie. for 10/8 parsing */
+#ifdef __FreeBSD__
+ if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1)
+#else
+ if (asprintf(&buf, "%lld/%lld", $1, $3) == -1)
+#endif
+ err(1, "host: asprintf");
+ if (($$ = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+ | dynaddr
+ | dynaddr '/' NUMBER {
+ struct node_host *n;
+
+ if ($3 < 0 || $3 > 128) {
+ yyerror("bit number too big");
+ YYERROR;
+ }
+ $$ = $1;
+ for (n = $1; n != NULL; n = n->next)
+ set_ipmask(n, $3);
+ }
+ | '<' STRING '>' {
+ if (strlen($2) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", $2);
+ free($2);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "host: calloc");
+ $$->addr.type = PF_ADDR_TABLE;
+ if (strlcpy($$->addr.v.tblname, $2,
+ sizeof($$->addr.v.tblname)) >=
+ sizeof($$->addr.v.tblname))
+ errx(1, "host: strlcpy");
+ free($2);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+number : NUMBER
+ | STRING {
+ u_long ulval;
+
+ if (atoul($1, &ulval) == -1) {
+ yyerror("%s is not a number", $1);
+ free($1);
+ YYERROR;
+ } else
+ $$ = ulval;
+ free($1);
+ }
+ ;
+
+dynaddr : '(' STRING ')' {
+ int flags = 0;
+ char *p, *op;
+
+ op = $2;
+ if (!isalpha(op[0])) {
+ yyerror("invalid interface name '%s'", op);
+ free(op);
+ YYERROR;
+ }
+ while ((p = strrchr($2, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ yyerror("interface %s has bad modifier",
+ $2);
+ free(op);
+ YYERROR;
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
+ free(op);
+ yyerror("illegal combination of "
+ "interface modifiers");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "address: calloc");
+ $$->af = 0;
+ set_ipmask($$, 128);
+ $$->addr.type = PF_ADDR_DYNIFTL;
+ $$->addr.iflags = flags;
+ if (strlcpy($$->addr.v.ifname, $2,
+ sizeof($$->addr.v.ifname)) >=
+ sizeof($$->addr.v.ifname)) {
+ free(op);
+ free($$);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ free(op);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+portspec : port_item { $$ = $1; }
+ | '{' optnl port_list '}' { $$ = $3; }
+ ;
+
+port_list : port_item optnl { $$ = $1; }
+ | port_list comma port_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+port_item : portrange {
+ $$ = calloc(1, sizeof(struct node_port));
+ if ($$ == NULL)
+ err(1, "port_item: calloc");
+ $$->port[0] = $1.a;
+ $$->port[1] = $1.b;
+ if ($1.t)
+ $$->op = PF_OP_RRG;
+ else
+ $$->op = PF_OP_EQ;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | unaryop portrange {
+ if ($2.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_port));
+ if ($$ == NULL)
+ err(1, "port_item: calloc");
+ $$->port[0] = $2.a;
+ $$->port[1] = $2.b;
+ $$->op = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | portrange PORTBINARY portrange {
+ if ($1.t || $3.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_port));
+ if ($$ == NULL)
+ err(1, "port_item: calloc");
+ $$->port[0] = $1.a;
+ $$->port[1] = $3.a;
+ $$->op = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+portplain : numberstring {
+ if (parseport($1, &$$, 0) == -1) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+portrange : numberstring {
+ if (parseport($1, &$$, PPORT_RANGE) == -1) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+uids : uid_item { $$ = $1; }
+ | '{' optnl uid_list '}' { $$ = $3; }
+ ;
+
+uid_list : uid_item optnl { $$ = $1; }
+ | uid_list comma uid_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+uid_item : uid {
+ $$ = calloc(1, sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: calloc");
+ $$->uid[0] = $1;
+ $$->uid[1] = $1;
+ $$->op = PF_OP_EQ;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | unaryop uid {
+ if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: calloc");
+ $$->uid[0] = $2;
+ $$->uid[1] = $2;
+ $$->op = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | uid PORTBINARY uid {
+ if ($1 == UID_MAX || $3 == UID_MAX) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: calloc");
+ $$->uid[0] = $1;
+ $$->uid[1] = $3;
+ $$->op = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+uid : STRING {
+ if (!strcmp($1, "unknown"))
+ $$ = UID_MAX;
+ else {
+ struct passwd *pw;
+
+ if ((pw = getpwnam($1)) == NULL) {
+ yyerror("unknown user %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = pw->pw_uid;
+ }
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 >= UID_MAX) {
+ yyerror("illegal uid value %lu", $1);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+gids : gid_item { $$ = $1; }
+ | '{' optnl gid_list '}' { $$ = $3; }
+ ;
+
+gid_list : gid_item optnl { $$ = $1; }
+ | gid_list comma gid_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+gid_item : gid {
+ $$ = calloc(1, sizeof(struct node_gid));
+ if ($$ == NULL)
+ err(1, "gid_item: calloc");
+ $$->gid[0] = $1;
+ $$->gid[1] = $1;
+ $$->op = PF_OP_EQ;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | unaryop gid {
+ if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_gid));
+ if ($$ == NULL)
+ err(1, "gid_item: calloc");
+ $$->gid[0] = $2;
+ $$->gid[1] = $2;
+ $$->op = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | gid PORTBINARY gid {
+ if ($1 == GID_MAX || $3 == GID_MAX) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_gid));
+ if ($$ == NULL)
+ err(1, "gid_item: calloc");
+ $$->gid[0] = $1;
+ $$->gid[1] = $3;
+ $$->op = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+gid : STRING {
+ if (!strcmp($1, "unknown"))
+ $$ = GID_MAX;
+ else {
+ struct group *grp;
+
+ if ((grp = getgrnam($1)) == NULL) {
+ yyerror("unknown group %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = grp->gr_gid;
+ }
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 >= GID_MAX) {
+ yyerror("illegal gid value %lu", $1);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+flag : STRING {
+ int f;
+
+ if ((f = parse_flags($1)) < 0) {
+ yyerror("bad flags %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$.b1 = f;
+ }
+ ;
+
+flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; }
+ | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; }
+ | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; }
+ ;
+
+icmpspec : ICMPTYPE icmp_item { $$ = $2; }
+ | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; }
+ | ICMP6TYPE icmp6_item { $$ = $2; }
+ | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; }
+ ;
+
+icmp_list : icmp_item optnl { $$ = $1; }
+ | icmp_list comma icmp_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+icmp6_list : icmp6_item optnl { $$ = $1; }
+ | icmp6_list comma icmp6_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+icmp_item : icmptype {
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = 0;
+ $$->proto = IPPROTO_ICMP;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmptype CODE STRING {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) {
+ yyerror("unknown icmp-code %s", $3);
+ free($3);
+ YYERROR;
+ }
+
+ free($3);
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = p->code + 1;
+ $$->proto = IPPROTO_ICMP;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmptype CODE NUMBER {
+ if ($3 < 0 || $3 > 255) {
+ yyerror("illegal icmp-code %lu", $3);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = $3 + 1;
+ $$->proto = IPPROTO_ICMP;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+icmp6_item : icmp6type {
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = 0;
+ $$->proto = IPPROTO_ICMPV6;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmp6type CODE STRING {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) {
+ yyerror("unknown icmp6-code %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = p->code + 1;
+ $$->proto = IPPROTO_ICMPV6;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmp6type CODE NUMBER {
+ if ($3 < 0 || $3 > 255) {
+ yyerror("illegal icmp-code %lu", $3);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = $3 + 1;
+ $$->proto = IPPROTO_ICMPV6;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+icmptype : STRING {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
+ yyerror("unknown icmp-type %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = p->type + 1;
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > 255) {
+ yyerror("illegal icmp-type %lu", $1);
+ YYERROR;
+ }
+ $$ = $1 + 1;
+ }
+ ;
+
+icmp6type : STRING {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname($1, AF_INET6)) ==
+ NULL) {
+ yyerror("unknown icmp6-type %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = p->type + 1;
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > 255) {
+ yyerror("illegal icmp6-type %lu", $1);
+ YYERROR;
+ }
+ $$ = $1 + 1;
+ }
+ ;
+
+tos : STRING {
+ if (!strcmp($1, "lowdelay"))
+ $$ = IPTOS_LOWDELAY;
+ else if (!strcmp($1, "throughput"))
+ $$ = IPTOS_THROUGHPUT;
+ else if (!strcmp($1, "reliability"))
+ $$ = IPTOS_RELIABILITY;
+ else if ($1[0] == '0' && $1[1] == 'x')
+ $$ = strtoul($1, NULL, 16);
+ else
+ $$ = 256; /* flag bad argument */
+ if ($$ < 0 || $$ > 255) {
+ yyerror("illegal tos value %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | NUMBER {
+ $$ = $1;
+ if ($$ < 0 || $$ > 255) {
+ yyerror("illegal tos value %s", $1);
+ YYERROR;
+ }
+ }
+ ;
+
+sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; }
+ | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; }
+ | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; }
+ ;
+
+statelock : IFBOUND {
+ $$ = PFRULE_IFBOUND;
+ }
+ | FLOATING {
+ $$ = 0;
+ }
+ ;
+
+keep : NO STATE {
+ $$.action = 0;
+ $$.options = NULL;
+ }
+ | KEEP STATE state_opt_spec {
+ $$.action = PF_STATE_NORMAL;
+ $$.options = $3;
+ }
+ | MODULATE STATE state_opt_spec {
+ $$.action = PF_STATE_MODULATE;
+ $$.options = $3;
+ }
+ | SYNPROXY STATE state_opt_spec {
+ $$.action = PF_STATE_SYNPROXY;
+ $$.options = $3;
+ }
+ ;
+
+flush : /* empty */ { $$ = 0; }
+ | FLUSH { $$ = PF_FLUSH; }
+ | FLUSH GLOBAL {
+ $$ = PF_FLUSH | PF_FLUSH_GLOBAL;
+ }
+ ;
+
+state_opt_spec : '(' state_opt_list ')' { $$ = $2; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+state_opt_list : state_opt_item { $$ = $1; }
+ | state_opt_list comma state_opt_item {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+state_opt_item : MAXIMUM NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX;
+ $$->data.max_states = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | NOSYNC {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_NOSYNC;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCSTATES NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_STATES;
+ $$->data.max_src_states = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCCONN NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_CONN;
+ $$->data.max_src_conn = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCCONNRATE NUMBER '/' NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX ||
+ $4 < 0 || $4 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
+ $$->data.max_src_conn_rate.limit = $2;
+ $$->data.max_src_conn_rate.seconds = $4;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | OVERLOAD '<' STRING '>' flush {
+ if (strlen($3) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", $3);
+ free($3);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ if (strlcpy($$->data.overload.tblname, $3,
+ PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
+ errx(1, "state_opt_item: strlcpy");
+ free($3);
+ $$->type = PF_STATE_OPT_OVERLOAD;
+ $$->data.overload.flush = $5;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCNODES NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_NODES;
+ $$->data.max_src_nodes = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | sourcetrack {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_SRCTRACK;
+ $$->data.src_track = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | statelock {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_STATELOCK;
+ $$->data.statelock = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | SLOPPY {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_SLOPPY;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | STRING NUMBER {
+ int i;
+
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ for (i = 0; pf_timeouts[i].name &&
+ strcmp(pf_timeouts[i].name, $1); ++i)
+ ; /* nothing */
+ if (!pf_timeouts[i].name) {
+ yyerror("illegal timeout name %s", $1);
+ free($1);
+ YYERROR;
+ }
+ if (strchr(pf_timeouts[i].name, '.') == NULL) {
+ yyerror("illegal state timeout %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_TIMEOUT;
+ $$->data.timeout.number = pf_timeouts[i].timeout;
+ $$->data.timeout.seconds = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+label : LABEL STRING {
+ $$ = $2;
+ }
+ ;
+
+qname : QUEUE STRING {
+ $$.qname = $2;
+ $$.pqname = NULL;
+ }
+ | QUEUE '(' STRING ')' {
+ $$.qname = $3;
+ $$.pqname = NULL;
+ }
+ | QUEUE '(' STRING comma STRING ')' {
+ $$.qname = $3;
+ $$.pqname = $5;
+ }
+ ;
+
+no : /* empty */ { $$ = 0; }
+ | NO { $$ = 1; }
+ ;
+
+portstar : numberstring {
+ if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+redirspec : host { $$ = $1; }
+ | '{' optnl redir_host_list '}' { $$ = $3; }
+ ;
+
+redir_host_list : host optnl { $$ = $1; }
+ | redir_host_list comma host optnl {
+ $1->tail->next = $3;
+ $1->tail = $3->tail;
+ $$ = $1;
+ }
+ ;
+
+redirpool : /* empty */ { $$ = NULL; }
+ | ARROW redirspec {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport.a = $$->rport.b = $$->rport.t = 0;
+ }
+ | ARROW redirspec PORT portstar {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport = $4;
+ }
+ ;
+
+hashkey : /* empty */
+ {
+ $$ = calloc(1, sizeof(struct pf_poolhashkey));
+ if ($$ == NULL)
+ err(1, "hashkey: calloc");
+ $$->key32[0] = arc4random();
+ $$->key32[1] = arc4random();
+ $$->key32[2] = arc4random();
+ $$->key32[3] = arc4random();
+ }
+ | string
+ {
+ if (!strncmp($1, "0x", 2)) {
+ if (strlen($1) != 34) {
+ free($1);
+ yyerror("hex key must be 128 bits "
+ "(32 hex digits) long");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct pf_poolhashkey));
+ if ($$ == NULL)
+ err(1, "hashkey: calloc");
+
+ if (sscanf($1, "0x%8x%8x%8x%8x",
+ &$$->key32[0], &$$->key32[1],
+ &$$->key32[2], &$$->key32[3]) != 4) {
+ free($$);
+ free($1);
+ yyerror("invalid hex key");
+ YYERROR;
+ }
+ } else {
+ MD5_CTX context;
+
+ $$ = calloc(1, sizeof(struct pf_poolhashkey));
+ if ($$ == NULL)
+ err(1, "hashkey: calloc");
+ MD5Init(&context);
+ MD5Update(&context, (unsigned char *)$1,
+ strlen($1));
+ MD5Final((unsigned char *)$$, &context);
+ HTONL($$->key32[0]);
+ HTONL($$->key32[1]);
+ HTONL($$->key32[2]);
+ HTONL($$->key32[3]);
+ }
+ free($1);
+ }
+ ;
+
+pool_opts : { bzero(&pool_opts, sizeof pool_opts); }
+ pool_opts_l
+ { $$ = pool_opts; }
+ | /* empty */ {
+ bzero(&pool_opts, sizeof pool_opts);
+ $$ = pool_opts;
+ }
+ ;
+
+pool_opts_l : pool_opts_l pool_opt
+ | pool_opt
+ ;
+
+pool_opt : BITMASK {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_BITMASK;
+ }
+ | RANDOM {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_RANDOM;
+ }
+ | SOURCEHASH hashkey {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_SRCHASH;
+ pool_opts.key = $2;
+ }
+ | ROUNDROBIN {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_ROUNDROBIN;
+ }
+ | STATICPORT {
+ if (pool_opts.staticport) {
+ yyerror("static-port cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.staticport = 1;
+ }
+ | STICKYADDRESS {
+ if (filter_opts.marker & POM_STICKYADDRESS) {
+ yyerror("sticky-address cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.marker |= POM_STICKYADDRESS;
+ pool_opts.opts |= PF_POOL_STICKYADDR;
+ }
+ ;
+
+redirection : /* empty */ { $$ = NULL; }
+ | ARROW host {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport.a = $$->rport.b = $$->rport.t = 0;
+ }
+ | ARROW host PORT portstar {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport = $4;
+ }
+ ;
+
+natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; }
+ | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
+ | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
+ | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
+ ;
+
+nataction : no NAT natpasslog {
+ if ($1 && $3.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if ($1)
+ $$.b1 = PF_NONAT;
+ else
+ $$.b1 = PF_NAT;
+ $$.b2 = $3.b1;
+ $$.w = $3.b2;
+ $$.w2 = $3.w2;
+ }
+ | no RDR natpasslog {
+ if ($1 && $3.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if ($1)
+ $$.b1 = PF_NORDR;
+ else
+ $$.b1 = PF_RDR;
+ $$.b2 = $3.b1;
+ $$.w = $3.b2;
+ $$.w2 = $3.w2;
+ }
+ ;
+
+natrule : nataction interface af proto fromto tag tagged rtable
+ redirpool pool_opts
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = $1.b1;
+ r.natpass = $1.b2;
+ r.log = $1.w;
+ r.logif = $1.w2;
+ r.af = $3;
+
+ if (!r.af) {
+ if ($5.src.host && $5.src.host->af &&
+ !$5.src.host->ifindex)
+ r.af = $5.src.host->af;
+ else if ($5.dst.host && $5.dst.host->af &&
+ !$5.dst.host->ifindex)
+ r.af = $5.dst.host->af;
+ }
+
+ if ($6 != NULL)
+ if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
+ PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+
+ if ($7.name)
+ if (strlcpy(r.match_tagname, $7.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $7.neg;
+ r.rtableid = $8;
+
+ if (r.action == PF_NONAT || r.action == PF_NORDR) {
+ if ($9 != NULL) {
+ yyerror("translation rule with 'no' "
+ "does not need '->'");
+ YYERROR;
+ }
+ } else {
+ if ($9 == NULL || $9->host == NULL) {
+ yyerror("translation rule requires '-> "
+ "address'");
+ YYERROR;
+ }
+ if (!r.af && ! $9->host->ifindex)
+ r.af = $9->host->af;
+
+ remove_invalid_hosts(&$9->host, &r.af);
+ if (invalid_redirect($9->host, r.af))
+ YYERROR;
+ if (check_netmask($9->host, r.af))
+ YYERROR;
+
+ r.rpool.proxy_port[0] = ntohs($9->rport.a);
+
+ switch (r.action) {
+ case PF_RDR:
+ if (!$9->rport.b && $9->rport.t &&
+ $5.dst.port != NULL) {
+ r.rpool.proxy_port[1] =
+ ntohs($9->rport.a) +
+ (ntohs(
+ $5.dst.port->port[1]) -
+ ntohs(
+ $5.dst.port->port[0]));
+ } else
+ r.rpool.proxy_port[1] =
+ ntohs($9->rport.b);
+ break;
+ case PF_NAT:
+ r.rpool.proxy_port[1] =
+ ntohs($9->rport.b);
+ if (!r.rpool.proxy_port[0] &&
+ !r.rpool.proxy_port[1]) {
+ r.rpool.proxy_port[0] =
+ PF_NAT_PROXY_PORT_LOW;
+ r.rpool.proxy_port[1] =
+ PF_NAT_PROXY_PORT_HIGH;
+ } else if (!r.rpool.proxy_port[1])
+ r.rpool.proxy_port[1] =
+ r.rpool.proxy_port[0];
+ break;
+ default:
+ break;
+ }
+
+ r.rpool.opts = $10.type;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && ($9->host->next != NULL ||
+ $9->host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($9->host->addr)))
+ r.rpool.opts = PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table($9->host, "tables are only "
+ "supported in round-robin redirection "
+ "pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($9->host, "interface (%s) "
+ "is only supported in round-robin "
+ "redirection pools"))
+ YYERROR;
+ if ($9->host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("only round-robin "
+ "valid for multiple "
+ "redirection addresses");
+ YYERROR;
+ }
+ }
+ }
+
+ if ($10.key != NULL)
+ memcpy(&r.rpool.key, $10.key,
+ sizeof(struct pf_poolhashkey));
+
+ if ($10.opts)
+ r.rpool.opts |= $10.opts;
+
+ if ($10.staticport) {
+ if (r.action != PF_NAT) {
+ yyerror("the 'static-port' option is "
+ "only valid with nat rules");
+ YYERROR;
+ }
+ if (r.rpool.proxy_port[0] !=
+ PF_NAT_PROXY_PORT_LOW &&
+ r.rpool.proxy_port[1] !=
+ PF_NAT_PROXY_PORT_HIGH) {
+ yyerror("the 'static-port' option can't"
+ " be used when specifying a port"
+ " range");
+ YYERROR;
+ }
+ r.rpool.proxy_port[0] = 0;
+ r.rpool.proxy_port[1] = 0;
+ }
+
+ expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
+ $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
+ $5.dst.port, 0, 0, 0, "");
+ free($9);
+ }
+ ;
+
+binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
+ tagged rtable redirection
+ {
+ struct pf_rule binat;
+ struct pf_pooladdr *pa;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+ if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
+ "permitted as a binat destination"))
+ YYERROR;
+
+ memset(&binat, 0, sizeof(binat));
+
+ if ($1 && $3.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if ($1)
+ binat.action = PF_NOBINAT;
+ else
+ binat.action = PF_BINAT;
+ binat.natpass = $3.b1;
+ binat.log = $3.b2;
+ binat.logif = $3.w2;
+ binat.af = $5;
+ if (!binat.af && $8 != NULL && $8->af)
+ binat.af = $8->af;
+ if (!binat.af && $9 != NULL && $9->af)
+ binat.af = $9->af;
+
+ if (!binat.af && $13 != NULL && $13->host)
+ binat.af = $13->host->af;
+ if (!binat.af) {
+ yyerror("address family (inet/inet6) "
+ "undefined");
+ YYERROR;
+ }
+
+ if ($4 != NULL) {
+ memcpy(binat.ifname, $4->ifname,
+ sizeof(binat.ifname));
+ binat.ifnot = $4->not;
+ free($4);
+ }
+
+ if ($10 != NULL)
+ if (strlcpy(binat.tagname, $10,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if ($11.name)
+ if (strlcpy(binat.match_tagname, $11.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ binat.match_tag_not = $11.neg;
+ binat.rtableid = $12;
+
+ if ($6 != NULL) {
+ binat.proto = $6->proto;
+ free($6);
+ }
+
+ if ($8 != NULL && disallow_table($8, "invalid use of "
+ "table <%s> as the source address of a binat rule"))
+ YYERROR;
+ if ($8 != NULL && disallow_alias($8, "invalid use of "
+ "interface (%s) as the source address of a binat "
+ "rule"))
+ YYERROR;
+ if ($13 != NULL && $13->host != NULL && disallow_table(
+ $13->host, "invalid use of table <%s> as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+ if ($13 != NULL && $13->host != NULL && disallow_alias(
+ $13->host, "invalid use of interface (%s) as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+
+ if ($8 != NULL) {
+ if ($8->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if ($8->addr.type == PF_ADDR_DYNIFTL)
+ $8->af = binat.af;
+ if ($8->af != binat.af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask($8, binat.af))
+ YYERROR;
+ memcpy(&binat.src.addr, &$8->addr,
+ sizeof(binat.src.addr));
+ free($8);
+ }
+ if ($9 != NULL) {
+ if ($9->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if ($9->af != binat.af && $9->af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask($9, binat.af))
+ YYERROR;
+ memcpy(&binat.dst.addr, &$9->addr,
+ sizeof(binat.dst.addr));
+ binat.dst.neg = $9->not;
+ free($9);
+ }
+
+ if (binat.action == PF_NOBINAT) {
+ if ($13 != NULL) {
+ yyerror("'no binat' rule does not need"
+ " '->'");
+ YYERROR;
+ }
+ } else {
+ if ($13 == NULL || $13->host == NULL) {
+ yyerror("'binat' rule requires"
+ " '-> address'");
+ YYERROR;
+ }
+
+ remove_invalid_hosts(&$13->host, &binat.af);
+ if (invalid_redirect($13->host, binat.af))
+ YYERROR;
+ if ($13->host->next != NULL) {
+ yyerror("binat rule must redirect to "
+ "a single address");
+ YYERROR;
+ }
+ if (check_netmask($13->host, binat.af))
+ YYERROR;
+
+ if (!PF_AZERO(&binat.src.addr.v.a.mask,
+ binat.af) &&
+ !PF_AEQ(&binat.src.addr.v.a.mask,
+ &$13->host->addr.v.a.mask, binat.af)) {
+ yyerror("'binat' source mask and "
+ "redirect mask must be the same");
+ YYERROR;
+ }
+
+ TAILQ_INIT(&binat.rpool.list);
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "binat: calloc");
+ pa->addr = $13->host->addr;
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&binat.rpool.list,
+ pa, entries);
+
+ free($13);
+ }
+
+ pfctl_add_rule(pf, &binat, "");
+ }
+ ;
+
+tag : /* empty */ { $$ = NULL; }
+ | TAG STRING { $$ = $2; }
+ ;
+
+tagged : /* empty */ { $$.neg = 0; $$.name = NULL; }
+ | not TAGGED string { $$.neg = $1; $$.name = $3; }
+ ;
+
+rtable : /* empty */ { $$ = -1; }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ ;
+
+route_host : STRING {
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "route_host: calloc");
+ $$->ifname = $1;
+ set_ipmask($$, 128);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | '(' STRING host ')' {
+ $$ = $3;
+ $$->ifname = $2;
+ }
+ ;
+
+route_host_list : route_host optnl { $$ = $1; }
+ | route_host_list comma route_host optnl {
+ if ($1->af == 0)
+ $1->af = $3->af;
+ if ($1->af != $3->af) {
+ yyerror("all pool addresses must be in the "
+ "same address family");
+ YYERROR;
+ }
+ $1->tail->next = $3;
+ $1->tail = $3->tail;
+ $$ = $1;
+ }
+ ;
+
+routespec : route_host { $$ = $1; }
+ | '{' optnl route_host_list '}' { $$ = $3; }
+ ;
+
+route : /* empty */ {
+ $$.host = NULL;
+ $$.rt = 0;
+ $$.pool_opts = 0;
+ }
+ | FASTROUTE {
+ $$.host = NULL;
+ $$.rt = PF_FASTROUTE;
+ $$.pool_opts = 0;
+ }
+ | ROUTETO routespec pool_opts {
+ $$.host = $2;
+ $$.rt = PF_ROUTETO;
+ $$.pool_opts = $3.type | $3.opts;
+ if ($3.key != NULL)
+ $$.key = $3.key;
+ }
+ | REPLYTO routespec pool_opts {
+ $$.host = $2;
+ $$.rt = PF_REPLYTO;
+ $$.pool_opts = $3.type | $3.opts;
+ if ($3.key != NULL)
+ $$.key = $3.key;
+ }
+ | DUPTO routespec pool_opts {
+ $$.host = $2;
+ $$.rt = PF_DUPTO;
+ $$.pool_opts = $3.type | $3.opts;
+ if ($3.key != NULL)
+ $$.key = $3.key;
+ }
+ ;
+
+timeout_spec : STRING NUMBER
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($1);
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
+ yyerror("unknown timeout %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | INTERVAL NUMBER {
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, "interval", $2, 0) != 0)
+ YYERROR;
+ }
+ ;
+
+timeout_list : timeout_list comma timeout_spec optnl
+ | timeout_spec optnl
+ ;
+
+limit_spec : STRING NUMBER
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($1);
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_limit(pf, $1, $2) != 0) {
+ yyerror("unable to set limit %s %u", $1, $2);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+limit_list : limit_list comma limit_spec optnl
+ | limit_spec optnl
+ ;
+
+comma : ','
+ | /* empty */
+ ;
+
+yesno : NO { $$ = 0; }
+ | STRING {
+ if (!strcmp($1, "yes"))
+ $$ = 1;
+ else {
+ yyerror("invalid value '%s', expected 'yes' "
+ "or 'no'", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+unaryop : '=' { $$ = PF_OP_EQ; }
+ | '!' '=' { $$ = PF_OP_NE; }
+ | '<' '=' { $$ = PF_OP_LE; }
+ | '<' { $$ = PF_OP_LT; }
+ | '>' '=' { $$ = PF_OP_GE; }
+ | '>' { $$ = PF_OP_GT; }
+ ;
+
+%%
+#ifdef __rtems__
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack);
+#endif /* __rtems__ */
+
+int
+yyerror(const char *fmt, ...)
+{
+ va_list ap;
+
+ file->errors++;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ return (0);
+}
+
+int
+disallow_table(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_TABLE) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_urpf_failed(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_URPFFAILED) {
+ yyerror(fmt);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_alias(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (DYNIF_MULTIADDR(h->addr)) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+rule_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ switch (r->action) {
+ case PF_PASS:
+ case PF_DROP:
+ case PF_SCRUB:
+ case PF_NOSCRUB:
+ problems = filter_consistent(r, anchor_call);
+ break;
+ case PF_NAT:
+ case PF_NONAT:
+ problems = nat_consistent(r);
+ break;
+ case PF_RDR:
+ case PF_NORDR:
+ problems = rdr_consistent(r);
+ break;
+ case PF_BINAT:
+ case PF_NOBINAT:
+ default:
+ break;
+ }
+ return (problems);
+}
+
+int
+filter_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
+ (r->src.port_op || r->dst.port_op)) {
+ yyerror("port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
+ (r->type || r->code)) {
+ yyerror("icmp-type/code only applies to icmp");
+ problems++;
+ }
+ if (!r->af && (r->type || r->code)) {
+ yyerror("must indicate address family with icmp-type/code");
+ problems++;
+ }
+ if (r->overload_tblname[0] &&
+ r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
+ yyerror("'overload' requires 'max-src-conn' "
+ "or 'max-src-conn-rate'");
+ problems++;
+ }
+ if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
+ (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
+ yyerror("proto %s doesn't match address family %s",
+ r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
+ r->af == AF_INET ? "inet" : "inet6");
+ problems++;
+ }
+ if (r->allow_opts && r->action != PF_PASS) {
+ yyerror("allow-opts can only be specified for pass rules");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
+ r->dst.port_op || r->flagset || r->type || r->code)) {
+ yyerror("fragments can be filtered only on IP header fields");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
+ yyerror("return-rst can only be applied to TCP rules");
+ problems++;
+ }
+ if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
+ yyerror("max-src-nodes requires 'source-track rule'");
+ problems++;
+ }
+ if (r->action == PF_DROP && r->keep_state) {
+ yyerror("keep state on block rules doesn't make sense");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_STATESLOPPY &&
+ (r->keep_state == PF_STATE_MODULATE ||
+ r->keep_state == PF_STATE_SYNPROXY)) {
+ yyerror("sloppy state matching cannot be used with "
+ "synproxy state or modulate state");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+nat_consistent(struct pf_rule *r)
+{
+ return (0); /* yeah! */
+}
+
+int
+rdr_consistent(struct pf_rule *r)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
+ if (r->src.port_op) {
+ yyerror("src port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->dst.port_op) {
+ yyerror("dst port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->rpool.proxy_port[0]) {
+ yyerror("rpool port only applies to tcp/udp");
+ problems++;
+ }
+ }
+ if (r->dst.port_op &&
+ r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
+ yyerror("invalid port operator for rdr destination port");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+process_tabledef(char *name, struct table_opts *opts)
+{
+ struct pfr_buffer ab;
+ struct node_tinit *ti;
+
+ bzero(&ab, sizeof(ab));
+ ab.pfrb_type = PFRB_ADDRS;
+ SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
+ if (ti->file)
+ if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
+ if (errno)
+ yyerror("cannot load \"%s\": %s",
+ ti->file, strerror(errno));
+ else
+ yyerror("file \"%s\" contains bad data",
+ ti->file);
+ goto _error;
+ }
+ if (ti->host)
+ if (append_addr_host(&ab, ti->host, 0, 0)) {
+ yyerror("cannot create address buffer: %s",
+ strerror(errno));
+ goto _error;
+ }
+ }
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(name, opts->flags, opts->init_addr,
+ &opts->init_nodes);
+ if (!(pf->opts & PF_OPT_NOACTION) &&
+ pfctl_define_table(name, opts->flags, opts->init_addr,
+ pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
+ yyerror("cannot define table %s: %s", name,
+ pfr_strerror(errno));
+ goto _error;
+ }
+ pf->tdirty = 1;
+ pfr_buf_clear(&ab);
+ return (0);
+_error:
+ pfr_buf_clear(&ab);
+ return (-1);
+}
+
+struct keywords {
+ const char *k_name;
+ int k_val;
+};
+
+/* macro gore, but you should've seen the prior indentation nightmare... */
+
+#define FREE_LIST(T,r) \
+ do { \
+ T *p, *node = r; \
+ while (node != NULL) { \
+ p = node; \
+ node = node->next; \
+ free(p); \
+ } \
+ } while (0)
+
+#define LOOP_THROUGH(T,n,r,C) \
+ do { \
+ T *n; \
+ if (r == NULL) { \
+ r = calloc(1, sizeof(T)); \
+ if (r == NULL) \
+ err(1, "LOOP: calloc"); \
+ r->next = NULL; \
+ } \
+ n = r; \
+ while (n != NULL) { \
+ do { \
+ C; \
+ } while (0); \
+ n = n->next; \
+ } \
+ } while (0)
+
+void
+expand_label_str(char *label, size_t len, const char *srch, const char *repl)
+{
+ char *tmp;
+ char *p, *q;
+
+ if ((tmp = calloc(1, len)) == NULL)
+ err(1, "expand_label_str: calloc");
+ p = q = label;
+ while ((q = strstr(p, srch)) != NULL) {
+ *q = '\0';
+ if ((strlcat(tmp, p, len) >= len) ||
+ (strlcat(tmp, repl, len) >= len))
+ errx(1, "expand_label: label too long");
+ q += strlen(srch);
+ p = q;
+ }
+ if (strlcat(tmp, p, len) >= len)
+ errx(1, "expand_label: label too long");
+ strlcpy(label, tmp, len); /* always fits */
+ free(tmp);
+}
+
+void
+expand_label_if(const char *name, char *label, size_t len, const char *ifname)
+{
+ if (strstr(label, name) != NULL) {
+ if (!*ifname)
+ expand_label_str(label, len, name, "any");
+ else
+ expand_label_str(label, len, name, ifname);
+ }
+}
+
+void
+expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
+ struct node_host *h)
+{
+ char tmp[64], tmp_not[66];
+
+ if (strstr(label, name) != NULL) {
+ switch (h->addr.type) {
+ case PF_ADDR_DYNIFTL:
+ snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
+ break;
+ case PF_ADDR_TABLE:
+ snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
+ break;
+ case PF_ADDR_NOROUTE:
+ snprintf(tmp, sizeof(tmp), "no-route");
+ break;
+ case PF_ADDR_URPFFAILED:
+ snprintf(tmp, sizeof(tmp), "urpf-failed");
+ break;
+ case PF_ADDR_ADDRMASK:
+ if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
+ PF_AZERO(&h->addr.v.a.mask, af)))
+ snprintf(tmp, sizeof(tmp), "any");
+ else {
+ char a[48];
+ int bits;
+
+ if (inet_ntop(af, &h->addr.v.a.addr, a,
+ sizeof(a)) == NULL)
+ snprintf(tmp, sizeof(tmp), "?");
+ else {
+ bits = unmask(&h->addr.v.a.mask, af);
+ if ((af == AF_INET && bits < 32) ||
+ (af == AF_INET6 && bits < 128))
+ snprintf(tmp, sizeof(tmp),
+ "%s/%d", a, bits);
+ else
+ snprintf(tmp, sizeof(tmp),
+ "%s", a);
+ }
+ }
+ break;
+ default:
+ snprintf(tmp, sizeof(tmp), "?");
+ break;
+ }
+
+ if (h->not) {
+ snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
+ expand_label_str(label, len, name, tmp_not);
+ } else
+ expand_label_str(label, len, name, tmp);
+ }
+}
+
+void
+expand_label_port(const char *name, char *label, size_t len,
+ struct node_port *port)
+{
+ char a1[6], a2[6], op[13] = "";
+
+ if (strstr(label, name) != NULL) {
+ snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
+ snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
+ if (!port->op)
+ ;
+ else if (port->op == PF_OP_IRG)
+ snprintf(op, sizeof(op), "%s><%s", a1, a2);
+ else if (port->op == PF_OP_XRG)
+ snprintf(op, sizeof(op), "%s<>%s", a1, a2);
+ else if (port->op == PF_OP_EQ)
+ snprintf(op, sizeof(op), "%s", a1);
+ else if (port->op == PF_OP_NE)
+ snprintf(op, sizeof(op), "!=%s", a1);
+ else if (port->op == PF_OP_LT)
+ snprintf(op, sizeof(op), "<%s", a1);
+ else if (port->op == PF_OP_LE)
+ snprintf(op, sizeof(op), "<=%s", a1);
+ else if (port->op == PF_OP_GT)
+ snprintf(op, sizeof(op), ">%s", a1);
+ else if (port->op == PF_OP_GE)
+ snprintf(op, sizeof(op), ">=%s", a1);
+ expand_label_str(label, len, name, op);
+ }
+}
+
+void
+expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
+{
+ struct protoent *pe;
+ char n[4];
+
+ if (strstr(label, name) != NULL) {
+ pe = getprotobynumber(proto);
+ if (pe != NULL)
+ expand_label_str(label, len, name, pe->p_name);
+ else {
+ snprintf(n, sizeof(n), "%u", proto);
+ expand_label_str(label, len, name, n);
+ }
+ }
+}
+
+void
+expand_label_nr(const char *name, char *label, size_t len)
+{
+ char n[11];
+
+ if (strstr(label, name) != NULL) {
+ snprintf(n, sizeof(n), "%u", pf->anchor->match);
+ expand_label_str(label, len, name, n);
+ }
+}
+
+void
+expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
+ struct node_host *src_host, struct node_port *src_port,
+ struct node_host *dst_host, struct node_port *dst_port,
+ u_int8_t proto)
+{
+ expand_label_if("$if", label, len, ifname);
+ expand_label_addr("$srcaddr", label, len, af, src_host);
+ expand_label_addr("$dstaddr", label, len, af, dst_host);
+ expand_label_port("$srcport", label, len, src_port);
+ expand_label_port("$dstport", label, len, dst_port);
+ expand_label_proto("$proto", label, len, proto);
+ expand_label_nr("$nr", label, len);
+}
+
+int
+expand_altq(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct pf_altq pa, pb;
+ char qname[PF_QNAME_SIZE];
+ struct node_queue *n;
+ struct node_queue_bw bw;
+ int errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ memcpy(&pa, a, sizeof(struct pf_altq));
+ if (strlcpy(pa.ifname, interface->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_altq: strlcpy");
+
+ if (interface->not) {
+ yyerror("altq on ! <interface> is not supported");
+ errs++;
+ } else {
+ if (eval_pfaltq(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ if (pf->opts & PF_OPT_VERBOSE) {
+ print_altq(&pf->paltq->altq, 0,
+ &bwspec, opts);
+ if (nqueues && nqueues->tail) {
+ printf("queue { ");
+ LOOP_THROUGH(struct node_queue, queue,
+ nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC) {
+ /* now create a root queue */
+ memset(&pb, 0, sizeof(struct pf_altq));
+ if (strlcpy(qname, "root_", sizeof(qname)) >=
+ sizeof(qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcat(qname, interface->ifname,
+ sizeof(qname)) >= sizeof(qname))
+ errx(1, "expand_altq: strlcat");
+ if (strlcpy(pb.qname, qname,
+ sizeof(pb.qname)) >= sizeof(pb.qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(pb.ifname, interface->ifname,
+ sizeof(pb.ifname)) >= sizeof(pb.ifname))
+ errx(1, "expand_altq: strlcpy");
+ pb.qlimit = pa.qlimit;
+ pb.scheduler = pa.scheduler;
+ bw.bw_absolute = pa.ifbandwidth;
+ bw.bw_percent = 0;
+ if (eval_pfqueue(pf, &pb, &bw, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pb))
+ errs++;
+ }
+
+ LOOP_THROUGH(struct node_queue, queue, nqueues,
+ n = calloc(1, sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_altq: calloc");
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC)
+ if (strlcpy(n->parent, qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->queue, queue->queue,
+ sizeof(n->queue)) >= sizeof(n->queue))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->ifname, interface->ifname,
+ sizeof(n->ifname)) >= sizeof(n->ifname))
+ errx(1, "expand_altq: strlcpy");
+ n->scheduler = pa.scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ );
+ }
+ );
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+
+ return (errs);
+}
+
+int
+expand_queue(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct node_queue *n, *nq;
+ struct pf_altq pa;
+ u_int8_t found = 0;
+ u_int8_t errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ if (queues == NULL) {
+ yyerror("queue %s has no parent", a->qname);
+ FREE_LIST(struct node_queue, nqueues);
+ return (1);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_queue, tqueue, queues,
+ if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
+ (interface->ifname[0] == 0 ||
+ (!interface->not && !strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)) ||
+ (interface->not && strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)))) {
+ /* found ourself in queues */
+ found++;
+
+ memcpy(&pa, a, sizeof(struct pf_altq));
+
+ if (pa.scheduler != ALTQT_NONE &&
+ pa.scheduler != tqueue->scheduler) {
+ yyerror("exactly one scheduler type "
+ "per interface allowed");
+ return (1);
+ }
+ pa.scheduler = tqueue->scheduler;
+
+ /* scheduler dependent error checking */
+ switch (pa.scheduler) {
+ case ALTQT_PRIQ:
+ if (nqueues != NULL) {
+ yyerror("priq queues cannot "
+ "have child queues");
+ return (1);
+ }
+ if (bwspec.bw_absolute > 0 ||
+ bwspec.bw_percent < 100) {
+ yyerror("priq doesn't take "
+ "bandwidth");
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (strlcpy(pa.ifname, tqueue->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_queue: strlcpy");
+ if (strlcpy(pa.parent, tqueue->parent,
+ sizeof(pa.parent)) >= sizeof(pa.parent))
+ errx(1, "expand_queue: strlcpy");
+
+ if (eval_pfqueue(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ for (nq = nqueues; nq != NULL; nq = nq->next) {
+ if (!strcmp(a->qname, nq->queue)) {
+ yyerror("queue cannot have "
+ "itself as child");
+ errs++;
+ continue;
+ }
+ n = calloc(1,
+ sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_queue: calloc");
+ if (strlcpy(n->parent, a->qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->queue, nq->queue,
+ sizeof(n->queue)) >=
+ sizeof(n->queue))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->ifname, tqueue->ifname,
+ sizeof(n->ifname)) >=
+ sizeof(n->ifname))
+ errx(1, "expand_queue strlcpy");
+ n->scheduler = tqueue->scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ }
+ if ((pf->opts & PF_OPT_VERBOSE) && (
+ (found == 1 && interface->ifname[0] == 0) ||
+ (found > 0 && interface->ifname[0] != 0))) {
+ print_queue(&pf->paltq->altq, 0,
+ &bwspec, interface->ifname[0] != 0,
+ opts);
+ if (nqueues && nqueues->tail) {
+ printf("{ ");
+ LOOP_THROUGH(struct node_queue,
+ queue, nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+ }
+ );
+ );
+
+ FREE_LIST(struct node_queue, nqueues);
+ FREE_LIST(struct node_if, interfaces);
+
+ if (!found) {
+ yyerror("queue %s has no parent", a->qname);
+ errs++;
+ }
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+void
+expand_rule(struct pf_rule *r,
+ struct node_if *interfaces, struct node_host *rpool_hosts,
+ struct node_proto *protos, struct node_os *src_oses,
+ struct node_host *src_hosts, struct node_port *src_ports,
+ struct node_host *dst_hosts, struct node_port *dst_ports,
+ struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
+ const char *anchor_call)
+{
+ sa_family_t af = r->af;
+ int added = 0, error = 0;
+ char ifname[IF_NAMESIZE];
+ char label[PF_RULE_LABEL_SIZE];
+ char tagname[PF_TAG_NAME_SIZE];
+ char match_tagname[PF_TAG_NAME_SIZE];
+ struct pf_pooladdr *pa;
+ struct node_host *h;
+ u_int8_t flags, flagset, keep_state;
+
+ if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
+ sizeof(match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ flags = r->flags;
+ flagset = r->flagset;
+ keep_state = r->keep_state;
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_proto, proto, protos,
+ LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
+ LOOP_THROUGH(struct node_host, src_host, src_hosts,
+ LOOP_THROUGH(struct node_port, src_port, src_ports,
+ LOOP_THROUGH(struct node_os, src_os, src_oses,
+ LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
+ LOOP_THROUGH(struct node_port, dst_port, dst_ports,
+ LOOP_THROUGH(struct node_uid, uid, uids,
+ LOOP_THROUGH(struct node_gid, gid, gids,
+
+ r->af = af;
+ /* for link-local IPv6 address, interface must match up */
+ if ((r->af && src_host->af && r->af != src_host->af) ||
+ (r->af && dst_host->af && r->af != dst_host->af) ||
+ (src_host->af && dst_host->af &&
+ src_host->af != dst_host->af) ||
+ (src_host->ifindex && dst_host->ifindex &&
+ src_host->ifindex != dst_host->ifindex) ||
+ (src_host->ifindex && *interface->ifname &&
+ src_host->ifindex != if_nametoindex(interface->ifname)) ||
+ (dst_host->ifindex && *interface->ifname &&
+ dst_host->ifindex != if_nametoindex(interface->ifname)))
+ continue;
+ if (!r->af && src_host->af)
+ r->af = src_host->af;
+ else if (!r->af && dst_host->af)
+ r->af = dst_host->af;
+
+ if (*interface->ifname)
+ strlcpy(r->ifname, interface->ifname,
+ sizeof(r->ifname));
+ else if (if_indextoname(src_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else if (if_indextoname(dst_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else
+ memset(r->ifname, '\0', sizeof(r->ifname));
+
+ if (strlcpy(r->label, label, sizeof(r->label)) >=
+ sizeof(r->label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
+ sizeof(r->tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->match_tagname, match_tagname,
+ sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
+ r->af, src_host, src_port, dst_host, dst_port,
+ proto->proto);
+
+ error += check_netmask(src_host, r->af);
+ error += check_netmask(dst_host, r->af);
+
+ r->ifnot = interface->not;
+ r->proto = proto->proto;
+ r->src.addr = src_host->addr;
+ r->src.neg = src_host->not;
+ r->src.port[0] = src_port->port[0];
+ r->src.port[1] = src_port->port[1];
+ r->src.port_op = src_port->op;
+ r->dst.addr = dst_host->addr;
+ r->dst.neg = dst_host->not;
+ r->dst.port[0] = dst_port->port[0];
+ r->dst.port[1] = dst_port->port[1];
+ r->dst.port_op = dst_port->op;
+ r->uid.op = uid->op;
+ r->uid.uid[0] = uid->uid[0];
+ r->uid.uid[1] = uid->uid[1];
+ r->gid.op = gid->op;
+ r->gid.gid[0] = gid->gid[0];
+ r->gid.gid[1] = gid->gid[1];
+ r->type = icmp_type->type;
+ r->code = icmp_type->code;
+
+ if ((keep_state == PF_STATE_MODULATE ||
+ keep_state == PF_STATE_SYNPROXY) &&
+ r->proto && r->proto != IPPROTO_TCP)
+ r->keep_state = PF_STATE_NORMAL;
+ else
+ r->keep_state = keep_state;
+
+ if (r->proto && r->proto != IPPROTO_TCP) {
+ r->flags = 0;
+ r->flagset = 0;
+ } else {
+ r->flags = flags;
+ r->flagset = flagset;
+ }
+ if (icmp_type->proto && r->proto != icmp_type->proto) {
+ yyerror("icmp-type mismatch");
+ error++;
+ }
+
+ if (src_os && src_os->os) {
+ r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
+ if ((pf->opts & PF_OPT_VERBOSE2) &&
+ r->os_fingerprint == PF_OSFP_NOMATCH)
+ fprintf(stderr,
+ "warning: unknown '%s' OS fingerprint\n",
+ src_os->os);
+ } else {
+ r->os_fingerprint = PF_OSFP_ANY;
+ }
+
+ TAILQ_INIT(&r->rpool.list);
+ for (h = rpool_hosts; h != NULL; h = h->next) {
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "expand_rule: calloc");
+ pa->addr = h->addr;
+ if (h->ifname != NULL) {
+ if (strlcpy(pa->ifname, h->ifname,
+ sizeof(pa->ifname)) >=
+ sizeof(pa->ifname))
+ errx(1, "expand_rule: strlcpy");
+ } else
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
+ }
+
+ if (rule_consistent(r, anchor_call[0]) < 0 || error)
+ yyerror("skipping rule due to errors");
+ else {
+ r->nr = pf->astack[pf->asd]->match++;
+ pfctl_add_rule(pf, r, anchor_call);
+ added++;
+ }
+
+ ))))))))));
+
+ FREE_LIST(struct node_if, interfaces);
+ FREE_LIST(struct node_proto, protos);
+ FREE_LIST(struct node_host, src_hosts);
+ FREE_LIST(struct node_port, src_ports);
+ FREE_LIST(struct node_os, src_oses);
+ FREE_LIST(struct node_host, dst_hosts);
+ FREE_LIST(struct node_port, dst_ports);
+ FREE_LIST(struct node_uid, uids);
+ FREE_LIST(struct node_gid, gids);
+ FREE_LIST(struct node_icmp, icmp_types);
+ FREE_LIST(struct node_host, rpool_hosts);
+
+ if (!added)
+ yyerror("rule expands to no valid combination");
+}
+
+int
+expand_skip_interface(struct node_if *interfaces)
+{
+ int errs = 0;
+
+ if (!interfaces || (!interfaces->next && !interfaces->not &&
+ !strcmp(interfaces->ifname, "none"))) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on none\n");
+ errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
+ return (errs);
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on {");
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" %s", interface->ifname);
+ if (interface->not) {
+ yyerror("skip on ! <interface> is not supported");
+ errs++;
+ } else
+ errs += pfctl_set_interface_flags(pf,
+ interface->ifname, PFI_IFLAG_SKIP, 1);
+ );
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" }\n");
+
+ FREE_LIST(struct node_if, interfaces);
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+#undef FREE_LIST
+#undef LOOP_THROUGH
+
+int
+check_rulestate(int desired_state)
+{
+ if (require_order && (rulestate > desired_state)) {
+ yyerror("Rules must be in order: options, normalization, "
+ "queueing, translation, filtering");
+ return (1);
+ }
+ rulestate = desired_state;
+ return (0);
+}
+
+int
+kw_cmp(const void *k, const void *e)
+{
+ return (strcmp(k, ((const struct keywords *)e)->k_name));
+}
+
+int
+lookup(char *s)
+{
+ /* this has to be sorted always */
+ static const struct keywords keywords[] = {
+ { "all", ALL},
+ { "allow-opts", ALLOWOPTS},
+ { "altq", ALTQ},
+ { "anchor", ANCHOR},
+ { "antispoof", ANTISPOOF},
+ { "any", ANY},
+ { "bandwidth", BANDWIDTH},
+ { "binat", BINAT},
+ { "binat-anchor", BINATANCHOR},
+ { "bitmask", BITMASK},
+ { "block", BLOCK},
+ { "block-policy", BLOCKPOLICY},
+ { "buckets", BUCKETS},
+ { "cbq", CBQ},
+ { "code", CODE},
+ { "codelq", CODEL},
+ { "crop", FRAGCROP},
+ { "debug", DEBUG},
+ { "divert-reply", DIVERTREPLY},
+ { "divert-to", DIVERTTO},
+ { "drop", DROP},
+ { "drop-ovl", FRAGDROP},
+ { "dup-to", DUPTO},
+ { "fairq", FAIRQ},
+ { "fastroute", FASTROUTE},
+ { "file", FILENAME},
+ { "fingerprints", FINGERPRINTS},
+ { "flags", FLAGS},
+ { "floating", FLOATING},
+ { "flush", FLUSH},
+ { "for", FOR},
+ { "fragment", FRAGMENT},
+ { "from", FROM},
+ { "global", GLOBAL},
+ { "group", GROUP},
+ { "hfsc", HFSC},
+ { "hogs", HOGS},
+ { "hostid", HOSTID},
+ { "icmp-type", ICMPTYPE},
+ { "icmp6-type", ICMP6TYPE},
+ { "if-bound", IFBOUND},
+ { "in", IN},
+ { "include", INCLUDE},
+ { "inet", INET},
+ { "inet6", INET6},
+ { "interval", INTERVAL},
+ { "keep", KEEP},
+ { "label", LABEL},
+ { "limit", LIMIT},
+ { "linkshare", LINKSHARE},
+ { "load", LOAD},
+ { "log", LOG},
+ { "loginterface", LOGINTERFACE},
+ { "max", MAXIMUM},
+ { "max-mss", MAXMSS},
+ { "max-src-conn", MAXSRCCONN},
+ { "max-src-conn-rate", MAXSRCCONNRATE},
+ { "max-src-nodes", MAXSRCNODES},
+ { "max-src-states", MAXSRCSTATES},
+ { "min-ttl", MINTTL},
+ { "modulate", MODULATE},
+ { "nat", NAT},
+ { "nat-anchor", NATANCHOR},
+ { "no", NO},
+ { "no-df", NODF},
+ { "no-route", NOROUTE},
+ { "no-sync", NOSYNC},
+ { "on", ON},
+ { "optimization", OPTIMIZATION},
+ { "os", OS},
+ { "out", OUT},
+ { "overload", OVERLOAD},
+ { "pass", PASS},
+ { "port", PORT},
+ { "prio", PRIO},
+ { "priority", PRIORITY},
+ { "priq", PRIQ},
+ { "probability", PROBABILITY},
+ { "proto", PROTO},
+ { "qlimit", QLIMIT},
+ { "queue", QUEUE},
+ { "quick", QUICK},
+ { "random", RANDOM},
+ { "random-id", RANDOMID},
+ { "rdr", RDR},
+ { "rdr-anchor", RDRANCHOR},
+ { "realtime", REALTIME},
+ { "reassemble", REASSEMBLE},
+ { "reply-to", REPLYTO},
+ { "require-order", REQUIREORDER},
+ { "return", RETURN},
+ { "return-icmp", RETURNICMP},
+ { "return-icmp6", RETURNICMP6},
+ { "return-rst", RETURNRST},
+ { "round-robin", ROUNDROBIN},
+ { "route", ROUTE},
+ { "route-to", ROUTETO},
+ { "rtable", RTABLE},
+ { "rule", RULE},
+ { "ruleset-optimization", RULESET_OPTIMIZATION},
+ { "scrub", SCRUB},
+ { "set", SET},
+ { "set-tos", SETTOS},
+ { "skip", SKIP},
+ { "sloppy", SLOPPY},
+ { "source-hash", SOURCEHASH},
+ { "source-track", SOURCETRACK},
+ { "state", STATE},
+ { "state-defaults", STATEDEFAULTS},
+ { "state-policy", STATEPOLICY},
+ { "static-port", STATICPORT},
+ { "sticky-address", STICKYADDRESS},
+ { "synproxy", SYNPROXY},
+ { "table", TABLE},
+ { "tag", TAG},
+ { "tagged", TAGGED},
+ { "target", TARGET},
+ { "tbrsize", TBRSIZE},
+ { "timeout", TIMEOUT},
+ { "to", TO},
+ { "tos", TOS},
+ { "ttl", TTL},
+ { "upperlimit", UPPERLIMIT},
+ { "urpf-failed", URPFFAILED},
+ { "user", USER},
+ };
+ const struct keywords *p;
+
+ p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
+ sizeof(keywords[0]), kw_cmp);
+
+ if (p) {
+ if (debug > 1)
+ fprintf(stderr, "%s: %d\n", s, p->k_val);
+ return (p->k_val);
+ } else {
+ if (debug > 1)
+ fprintf(stderr, "string: %s\n", s);
+ return (STRING);
+ }
+}
+
+#define MAXPUSHBACK 128
+
+static char *parsebuf;
+static int parseindex;
+static char pushback_buffer[MAXPUSHBACK];
+static int pushback_index = 0;
+
+int
+lgetc(int quotec)
+{
+ int c, next;
+
+ if (parsebuf) {
+ /* Read character from the parsebuffer instead of input. */
+ if (parseindex >= 0) {
+ c = parsebuf[parseindex++];
+ if (c != '\0')
+ return (c);
+ parsebuf = NULL;
+ } else
+ parseindex++;
+ }
+
+ if (pushback_index)
+ return (pushback_buffer[--pushback_index]);
+
+ if (quotec) {
+ if ((c = getc(file->stream)) == EOF) {
+ yyerror("reached end of file while parsing quoted string");
+ if (popfile() == EOF)
+ return (EOF);
+ return (quotec);
+ }
+ return (c);
+ }
+
+ while ((c = getc(file->stream)) == '\\') {
+ next = getc(file->stream);
+ if (next != '\n') {
+ c = next;
+ break;
+ }
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+
+ while (c == EOF) {
+ if (popfile() == EOF)
+ return (EOF);
+ c = getc(file->stream);
+ }
+ return (c);
+}
+
+int
+lungetc(int c)
+{
+ if (c == EOF)
+ return (EOF);
+ if (parsebuf) {
+ parseindex--;
+ if (parseindex >= 0)
+ return (c);
+ }
+ if (pushback_index < MAXPUSHBACK-1)
+ return (pushback_buffer[pushback_index++] = c);
+ else
+ return (EOF);
+}
+
+int
+findeol(void)
+{
+ int c;
+
+ parsebuf = NULL;
+
+ /* skip to either EOF or the first real EOL */
+ while (1) {
+ if (pushback_index)
+ c = pushback_buffer[--pushback_index];
+ else
+ c = lgetc(0);
+ if (c == '\n') {
+ file->lineno++;
+ break;
+ }
+ if (c == EOF)
+ break;
+ }
+ return (ERROR);
+}
+
+int
+yylex(void)
+{
+ char buf[8096];
+ char *p, *val;
+ int quotec, next, c;
+ int token;
+
+top:
+ p = buf;
+ while ((c = lgetc(0)) == ' ' || c == '\t')
+ ; /* nothing */
+
+ yylval.lineno = file->lineno;
+ if (c == '#')
+ while ((c = lgetc(0)) != '\n' && c != EOF)
+ ; /* nothing */
+ if (c == '$' && parsebuf == NULL) {
+ while (1) {
+ if ((c = lgetc(0)) == EOF)
+ return (0);
+
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ if (isalnum(c) || c == '_') {
+ *p++ = (char)c;
+ continue;
+ }
+ *p = '\0';
+ lungetc(c);
+ break;
+ }
+ val = symget(buf);
+ if (val == NULL) {
+ yyerror("macro '%s' not defined", buf);
+ return (findeol());
+ }
+ parsebuf = val;
+ parseindex = 0;
+ goto top;
+ }
+
+ switch (c) {
+ case '\'':
+ case '"':
+ quotec = c;
+ while (1) {
+ if ((c = lgetc(quotec)) == EOF)
+ return (0);
+ if (c == '\n') {
+ file->lineno++;
+ continue;
+ } else if (c == '\\') {
+ if ((next = lgetc(quotec)) == EOF)
+ return (0);
+ if (next == quotec || c == ' ' || c == '\t')
+ c = next;
+ else if (next == '\n')
+ continue;
+ else
+ lungetc(next);
+ } else if (c == quotec) {
+ *p = '\0';
+ break;
+ }
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ *p++ = (char)c;
+ }
+ yylval.v.string = strdup(buf);
+ if (yylval.v.string == NULL)
+ err(1, "yylex: strdup");
+ return (STRING);
+ case '<':
+ next = lgetc(0);
+ if (next == '>') {
+ yylval.v.i = PF_OP_XRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '>':
+ next = lgetc(0);
+ if (next == '<') {
+ yylval.v.i = PF_OP_IRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '-':
+ next = lgetc(0);
+ if (next == '>')
+ return (ARROW);
+ lungetc(next);
+ break;
+ }
+
+#define allowed_to_end_number(x) \
+ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
+
+ if (c == '-' || isdigit(c)) {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && isdigit(c));
+ lungetc(c);
+ if (p == buf + 1 && buf[0] == '-')
+ goto nodigits;
+ if (c == EOF || allowed_to_end_number(c)) {
+ const char *errstr = NULL;
+
+ *p = '\0';
+ yylval.v.number = strtonum(buf, LLONG_MIN,
+ LLONG_MAX, &errstr);
+ if (errstr) {
+ yyerror("\"%s\" invalid number: %s",
+ buf, errstr);
+ return (findeol());
+ }
+ return (NUMBER);
+ } else {
+nodigits:
+ while (p > buf + 1)
+ lungetc(*--p);
+ c = *--p;
+ if (c == '-')
+ return (c);
+ }
+ }
+
+#define allowed_in_string(x) \
+ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
+ x != '{' && x != '}' && x != '<' && x != '>' && \
+ x != '!' && x != '=' && x != '/' && x != '#' && \
+ x != ','))
+
+ if (isalnum(c) || c == ':' || c == '_') {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
+ lungetc(c);
+ *p = '\0';
+ if ((token = lookup(buf)) == STRING)
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "yylex: strdup");
+ return (token);
+ }
+ if (c == '\n') {
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+ if (c == EOF)
+ return (0);
+ return (c);
+}
+
+int
+check_file_secrecy(int fd, const char *fname)
+{
+ struct stat st;
+
+ if (fstat(fd, &st)) {
+ warn("cannot stat %s", fname);
+ return (-1);
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ warnx("%s: owner not root or current user", fname);
+ return (-1);
+ }
+ if (st.st_mode & (S_IRWXG | S_IRWXO)) {
+ warnx("%s: group/world readable/writeable", fname);
+ return (-1);
+ }
+ return (0);
+}
+
+struct file *
+pushfile(const char *name, int secret)
+{
+ struct file *nfile;
+
+ if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
+ (nfile->name = strdup(name)) == NULL) {
+ warn("malloc");
+ return (NULL);
+ }
+ if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
+ nfile->stream = stdin;
+ free(nfile->name);
+ if ((nfile->name = strdup("stdin")) == NULL) {
+ warn("strdup");
+ free(nfile);
+ return (NULL);
+ }
+ } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
+ warn("%s", nfile->name);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ } else if (secret &&
+ check_file_secrecy(fileno(nfile->stream), nfile->name)) {
+ fclose(nfile->stream);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ }
+ nfile->lineno = 1;
+ TAILQ_INSERT_TAIL(&files, nfile, entry);
+ return (nfile);
+}
+
+int
+popfile(void)
+{
+ struct file *prev;
+
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
+ prev->errors += file->errors;
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file);
+ file = prev;
+ return (0);
+ }
+ return (EOF);
+}
+
+int
+parse_config(char *filename, struct pfctl *xpf)
+{
+ int errors = 0;
+ struct sym *sym;
+
+ pf = xpf;
+ errors = 0;
+ rulestate = PFCTL_STATE_NONE;
+ returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+ returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+ blockpolicy = PFRULE_DROP;
+ require_order = 1;
+
+ if ((file = pushfile(filename, 0)) == NULL) {
+ warn("cannot open the main config file!");
+ return (-1);
+ }
+
+ yyparse();
+ errors = file->errors;
+ popfile();
+
+ /* Free macros and check which have not been used. */
+ while ((sym = TAILQ_FIRST(&symhead))) {
+ if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
+ fprintf(stderr, "warning: macro '%s' not "
+ "used\n", sym->nam);
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+
+ return (errors ? -1 : 0);
+}
+
+int
+symset(const char *nam, const char *val, int persist)
+{
+ struct sym *sym;
+
+ for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
+ sym = TAILQ_NEXT(sym, entry))
+ ; /* nothing */
+
+ if (sym != NULL) {
+ if (sym->persist == 1)
+ return (0);
+ else {
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+ }
+ if ((sym = calloc(1, sizeof(*sym))) == NULL)
+ return (-1);
+
+ sym->nam = strdup(nam);
+ if (sym->nam == NULL) {
+ free(sym);
+ return (-1);
+ }
+ sym->val = strdup(val);
+ if (sym->val == NULL) {
+ free(sym->nam);
+ free(sym);
+ return (-1);
+ }
+ sym->used = 0;
+ sym->persist = persist;
+ TAILQ_INSERT_TAIL(&symhead, sym, entry);
+ return (0);
+}
+
+int
+pfctl_cmdline_symset(char *s)
+{
+ char *sym, *val;
+ int ret;
+
+ if ((val = strrchr(s, '=')) == NULL)
+ return (-1);
+
+ if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
+ err(1, "pfctl_cmdline_symset: malloc");
+
+ strlcpy(sym, s, strlen(s) - strlen(val) + 1);
+
+ ret = symset(sym, val + 1, 1);
+ free(sym);
+
+ return (ret);
+}
+
+char *
+symget(const char *nam)
+{
+ struct sym *sym;
+
+ TAILQ_FOREACH(sym, &symhead, entry)
+ if (strcmp(nam, sym->nam) == 0) {
+ sym->used = 1;
+ return (sym->val);
+ }
+ return (NULL);
+}
+
+void
+mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
+{
+ int i;
+ struct pf_rule *r;
+
+ for (i = 0; i < PF_RULESET_MAX; ++i) {
+ while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
+ dst->anchor->match++;
+ }
+ src->anchor->match = 0;
+ while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
+ r, entries);
+ }
+ }
+}
+
+void
+decide_address_family(struct node_host *n, sa_family_t *af)
+{
+ if (*af != 0 || n == NULL)
+ return;
+ *af = n->af;
+ while ((n = n->next) != NULL) {
+ if (n->af != *af) {
+ *af = 0;
+ return;
+ }
+ }
+}
+
+void
+remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
+{
+ struct node_host *n = *nh, *prev = NULL;
+
+ while (n != NULL) {
+ if (*af && n->af && n->af != *af) {
+ /* unlink and free n */
+ struct node_host *next = n->next;
+
+ /* adjust tail pointer */
+ if (n == (*nh)->tail)
+ (*nh)->tail = prev;
+ /* adjust previous node's next pointer */
+ if (prev == NULL)
+ *nh = next;
+ else
+ prev->next = next;
+ /* free node */
+ if (n->ifname != NULL)
+ free(n->ifname);
+ free(n);
+ n = next;
+ } else {
+ if (n->af && !*af)
+ *af = n->af;
+ prev = n;
+ n = n->next;
+ }
+ }
+}
+
+int
+invalid_redirect(struct node_host *nh, sa_family_t af)
+{
+ if (!af) {
+ struct node_host *n;
+
+ /* tables and dyniftl are ok without an address family */
+ for (n = nh; n != NULL; n = n->next) {
+ if (n->addr.type != PF_ADDR_TABLE &&
+ n->addr.type != PF_ADDR_DYNIFTL) {
+ yyerror("address family not given and "
+ "translation address expands to multiple "
+ "address families");
+ return (1);
+ }
+ }
+ }
+ if (nh == NULL) {
+ yyerror("no translation address with matching address family "
+ "found.");
+ return (1);
+ }
+ return (0);
+}
+
+int
+atoul(char *s, u_long *ulvalp)
+{
+ u_long ulval;
+ char *ep;
+
+ errno = 0;
+ ulval = strtoul(s, &ep, 0);
+ if (s[0] == '\0' || *ep != '\0')
+ return (-1);
+ if (errno == ERANGE && ulval == ULONG_MAX)
+ return (-1);
+ *ulvalp = ulval;
+ return (0);
+}
+
+int
+getservice(char *n)
+{
+ struct servent *s;
+ u_long ulval;
+
+ if (atoul(n, &ulval) == 0) {
+ if (ulval > 65535) {
+ yyerror("illegal port value %lu", ulval);
+ return (-1);
+ }
+ return (htons(ulval));
+ } else {
+ s = getservbyname(n, "tcp");
+ if (s == NULL)
+ s = getservbyname(n, "udp");
+ if (s == NULL) {
+ yyerror("unknown port %s", n);
+ return (-1);
+ }
+ return (s->s_port);
+ }
+}
+
+int
+rule_label(struct pf_rule *r, char *s)
+{
+ if (s) {
+ if (strlcpy(r->label, s, sizeof(r->label)) >=
+ sizeof(r->label)) {
+ yyerror("rule label too long (max %d chars)",
+ sizeof(r->label)-1);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+u_int16_t
+parseicmpspec(char *w, sa_family_t af)
+{
+ const struct icmpcodeent *p;
+ u_long ulval;
+ u_int8_t icmptype;
+
+ if (af == AF_INET)
+ icmptype = returnicmpdefault >> 8;
+ else
+ icmptype = returnicmp6default >> 8;
+
+ if (atoul(w, &ulval) == -1) {
+ if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
+ yyerror("unknown icmp code %s", w);
+ return (0);
+ }
+ ulval = p->code;
+ }
+ if (ulval > 255) {
+ yyerror("invalid icmp code %lu", ulval);
+ return (0);
+ }
+ return (icmptype << 8 | ulval);
+}
+
+int
+parseport(char *port, struct range *r, int extensions)
+{
+ char *p = strchr(port, ':');
+
+ if (p == NULL) {
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ return (0);
+ }
+ if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
+ *p = 0;
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_IRG;
+ return (0);
+ }
+ if ((extensions & PPORT_RANGE)) {
+ *p++ = 0;
+ if ((r->a = getservice(port)) == -1 ||
+ (r->b = getservice(p)) == -1)
+ return (-1);
+ if (r->a == r->b) {
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ } else
+ r->t = PF_OP_RRG;
+ return (0);
+ }
+ return (-1);
+}
+
+int
+pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
+{
+ struct loadanchors *la;
+
+ TAILQ_FOREACH(la, &loadanchorshead, entries) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "\nLoading anchor %s from %s\n",
+ la->anchorname, la->filename);
+ if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
+ la->anchorname, trans) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+rt_tableid_max(void)
+{
+#ifdef __FreeBSD__
+ int fibs;
+ size_t l = sizeof(fibs);
+
+ if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
+ fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */
+ /*
+ * As the OpenBSD code only compares > and not >= we need to adjust
+ * here given we only accept values of 0..n and want to avoid #ifdefs
+ * in the grammar.
+ */
+ return (fibs - 1);
+#else
+ return (RT_TABLEID_MAX);
+#endif
+}
diff --git a/freebsd/sbin/pfctl/pf_print_state.c b/freebsd/sbin/pfctl/pf_print_state.c
new file mode 100644
index 00000000..1e09a01f
--- /dev/null
+++ b/freebsd/sbin/pfctl/pf_print_state.c
@@ -0,0 +1,387 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pf_print_state.c,v 1.52 2008/08/12 16:40:18 david Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/endian.h>
+#include <net/if.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pf_print_state-data.h"
+#endif /* __rtems__ */
+
+void print_name(struct pf_addr *, sa_family_t);
+
+void
+print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
+{
+ switch (addr->type) {
+ case PF_ADDR_DYNIFTL:
+ printf("(%s", addr->v.ifname);
+ if (addr->iflags & PFI_AFLAG_NETWORK)
+ printf(":network");
+ if (addr->iflags & PFI_AFLAG_BROADCAST)
+ printf(":broadcast");
+ if (addr->iflags & PFI_AFLAG_PEER)
+ printf(":peer");
+ if (addr->iflags & PFI_AFLAG_NOALIAS)
+ printf(":0");
+ if (verbose) {
+ if (addr->p.dyncnt <= 0)
+ printf(":*");
+ else
+ printf(":%d", addr->p.dyncnt);
+ }
+ printf(")");
+ break;
+ case PF_ADDR_TABLE:
+ if (verbose)
+ if (addr->p.tblcnt == -1)
+ printf("<%s:*>", addr->v.tblname);
+ else
+ printf("<%s:%d>", addr->v.tblname,
+ addr->p.tblcnt);
+ else
+ printf("<%s>", addr->v.tblname);
+ return;
+ case PF_ADDR_RANGE: {
+ char buf[48];
+
+ if (inet_ntop(af, &addr->v.a.addr, buf, sizeof(buf)) == NULL)
+ printf("?");
+ else
+ printf("%s", buf);
+ if (inet_ntop(af, &addr->v.a.mask, buf, sizeof(buf)) == NULL)
+ printf(" - ?");
+ else
+ printf(" - %s", buf);
+ break;
+ }
+ case PF_ADDR_ADDRMASK:
+ if (PF_AZERO(&addr->v.a.addr, AF_INET6) &&
+ PF_AZERO(&addr->v.a.mask, AF_INET6))
+ printf("any");
+ else {
+ char buf[48];
+
+ if (inet_ntop(af, &addr->v.a.addr, buf,
+ sizeof(buf)) == NULL)
+ printf("?");
+ else
+ printf("%s", buf);
+ }
+ break;
+ case PF_ADDR_NOROUTE:
+ printf("no-route");
+ return;
+ case PF_ADDR_URPFFAILED:
+ printf("urpf-failed");
+ return;
+ default:
+ printf("?");
+ return;
+ }
+
+ /* mask if not _both_ address and mask are zero */
+ if (addr->type != PF_ADDR_RANGE &&
+ !(PF_AZERO(&addr->v.a.addr, AF_INET6) &&
+ PF_AZERO(&addr->v.a.mask, AF_INET6))) {
+ int bits = unmask(&addr->v.a.mask, af);
+
+ if (bits != (af == AF_INET ? 32 : 128))
+ printf("/%d", bits);
+ }
+}
+
+void
+print_name(struct pf_addr *addr, sa_family_t af)
+{
+ char host[NI_MAXHOST];
+
+ strlcpy(host, "?", sizeof(host));
+ switch (af) {
+ case AF_INET: {
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr = addr->v4;
+ getnameinfo((struct sockaddr *)&sin, sin.sin_len,
+ host, sizeof(host), NULL, 0, NI_NOFQDN);
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 sin6;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = addr->v6;
+ getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ host, sizeof(host), NULL, 0, NI_NOFQDN);
+ break;
+ }
+ }
+ printf("%s", host);
+}
+
+void
+print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts)
+{
+ if (opts & PF_OPT_USEDNS)
+ print_name(addr, af);
+ else {
+ struct pf_addr_wrap aw;
+
+ memset(&aw, 0, sizeof(aw));
+ aw.v.a.addr = *addr;
+ if (af == AF_INET)
+ aw.v.a.mask.addr32[0] = 0xffffffff;
+ else {
+ memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
+ af = AF_INET6;
+ }
+ print_addr(&aw, af, opts & PF_OPT_VERBOSE2);
+ }
+
+ if (port) {
+ if (af == AF_INET)
+ printf(":%u", ntohs(port));
+ else
+ printf("[%u]", ntohs(port));
+ }
+}
+
+void
+print_seq(struct pfsync_state_peer *p)
+{
+ if (p->seqdiff)
+ printf("[%u + %u](+%u)", ntohl(p->seqlo),
+ ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff));
+ else
+ printf("[%u + %u]", ntohl(p->seqlo),
+ ntohl(p->seqhi) - ntohl(p->seqlo));
+}
+
+void
+print_state(struct pfsync_state *s, int opts)
+{
+ struct pfsync_state_peer *src, *dst;
+ struct pfsync_state_key *key, *sk, *nk;
+ struct protoent *p;
+ int min, sec;
+#ifndef __NO_STRICT_ALIGNMENT
+ struct pfsync_state_key aligned_key[2];
+
+ bcopy(&s->key, aligned_key, sizeof(aligned_key));
+ key = aligned_key;
+#else
+ key = s->key;
+#endif
+
+ if (s->direction == PF_OUT) {
+ src = &s->src;
+ dst = &s->dst;
+ sk = &key[PF_SK_STACK];
+ nk = &key[PF_SK_WIRE];
+ if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+ sk->port[0] = nk->port[0];
+ } else {
+ src = &s->dst;
+ dst = &s->src;
+ sk = &key[PF_SK_WIRE];
+ nk = &key[PF_SK_STACK];
+ if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+ sk->port[1] = nk->port[1];
+ }
+ printf("%s ", s->ifname);
+ if ((p = getprotobynumber(s->proto)) != NULL)
+ printf("%s ", p->p_name);
+ else
+ printf("%u ", s->proto);
+
+ print_host(&nk->addr[1], nk->port[1], s->af, opts);
+ if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) ||
+ nk->port[1] != sk->port[1]) {
+ printf(" (");
+ print_host(&sk->addr[1], sk->port[1], s->af, opts);
+ printf(")");
+ }
+ if (s->direction == PF_OUT)
+ printf(" -> ");
+ else
+ printf(" <- ");
+ print_host(&nk->addr[0], nk->port[0], s->af, opts);
+ if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) ||
+ nk->port[0] != sk->port[0]) {
+ printf(" (");
+ print_host(&sk->addr[0], sk->port[0], s->af, opts);
+ printf(")");
+ }
+
+ printf(" ");
+ if (s->proto == IPPROTO_TCP) {
+ if (src->state <= TCPS_TIME_WAIT &&
+ dst->state <= TCPS_TIME_WAIT)
+ printf(" %s:%s\n", tcpstates[src->state],
+ tcpstates[dst->state]);
+ else if (src->state == PF_TCPS_PROXY_SRC ||
+ dst->state == PF_TCPS_PROXY_SRC)
+ printf(" PROXY:SRC\n");
+ else if (src->state == PF_TCPS_PROXY_DST ||
+ dst->state == PF_TCPS_PROXY_DST)
+ printf(" PROXY:DST\n");
+ else
+ printf(" <BAD STATE LEVELS %u:%u>\n",
+ src->state, dst->state);
+ if (opts & PF_OPT_VERBOSE) {
+ printf(" ");
+ print_seq(src);
+ if (src->wscale && dst->wscale)
+ printf(" wscale %u",
+ src->wscale & PF_WSCALE_MASK);
+ printf(" ");
+ print_seq(dst);
+ if (src->wscale && dst->wscale)
+ printf(" wscale %u",
+ dst->wscale & PF_WSCALE_MASK);
+ printf("\n");
+ }
+ } else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES &&
+ dst->state < PFUDPS_NSTATES) {
+ const char *states[] = PFUDPS_NAMES;
+
+ printf(" %s:%s\n", states[src->state], states[dst->state]);
+#ifndef INET6
+ } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
+ dst->state < PFOTHERS_NSTATES) {
+#else
+ } else if (s->proto != IPPROTO_ICMP && s->proto != IPPROTO_ICMPV6 &&
+ src->state < PFOTHERS_NSTATES && dst->state < PFOTHERS_NSTATES) {
+#endif
+ /* XXX ICMP doesn't really have state levels */
+ const char *states[] = PFOTHERS_NAMES;
+
+ printf(" %s:%s\n", states[src->state], states[dst->state]);
+ } else {
+ printf(" %u:%u\n", src->state, dst->state);
+ }
+
+ if (opts & PF_OPT_VERBOSE) {
+ u_int64_t packets[2];
+ u_int64_t bytes[2];
+ u_int32_t creation = ntohl(s->creation);
+ u_int32_t expire = ntohl(s->expire);
+
+ sec = creation % 60;
+ creation /= 60;
+ min = creation % 60;
+ creation /= 60;
+ printf(" age %.2u:%.2u:%.2u", creation, min, sec);
+ sec = expire % 60;
+ expire /= 60;
+ min = expire % 60;
+ expire /= 60;
+ printf(", expires in %.2u:%.2u:%.2u", expire, min, sec);
+
+ bcopy(s->packets[0], &packets[0], sizeof(u_int64_t));
+ bcopy(s->packets[1], &packets[1], sizeof(u_int64_t));
+ bcopy(s->bytes[0], &bytes[0], sizeof(u_int64_t));
+ bcopy(s->bytes[1], &bytes[1], sizeof(u_int64_t));
+ printf(", %ju:%ju pkts, %ju:%ju bytes",
+ (uintmax_t )be64toh(packets[0]),
+ (uintmax_t )be64toh(packets[1]),
+ (uintmax_t )be64toh(bytes[0]),
+ (uintmax_t )be64toh(bytes[1]));
+ if (ntohl(s->anchor) != -1)
+ printf(", anchor %u", ntohl(s->anchor));
+ if (ntohl(s->rule) != -1)
+ printf(", rule %u", ntohl(s->rule));
+ if (s->state_flags & PFSTATE_SLOPPY)
+ printf(", sloppy");
+ if (s->sync_flags & PFSYNC_FLAG_SRCNODE)
+ printf(", source-track");
+ if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE)
+ printf(", sticky-address");
+ printf("\n");
+ }
+ if (opts & PF_OPT_VERBOSE2) {
+ u_int64_t id;
+
+ bcopy(&s->id, &id, sizeof(u_int64_t));
+ printf(" id: %016jx creatorid: %08x",
+ (uintmax_t )be64toh(id), ntohl(s->creatorid));
+ printf("\n");
+ }
+}
+
+int
+unmask(struct pf_addr *m, sa_family_t af)
+{
+ int i = 31, j = 0, b = 0;
+ u_int32_t tmp;
+
+ while (j < 4 && m->addr32[j] == 0xffffffff) {
+ b += 32;
+ j++;
+ }
+ if (j < 4) {
+ tmp = ntohl(m->addr32[j]);
+ for (i = 31; tmp & (1 << i); --i)
+ b++;
+ }
+ return (b);
+}
diff --git a/freebsd/sbin/pfctl/pfctl.c b/freebsd/sbin/pfctl/pfctl.c
new file mode 100644
index 00000000..ab597068
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl.c
@@ -0,0 +1,2445 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * Copyright (c) 2002,2003 Henning Brauer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#define __need_getopt_newlib
+#include <getopt.h>
+#include <machine/rtems-bsd-program.h>
+#include <machine/rtems-bsd-commands.h>
+#define pf_get_ruleset_number _bsd_pf_get_ruleset_number
+#define pf_init_ruleset _bsd_pf_init_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <net/altq/altq.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl-data.h"
+#endif /* __rtems__ */
+
+void usage(void);
+int pfctl_enable(int, int);
+int pfctl_disable(int, int);
+int pfctl_clear_stats(int, int);
+int pfctl_clear_interface_flags(int, int);
+int pfctl_clear_rules(int, int, char *);
+int pfctl_clear_nat(int, int, char *);
+int pfctl_clear_altq(int, int);
+int pfctl_clear_src_nodes(int, int);
+int pfctl_clear_states(int, const char *, int);
+void pfctl_addrprefix(char *, struct pf_addr *);
+int pfctl_kill_src_nodes(int, const char *, int);
+int pfctl_net_kill_states(int, const char *, int);
+int pfctl_label_kill_states(int, const char *, int);
+int pfctl_id_kill_states(int, const char *, int);
+void pfctl_init_options(struct pfctl *);
+int pfctl_load_options(struct pfctl *);
+int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
+int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
+int pfctl_load_debug(struct pfctl *, unsigned int);
+int pfctl_load_logif(struct pfctl *, char *);
+int pfctl_load_hostid(struct pfctl *, u_int32_t);
+int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
+ char *);
+void pfctl_print_rule_counters(struct pf_rule *, int);
+int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
+int pfctl_show_nat(int, int, char *);
+int pfctl_show_src_nodes(int, int);
+int pfctl_show_states(int, const char *, int);
+int pfctl_show_status(int, int);
+int pfctl_show_timeouts(int, int);
+int pfctl_show_limits(int, int);
+void pfctl_debug(int, u_int32_t, int);
+int pfctl_test_altqsupport(int, int);
+int pfctl_show_anchors(int, int, char *);
+int pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
+int pfctl_load_ruleset(struct pfctl *, char *,
+ struct pf_ruleset *, int, int);
+int pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
+const char *pfctl_lookup_option(char *, const char * const *);
+
+static struct pf_anchor_global pf_anchors;
+static struct pf_anchor pf_main_anchor;
+
+static const char *clearopt;
+static char *rulesopt;
+static const char *showopt;
+static const char *debugopt;
+static char *anchoropt;
+static const char *optiopt = NULL;
+static const char *pf_device = "/dev/pf";
+static char *ifaceopt;
+static char *tableopt;
+static const char *tblcmdopt;
+static int src_node_killers;
+static char *src_node_kill[2];
+static int state_killers;
+static char *state_kill[2];
+int loadopt;
+int altqsupport;
+
+int dev = -1;
+static int first_title = 1;
+static int labels = 0;
+
+#define INDENT(d, o) do { \
+ if (o) { \
+ int i; \
+ for (i=0; i < d; i++) \
+ printf(" "); \
+ } \
+ } while (0); \
+
+
+static const struct {
+ const char *name;
+ int index;
+} pf_limits[] = {
+ { "states", PF_LIMIT_STATES },
+ { "src-nodes", PF_LIMIT_SRC_NODES },
+ { "frags", PF_LIMIT_FRAGS },
+ { "table-entries", PF_LIMIT_TABLE_ENTRIES },
+ { NULL, 0 }
+};
+
+struct pf_hint {
+ const char *name;
+ int timeout;
+};
+static const struct pf_hint pf_hint_normal[] = {
+ { "tcp.first", 2 * 60 },
+ { "tcp.opening", 30 },
+ { "tcp.established", 24 * 60 * 60 },
+ { "tcp.closing", 15 * 60 },
+ { "tcp.finwait", 45 },
+ { "tcp.closed", 90 },
+ { "tcp.tsdiff", 30 },
+ { NULL, 0 }
+};
+static const struct pf_hint pf_hint_satellite[] = {
+ { "tcp.first", 3 * 60 },
+ { "tcp.opening", 30 + 5 },
+ { "tcp.established", 24 * 60 * 60 },
+ { "tcp.closing", 15 * 60 + 5 },
+ { "tcp.finwait", 45 + 5 },
+ { "tcp.closed", 90 + 5 },
+ { "tcp.tsdiff", 60 },
+ { NULL, 0 }
+};
+static const struct pf_hint pf_hint_conservative[] = {
+ { "tcp.first", 60 * 60 },
+ { "tcp.opening", 15 * 60 },
+ { "tcp.established", 5 * 24 * 60 * 60 },
+ { "tcp.closing", 60 * 60 },
+ { "tcp.finwait", 10 * 60 },
+ { "tcp.closed", 3 * 60 },
+ { "tcp.tsdiff", 60 },
+ { NULL, 0 }
+};
+static const struct pf_hint pf_hint_aggressive[] = {
+ { "tcp.first", 30 },
+ { "tcp.opening", 5 },
+ { "tcp.established", 5 * 60 * 60 },
+ { "tcp.closing", 60 },
+ { "tcp.finwait", 30 },
+ { "tcp.closed", 30 },
+ { "tcp.tsdiff", 10 },
+ { NULL, 0 }
+};
+
+static const struct {
+ const char *name;
+ const struct pf_hint *hint;
+} pf_hints[] = {
+ { "normal", pf_hint_normal },
+ { "satellite", pf_hint_satellite },
+ { "high-latency", pf_hint_satellite },
+ { "conservative", pf_hint_conservative },
+ { "aggressive", pf_hint_aggressive },
+ { NULL, NULL }
+};
+
+static const char * const clearopt_list[] = {
+ "nat", "queue", "rules", "Sources",
+ "states", "info", "Tables", "osfp", "all", NULL
+};
+
+static const char * const showopt_list[] = {
+ "nat", "queue", "rules", "Anchors", "Sources", "states", "info",
+ "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
+ "all", NULL
+};
+
+static const char * const tblcmdopt_list[] = {
+ "kill", "flush", "add", "delete", "load", "replace", "show",
+ "test", "zero", "expire", NULL
+};
+
+static const char * const debugopt_list[] = {
+ "none", "urgent", "misc", "loud", NULL
+};
+
+static const char * const optiopt_list[] = {
+ "none", "basic", "profile", NULL
+};
+
+void
+usage(void)
+{
+#ifndef __rtems__
+ extern char *__progname;
+#else /* __rtems__ */
+#define __progname "pfctl"
+#endif /* __rtems__ */
+
+ fprintf(stderr,
+"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
+ "\t[-f file] [-i interface] [-K host | network]\n"
+ "\t[-k host | network | label | id] [-o level] [-p device]\n"
+ "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
+ __progname);
+
+ exit(1);
+}
+
+int
+pfctl_enable(int dev, int opts)
+{
+ if (ioctl(dev, DIOCSTART)) {
+ if (errno == EEXIST)
+ errx(1, "pf already enabled");
+ else if (errno == ESRCH)
+ errx(1, "pfil registeration failed");
+ else
+ err(1, "DIOCSTART");
+ }
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf enabled\n");
+
+ if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
+ if (errno != EEXIST)
+ err(1, "DIOCSTARTALTQ");
+
+ return (0);
+}
+
+int
+pfctl_disable(int dev, int opts)
+{
+ if (ioctl(dev, DIOCSTOP)) {
+ if (errno == ENOENT)
+ errx(1, "pf not enabled");
+ else
+ err(1, "DIOCSTOP");
+ }
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf disabled\n");
+
+ if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
+ if (errno != ENOENT)
+ err(1, "DIOCSTOPALTQ");
+
+ return (0);
+}
+
+int
+pfctl_clear_stats(int dev, int opts)
+{
+ if (ioctl(dev, DIOCCLRSTATUS))
+ err(1, "DIOCCLRSTATUS");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf: statistics cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_interface_flags(int dev, int opts)
+{
+ struct pfioc_iface pi;
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ bzero(&pi, sizeof(pi));
+ pi.pfiio_flags = PFI_IFLAG_SKIP;
+
+ if (ioctl(dev, DIOCCLRIFFLAG, &pi))
+ err(1, "DIOCCLRIFFLAG");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf: interface flags reset\n");
+ }
+ return (0);
+}
+
+int
+pfctl_clear_rules(int dev, int opts, char *anchorname)
+{
+ struct pfr_buffer t;
+
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
+ pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_rules");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "rules cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_nat(int dev, int opts, char *anchorname)
+{
+ struct pfr_buffer t;
+
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
+ pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
+ pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_nat");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "nat cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_altq(int dev, int opts)
+{
+ struct pfr_buffer t;
+
+ if (!altqsupport)
+ return (-1);
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_altq");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "altq cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_src_nodes(int dev, int opts)
+{
+ if (ioctl(dev, DIOCCLRSRCNODES))
+ err(1, "DIOCCLRSRCNODES");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "source tracking entries cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+
+ memset(&psk, 0, sizeof(psk));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
+
+ if (ioctl(dev, DIOCCLRSTATES, &psk))
+ err(1, "DIOCCLRSTATES");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "%d states cleared\n", psk.psk_killed);
+ return (0);
+}
+
+void
+pfctl_addrprefix(char *addr, struct pf_addr *mask)
+{
+ char *p;
+ const char *errstr;
+ int prefix, ret_ga, q, r;
+ struct addrinfo hints, *res;
+
+ if ((p = strchr(addr, '/')) == NULL)
+ return;
+
+ *p++ = '\0';
+ prefix = strtonum(p, 0, 128, &errstr);
+ if (errstr)
+ errx(1, "prefix is %s: %s", errstr, p);
+
+ bzero(&hints, sizeof(hints));
+ /* prefix only with numeric addresses */
+ hints.ai_flags |= AI_NUMERICHOST;
+
+ if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
+ errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+
+ if (res->ai_family == AF_INET && prefix > 32)
+ errx(1, "prefix too long for AF_INET");
+ else if (res->ai_family == AF_INET6 && prefix > 128)
+ errx(1, "prefix too long for AF_INET6");
+
+ q = prefix >> 3;
+ r = prefix & 7;
+ switch (res->ai_family) {
+ case AF_INET:
+ bzero(&mask->v4, sizeof(mask->v4));
+ mask->v4.s_addr = htonl((u_int32_t)
+ (0xffffffffffULL << (32 - prefix)));
+ break;
+ case AF_INET6:
+ bzero(&mask->v6, sizeof(mask->v6));
+ if (q > 0)
+ memset((void *)&mask->v6, 0xff, q);
+ if (r > 0)
+ *((u_char *)&mask->v6 + q) =
+ (0xff00 >> r) & 0xff;
+ break;
+ }
+ freeaddrinfo(res);
+}
+
+int
+pfctl_kill_src_nodes(int dev, const char *iface, int opts)
+{
+ struct pfioc_src_node_kill psnk;
+ struct addrinfo *res[2], *resp[2];
+ struct sockaddr last_src, last_dst;
+ int killed, sources, dests;
+ int ret_ga;
+
+ killed = sources = dests = 0;
+
+ memset(&psnk, 0, sizeof(psnk));
+ memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
+ sizeof(psnk.psnk_src.addr.v.a.mask));
+ memset(&last_src, 0xff, sizeof(last_src));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+
+ pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
+
+ if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
+ errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
+ if (resp[0]->ai_addr == NULL)
+ continue;
+ /* We get lots of duplicates. Catch the easy ones */
+ if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
+ continue;
+ last_src = *(struct sockaddr *)resp[0]->ai_addr;
+
+ psnk.psnk_af = resp[0]->ai_family;
+ sources++;
+
+ if (psnk.psnk_af == AF_INET)
+ psnk.psnk_src.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
+ else if (psnk.psnk_af == AF_INET6)
+ psnk.psnk_src.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[0]->ai_addr)->
+ sin6_addr;
+ else
+ errx(1, "Unknown address family %d", psnk.psnk_af);
+
+ if (src_node_killers > 1) {
+ dests = 0;
+ memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
+ sizeof(psnk.psnk_dst.addr.v.a.mask));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+ pfctl_addrprefix(src_node_kill[1],
+ &psnk.psnk_dst.addr.v.a.mask);
+ if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
+ &res[1]))) {
+ errx(1, "getaddrinfo: %s",
+ gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[1] = res[1]; resp[1];
+ resp[1] = resp[1]->ai_next) {
+ if (resp[1]->ai_addr == NULL)
+ continue;
+ if (psnk.psnk_af != resp[1]->ai_family)
+ continue;
+
+ if (memcmp(&last_dst, resp[1]->ai_addr,
+ sizeof(last_dst)) == 0)
+ continue;
+ last_dst = *(struct sockaddr *)resp[1]->ai_addr;
+
+ dests++;
+
+ if (psnk.psnk_af == AF_INET)
+ psnk.psnk_dst.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[1]->
+ ai_addr)->sin_addr;
+ else if (psnk.psnk_af == AF_INET6)
+ psnk.psnk_dst.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[1]->
+ ai_addr)->sin6_addr;
+ else
+ errx(1, "Unknown address family %d",
+ psnk.psnk_af);
+
+ if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
+ err(1, "DIOCKILLSRCNODES");
+ killed += psnk.psnk_killed;
+ }
+ freeaddrinfo(res[1]);
+ } else {
+ if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
+ err(1, "DIOCKILLSRCNODES");
+ killed += psnk.psnk_killed;
+ }
+ }
+
+ freeaddrinfo(res[0]);
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d src nodes from %d sources and %d "
+ "destinations\n", killed, sources, dests);
+ return (0);
+}
+
+int
+pfctl_net_kill_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+ struct addrinfo *res[2], *resp[2];
+ struct sockaddr last_src, last_dst;
+ int killed, sources, dests;
+ int ret_ga;
+
+ killed = sources = dests = 0;
+
+ memset(&psk, 0, sizeof(psk));
+ memset(&psk.psk_src.addr.v.a.mask, 0xff,
+ sizeof(psk.psk_src.addr.v.a.mask));
+ memset(&last_src, 0xff, sizeof(last_src));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
+
+ pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
+
+ if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
+ errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
+ if (resp[0]->ai_addr == NULL)
+ continue;
+ /* We get lots of duplicates. Catch the easy ones */
+ if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
+ continue;
+ last_src = *(struct sockaddr *)resp[0]->ai_addr;
+
+ psk.psk_af = resp[0]->ai_family;
+ sources++;
+
+ if (psk.psk_af == AF_INET)
+ psk.psk_src.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
+ else if (psk.psk_af == AF_INET6)
+ psk.psk_src.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[0]->ai_addr)->
+ sin6_addr;
+ else
+ errx(1, "Unknown address family %d", psk.psk_af);
+
+ if (state_killers > 1) {
+ dests = 0;
+ memset(&psk.psk_dst.addr.v.a.mask, 0xff,
+ sizeof(psk.psk_dst.addr.v.a.mask));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+ pfctl_addrprefix(state_kill[1],
+ &psk.psk_dst.addr.v.a.mask);
+ if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
+ &res[1]))) {
+ errx(1, "getaddrinfo: %s",
+ gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[1] = res[1]; resp[1];
+ resp[1] = resp[1]->ai_next) {
+ if (resp[1]->ai_addr == NULL)
+ continue;
+ if (psk.psk_af != resp[1]->ai_family)
+ continue;
+
+ if (memcmp(&last_dst, resp[1]->ai_addr,
+ sizeof(last_dst)) == 0)
+ continue;
+ last_dst = *(struct sockaddr *)resp[1]->ai_addr;
+
+ dests++;
+
+ if (psk.psk_af == AF_INET)
+ psk.psk_dst.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[1]->
+ ai_addr)->sin_addr;
+ else if (psk.psk_af == AF_INET6)
+ psk.psk_dst.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[1]->
+ ai_addr)->sin6_addr;
+ else
+ errx(1, "Unknown address family %d",
+ psk.psk_af);
+
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+ killed += psk.psk_killed;
+ }
+ freeaddrinfo(res[1]);
+ } else {
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+ killed += psk.psk_killed;
+ }
+ }
+
+ freeaddrinfo(res[0]);
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d states from %d sources and %d "
+ "destinations\n", killed, sources, dests);
+ return (0);
+}
+
+int
+pfctl_label_kill_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+
+ if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
+ warnx("no label specified");
+ usage();
+ }
+ memset(&psk, 0, sizeof(psk));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
+
+ if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
+ sizeof(psk.psk_label))
+ errx(1, "label too long: %s", state_kill[1]);
+
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d states\n", psk.psk_killed);
+
+ return (0);
+}
+
+int
+pfctl_id_kill_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+
+ if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
+ warnx("no id specified");
+ usage();
+ }
+
+ memset(&psk, 0, sizeof(psk));
+ if ((sscanf(state_kill[1], "%jx/%x",
+ &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
+ HTONL(psk.psk_pfcmp.creatorid);
+ else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
+ psk.psk_pfcmp.creatorid = 0;
+ } else {
+ warnx("wrong id format specified");
+ usage();
+ }
+ if (psk.psk_pfcmp.id == 0) {
+ warnx("cannot kill id 0");
+ usage();
+ }
+
+ psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d states\n", psk.psk_killed);
+
+ return (0);
+}
+
+int
+pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
+ u_int32_t ticket, int r_action, char *anchorname)
+{
+ struct pfioc_pooladdr pp;
+ struct pf_pooladdr *pa;
+ u_int32_t pnr, mpnr;
+
+ memset(&pp, 0, sizeof(pp));
+ memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
+ pp.r_action = r_action;
+ pp.r_num = nr;
+ pp.ticket = ticket;
+ if (ioctl(dev, DIOCGETADDRS, &pp)) {
+ warn("DIOCGETADDRS");
+ return (-1);
+ }
+ mpnr = pp.nr;
+ TAILQ_INIT(&pool->list);
+ for (pnr = 0; pnr < mpnr; ++pnr) {
+ pp.nr = pnr;
+ if (ioctl(dev, DIOCGETADDR, &pp)) {
+ warn("DIOCGETADDR");
+ return (-1);
+ }
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "calloc");
+ bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
+ TAILQ_INSERT_TAIL(&pool->list, pa, entries);
+ }
+
+ return (0);
+}
+
+void
+pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
+{
+ struct pf_pooladdr *pa;
+
+ while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
+ TAILQ_REMOVE(&src->list, pa, entries);
+ TAILQ_INSERT_TAIL(&dst->list, pa, entries);
+ }
+}
+
+void
+pfctl_clear_pool(struct pf_pool *pool)
+{
+ struct pf_pooladdr *pa;
+
+ while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
+ TAILQ_REMOVE(&pool->list, pa, entries);
+ free(pa);
+ }
+}
+
+void
+pfctl_print_rule_counters(struct pf_rule *rule, int opts)
+{
+ if (opts & PF_OPT_DEBUG) {
+ const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
+ "p", "sa", "sp", "da", "dp" };
+ int i;
+
+ printf(" [ Skip steps: ");
+ for (i = 0; i < PF_SKIP_COUNT; ++i) {
+ if (rule->skip[i].nr == rule->nr + 1)
+ continue;
+ printf("%s=", t[i]);
+ if (rule->skip[i].nr == -1)
+ printf("end ");
+ else
+ printf("%u ", rule->skip[i].nr);
+ }
+ printf("]\n");
+
+ printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
+ rule->qname, rule->qid, rule->pqname, rule->pqid);
+ }
+ if (opts & PF_OPT_VERBOSE) {
+ printf(" [ Evaluations: %-8llu Packets: %-8llu "
+ "Bytes: %-10llu States: %-6ju]\n",
+ (unsigned long long)rule->evaluations,
+ (unsigned long long)(rule->packets[0] +
+ rule->packets[1]),
+ (unsigned long long)(rule->bytes[0] +
+ rule->bytes[1]), (uintmax_t)rule->u_states_cur);
+ if (!(opts & PF_OPT_DEBUG))
+ printf(" [ Inserted: uid %u pid %u "
+ "State Creations: %-6ju]\n",
+ (unsigned)rule->cuid, (unsigned)rule->cpid,
+ (uintmax_t)rule->u_states_tot);
+ }
+}
+
+void
+pfctl_print_title(char *title)
+{
+ if (!first_title)
+ printf("\n");
+ first_title = 0;
+ printf("%s\n", title);
+}
+
+int
+pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
+ char *anchorname, int depth)
+{
+ struct pfioc_rule pr;
+ u_int32_t nr, mnr, header = 0;
+ int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
+ int numeric = opts & PF_OPT_NUMERIC;
+ int len = strlen(path);
+ int brace;
+ char *p;
+
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
+
+ memset(&pr, 0, sizeof(pr));
+ memcpy(pr.anchor, path, sizeof(pr.anchor));
+ if (opts & PF_OPT_SHOWALL) {
+ pr.rule.action = PF_PASS;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ goto error;
+ }
+ header++;
+ }
+ pr.rule.action = PF_SCRUB;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ goto error;
+ }
+ if (opts & PF_OPT_SHOWALL) {
+ if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
+ pfctl_print_title("FILTER RULES:");
+ else if (format == PFCTL_SHOW_LABELS && labels)
+ pfctl_print_title("LABEL COUNTERS:");
+ }
+ mnr = pr.nr;
+ if (opts & PF_OPT_CLRRULECTRS)
+ pr.action = PF_GET_CLR_CNTR;
+
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULE");
+ goto error;
+ }
+
+ if (pfctl_get_pool(dev, &pr.rule.rpool,
+ nr, pr.ticket, PF_SCRUB, path) != 0)
+ goto error;
+
+ switch (format) {
+ case PFCTL_SHOW_LABELS:
+ break;
+ case PFCTL_SHOW_RULES:
+ if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
+ labels = 1;
+ print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
+ printf("\n");
+ pfctl_print_rule_counters(&pr.rule, opts);
+ break;
+ case PFCTL_SHOW_NOTHING:
+ break;
+ }
+ pfctl_clear_pool(&pr.rule.rpool);
+ }
+ pr.rule.action = PF_PASS;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ goto error;
+ }
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULE");
+ goto error;
+ }
+
+ if (pfctl_get_pool(dev, &pr.rule.rpool,
+ nr, pr.ticket, PF_PASS, path) != 0)
+ goto error;
+
+ switch (format) {
+ case PFCTL_SHOW_LABELS:
+ if (pr.rule.label[0]) {
+ printf("%s %llu %llu %llu %llu"
+ " %llu %llu %llu %ju\n",
+ pr.rule.label,
+ (unsigned long long)pr.rule.evaluations,
+ (unsigned long long)(pr.rule.packets[0] +
+ pr.rule.packets[1]),
+ (unsigned long long)(pr.rule.bytes[0] +
+ pr.rule.bytes[1]),
+ (unsigned long long)pr.rule.packets[0],
+ (unsigned long long)pr.rule.bytes[0],
+ (unsigned long long)pr.rule.packets[1],
+ (unsigned long long)pr.rule.bytes[1],
+ (uintmax_t)pr.rule.u_states_tot);
+ }
+ break;
+ case PFCTL_SHOW_RULES:
+ brace = 0;
+ if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
+ labels = 1;
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ if (pr.anchor_call[0] &&
+ ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
+ ((void *)p == (void *)pr.anchor_call ||
+ *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
+ brace++;
+ if ((p = strrchr(pr.anchor_call, '/')) !=
+ NULL)
+ p++;
+ else
+ p = &pr.anchor_call[0];
+ } else
+ p = &pr.anchor_call[0];
+
+ print_rule(&pr.rule, p, rule_numbers, numeric);
+ if (brace)
+ printf(" {\n");
+ else
+ printf("\n");
+ pfctl_print_rule_counters(&pr.rule, opts);
+ if (brace) {
+ pfctl_show_rules(dev, path, opts, format,
+ p, depth + 1);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ break;
+ case PFCTL_SHOW_NOTHING:
+ break;
+ }
+ pfctl_clear_pool(&pr.rule.rpool);
+ }
+ path[len] = '\0';
+ return (0);
+
+ error:
+ path[len] = '\0';
+ return (-1);
+}
+
+int
+pfctl_show_nat(int dev, int opts, char *anchorname)
+{
+ struct pfioc_rule pr;
+ u_int32_t mnr, nr;
+#ifndef __rtems__
+ static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
+#else /* __rtems__ */
+ static const int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
+#endif /* __rtems__ */
+ int i, dotitle = opts & PF_OPT_SHOWALL;
+
+ memset(&pr, 0, sizeof(pr));
+ memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
+ for (i = 0; i < 3; i++) {
+ pr.rule.action = nattype[i];
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ return (-1);
+ }
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULE");
+ return (-1);
+ }
+ if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
+ pr.ticket, nattype[i], anchorname) != 0)
+ return (-1);
+ if (dotitle) {
+ pfctl_print_title("TRANSLATION RULES:");
+ dotitle = 0;
+ }
+ print_rule(&pr.rule, pr.anchor_call,
+ opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
+ printf("\n");
+ pfctl_print_rule_counters(&pr.rule, opts);
+ pfctl_clear_pool(&pr.rule.rpool);
+ }
+ }
+ return (0);
+}
+
+int
+pfctl_show_src_nodes(int dev, int opts)
+{
+ struct pfioc_src_nodes psn;
+ struct pf_src_node *p;
+ char *inbuf = NULL, *newinbuf = NULL;
+ unsigned int len = 0;
+ int i;
+
+ memset(&psn, 0, sizeof(psn));
+ for (;;) {
+ psn.psn_len = len;
+ if (len) {
+ newinbuf = realloc(inbuf, len);
+ if (newinbuf == NULL)
+ err(1, "realloc");
+ psn.psn_buf = inbuf = newinbuf;
+ }
+ if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
+ warn("DIOCGETSRCNODES");
+ free(inbuf);
+ return (-1);
+ }
+ if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
+ break;
+ if (len == 0 && psn.psn_len == 0)
+ goto done;
+ if (len == 0 && psn.psn_len != 0)
+ len = psn.psn_len;
+ if (psn.psn_len == 0)
+ goto done; /* no src_nodes */
+ len *= 2;
+ }
+ p = psn.psn_src_nodes;
+ if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
+ pfctl_print_title("SOURCE TRACKING NODES:");
+ for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
+ print_src_node(p, opts);
+ p++;
+ }
+done:
+ free(inbuf);
+ return (0);
+}
+
+int
+pfctl_show_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_states ps;
+ struct pfsync_state *p;
+ char *inbuf = NULL, *newinbuf = NULL;
+ unsigned int len = 0;
+ int i, dotitle = (opts & PF_OPT_SHOWALL);
+
+ memset(&ps, 0, sizeof(ps));
+ for (;;) {
+ ps.ps_len = len;
+ if (len) {
+ newinbuf = realloc(inbuf, len);
+ if (newinbuf == NULL)
+ err(1, "realloc");
+ ps.ps_buf = inbuf = newinbuf;
+ }
+ if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
+ warn("DIOCGETSTATES");
+ free(inbuf);
+ return (-1);
+ }
+ if (ps.ps_len + sizeof(struct pfioc_states) < len)
+ break;
+ if (len == 0 && ps.ps_len == 0)
+ goto done;
+ if (len == 0 && ps.ps_len != 0)
+ len = ps.ps_len;
+ if (ps.ps_len == 0)
+ goto done; /* no states */
+ len *= 2;
+ }
+ p = ps.ps_states;
+ for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
+ if (iface != NULL && strcmp(p->ifname, iface))
+ continue;
+ if (dotitle) {
+ pfctl_print_title("STATES:");
+ dotitle = 0;
+ }
+ print_state(p, opts);
+ }
+done:
+ free(inbuf);
+ return (0);
+}
+
+int
+pfctl_show_status(int dev, int opts)
+{
+ struct pf_status status;
+
+ if (ioctl(dev, DIOCGETSTATUS, &status)) {
+ warn("DIOCGETSTATUS");
+ return (-1);
+ }
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("INFO:");
+ print_status(&status, opts);
+ return (0);
+}
+
+int
+pfctl_show_timeouts(int dev, int opts)
+{
+ struct pfioc_tm pt;
+ int i;
+
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("TIMEOUTS:");
+ memset(&pt, 0, sizeof(pt));
+ for (i = 0; pf_timeouts[i].name; i++) {
+ pt.timeout = pf_timeouts[i].timeout;
+ if (ioctl(dev, DIOCGETTIMEOUT, &pt))
+ err(1, "DIOCGETTIMEOUT");
+ printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
+ if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
+ pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
+ printf(" states");
+ else
+ printf("s");
+ printf("\n");
+ }
+ return (0);
+
+}
+
+int
+pfctl_show_limits(int dev, int opts)
+{
+ struct pfioc_limit pl;
+ int i;
+
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("LIMITS:");
+ memset(&pl, 0, sizeof(pl));
+ for (i = 0; pf_limits[i].name; i++) {
+ pl.index = pf_limits[i].index;
+ if (ioctl(dev, DIOCGETLIMIT, &pl))
+ err(1, "DIOCGETLIMIT");
+ printf("%-13s ", pf_limits[i].name);
+ if (pl.limit == UINT_MAX)
+ printf("unlimited\n");
+ else
+ printf("hard limit %8u\n", pl.limit);
+ }
+ return (0);
+}
+
+/* callbacks for rule/nat/rdr/addr */
+int
+pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
+{
+ struct pf_pooladdr *pa;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
+ err(1, "DIOCBEGINADDRS");
+ }
+
+ pf->paddr.af = af;
+ TAILQ_FOREACH(pa, &p->list, entries) {
+ memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
+ err(1, "DIOCADDADDR");
+ }
+ }
+ return (0);
+}
+
+int
+pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
+{
+ u_int8_t rs_num;
+ struct pf_rule *rule;
+ struct pf_ruleset *rs;
+ char *p;
+
+ rs_num = pf_get_ruleset_number(r->action);
+ if (rs_num == PF_RULESET_MAX)
+ errx(1, "Invalid rule type %d", r->action);
+
+ rs = &pf->anchor->ruleset;
+
+ if (anchor_call[0] && r->anchor == NULL) {
+ /*
+ * Don't make non-brace anchors part of the main anchor pool.
+ */
+ if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
+ err(1, "pfctl_add_rule: calloc");
+
+ pf_init_ruleset(&r->anchor->ruleset);
+ r->anchor->ruleset.anchor = r->anchor;
+ if (strlcpy(r->anchor->path, anchor_call,
+ sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
+ errx(1, "pfctl_add_rule: strlcpy");
+ if ((p = strrchr(anchor_call, '/')) != NULL) {
+ if (!strlen(p))
+ err(1, "pfctl_add_rule: bad anchor name %s",
+ anchor_call);
+ } else
+ p = (char *)anchor_call;
+ if (strlcpy(r->anchor->name, p,
+ sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
+ errx(1, "pfctl_add_rule: strlcpy");
+ }
+
+ if ((rule = calloc(1, sizeof(*rule))) == NULL)
+ err(1, "calloc");
+ bcopy(r, rule, sizeof(*rule));
+ TAILQ_INIT(&rule->rpool.list);
+ pfctl_move_pool(&r->rpool, &rule->rpool);
+
+ TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
+ return (0);
+}
+
+int
+pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
+{
+ int osize = pf->trans->pfrb_size;
+
+ if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
+ pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
+ pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
+ return (1);
+ }
+ if (a == pf->astack[0] && ((altqsupport &&
+ (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
+ return (2);
+ }
+ if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
+ pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
+ return (3);
+ }
+ if (pf->loadopt & PFCTL_FLAG_TABLE)
+ if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
+ return (4);
+ if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
+ return (5);
+
+ return (0);
+}
+
+int
+pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
+ int rs_num, int depth)
+{
+ struct pf_rule *r;
+ int error, len = strlen(path);
+ int brace = 0;
+
+ pf->anchor = rs->anchor;
+
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
+
+ if (depth) {
+ if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
+ brace++;
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" {\n");
+ if ((pf->opts & PF_OPT_NOACTION) == 0 &&
+ (error = pfctl_ruleset_trans(pf,
+ path, rs->anchor))) {
+ printf("pfctl_load_rulesets: "
+ "pfctl_ruleset_trans %d\n", error);
+ goto error;
+ }
+ } else if (pf->opts & PF_OPT_VERBOSE)
+ printf("\n");
+
+ }
+
+ if (pf->optimize && rs_num == PF_RULESET_FILTER)
+ pfctl_optimize_ruleset(pf, rs);
+
+ while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
+ TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
+ if ((error = pfctl_load_rule(pf, path, r, depth)))
+ goto error;
+ if (r->anchor) {
+ if ((error = pfctl_load_ruleset(pf, path,
+ &r->anchor->ruleset, rs_num, depth + 1)))
+ goto error;
+ } else if (pf->opts & PF_OPT_VERBOSE)
+ printf("\n");
+ free(r);
+ }
+ if (brace && pf->opts & PF_OPT_VERBOSE) {
+ INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ path[len] = '\0';
+ return (0);
+
+ error:
+ path[len] = '\0';
+ return (error);
+
+}
+
+int
+pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
+{
+ u_int8_t rs_num = pf_get_ruleset_number(r->action);
+ char *name;
+ struct pfioc_rule pr;
+ int len = strlen(path);
+
+ bzero(&pr, sizeof(pr));
+ /* set up anchor before adding to path for anchor_call */
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
+ if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
+ errx(1, "pfctl_load_rule: strlcpy");
+
+ if (r->anchor) {
+ if (r->anchor->match) {
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len,
+ "/%s", r->anchor->name);
+ else
+ snprintf(&path[len], MAXPATHLEN - len,
+ "%s", r->anchor->name);
+ name = path;
+ } else
+ name = r->anchor->path;
+ } else
+ name = "";
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (pfctl_add_pool(pf, &r->rpool, r->af))
+ return (1);
+ pr.pool_ticket = pf->paddr.ticket;
+ memcpy(&pr.rule, r, sizeof(pr.rule));
+ if (r->anchor && strlcpy(pr.anchor_call, name,
+ sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
+ errx(1, "pfctl_load_rule: strlcpy");
+ if (ioctl(pf->dev, DIOCADDRULE, &pr))
+ err(1, "DIOCADDRULE");
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE) {
+ INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
+ print_rule(r, r->anchor ? r->anchor->name : "",
+ pf->opts & PF_OPT_VERBOSE2,
+ pf->opts & PF_OPT_NUMERIC);
+ }
+ path[len] = '\0';
+ pfctl_clear_pool(&r->rpool);
+ return (0);
+}
+
+int
+pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
+{
+ if (altqsupport &&
+ (loadopt & PFCTL_FLAG_ALTQ) != 0) {
+ memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
+ if (errno == ENXIO)
+ errx(1, "qtype not configured");
+ else if (errno == ENODEV)
+ errx(1, "%s: driver does not support "
+ "altq", a->ifname);
+ else
+ err(1, "DIOCADDALTQ");
+ }
+ }
+ pfaltq_store(&pf->paltq->altq);
+ }
+ return (0);
+}
+
+int
+pfctl_rules(int dev, char *filename, int opts, int optimize,
+ char *anchorname, struct pfr_buffer *trans)
+{
+#define ERR(x) do { warn(x); goto _error; } while(0)
+#define ERRX(x) do { warnx(x); goto _error; } while(0)
+
+ struct pfr_buffer *t, buf;
+ struct pfioc_altq pa;
+ struct pfctl pf;
+ struct pf_ruleset *rs;
+ struct pfr_table trs;
+ char *path;
+ int osize;
+
+ RB_INIT(&pf_anchors);
+ memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
+ pf_init_ruleset(&pf_main_anchor.ruleset);
+ pf_main_anchor.ruleset.anchor = &pf_main_anchor;
+ if (trans == NULL) {
+ bzero(&buf, sizeof(buf));
+ buf.pfrb_type = PFRB_TRANS;
+ t = &buf;
+ osize = 0;
+ } else {
+ t = trans;
+ osize = t->pfrb_size;
+ }
+
+ memset(&pa, 0, sizeof(pa));
+ memset(&pf, 0, sizeof(pf));
+ memset(&trs, 0, sizeof(trs));
+ if ((path = calloc(1, MAXPATHLEN)) == NULL)
+ ERRX("pfctl_rules: calloc");
+ if (strlcpy(trs.pfrt_anchor, anchorname,
+ sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
+ ERRX("pfctl_rules: strlcpy");
+ pf.dev = dev;
+ pf.opts = opts;
+ pf.optimize = optimize;
+ pf.loadopt = loadopt;
+
+ /* non-brace anchor, create without resolving the path */
+ if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
+ ERRX("pfctl_rules: calloc");
+ rs = &pf.anchor->ruleset;
+ pf_init_ruleset(rs);
+ rs->anchor = pf.anchor;
+ if (strlcpy(pf.anchor->path, anchorname,
+ sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
+ errx(1, "pfctl_add_rule: strlcpy");
+ if (strlcpy(pf.anchor->name, anchorname,
+ sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
+ errx(1, "pfctl_add_rule: strlcpy");
+
+
+ pf.astack[0] = pf.anchor;
+ pf.asd = 0;
+ if (anchorname[0])
+ pf.loadopt &= ~PFCTL_FLAG_ALTQ;
+ pf.paltq = &pa;
+ pf.trans = t;
+ pfctl_init_options(&pf);
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ /*
+ * XXX For the time being we need to open transactions for
+ * the main ruleset before parsing, because tables are still
+ * loaded at parse time.
+ */
+ if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
+ ERRX("pfctl_rules");
+ if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
+ pa.ticket =
+ pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
+ if (pf.loadopt & PFCTL_FLAG_TABLE)
+ pf.astack[0]->ruleset.tticket =
+ pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
+ }
+
+ if (parse_config(filename, &pf) < 0) {
+ if ((opts & PF_OPT_NOACTION) == 0)
+ ERRX("Syntax error in config file: "
+ "pf rules not loaded");
+ else
+ goto _error;
+ }
+
+ if ((pf.loadopt & PFCTL_FLAG_FILTER &&
+ (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
+ (pf.loadopt & PFCTL_FLAG_NAT &&
+ (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
+ pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
+ pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
+ (pf.loadopt & PFCTL_FLAG_FILTER &&
+ pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
+ if ((opts & PF_OPT_NOACTION) == 0)
+ ERRX("Unable to load rules into kernel");
+ else
+ goto _error;
+ }
+
+ if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
+ if (check_commit_altq(dev, opts) != 0)
+ ERRX("errors in altq config");
+
+ /* process "load anchor" directives */
+ if (!anchorname[0])
+ if (pfctl_load_anchors(dev, &pf, t) == -1)
+ ERRX("load anchors");
+
+ if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
+ if (!anchorname[0])
+ if (pfctl_load_options(&pf))
+ goto _error;
+ if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
+ ERR("DIOCXCOMMIT");
+ }
+ return (0);
+
+_error:
+ if (trans == NULL) { /* main ruleset */
+ if ((opts & PF_OPT_NOACTION) == 0)
+ if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
+ err(1, "DIOCXROLLBACK");
+ exit(1);
+ } else { /* sub ruleset */
+ return (-1);
+ }
+
+#undef ERR
+#undef ERRX
+}
+
+FILE *
+pfctl_fopen(const char *name, const char *mode)
+{
+ struct stat st;
+ FILE *fp;
+
+ fp = fopen(name, mode);
+ if (fp == NULL)
+ return (NULL);
+ if (fstat(fileno(fp), &st)) {
+ fclose(fp);
+ return (NULL);
+ }
+ if (S_ISDIR(st.st_mode)) {
+ fclose(fp);
+ errno = EISDIR;
+ return (NULL);
+ }
+ return (fp);
+}
+
+void
+pfctl_init_options(struct pfctl *pf)
+{
+
+ pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
+ pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
+ pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
+ pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
+ pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
+ pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
+ pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
+ pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
+ pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
+ pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
+ pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
+ pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
+ pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
+ pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
+ pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
+ pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
+
+ pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
+ pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
+ pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
+ pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
+
+ pf->debug = PF_DEBUG_URGENT;
+}
+
+int
+pfctl_load_options(struct pfctl *pf)
+{
+ int i, error = 0;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ /* load limits */
+ for (i = 0; i < PF_LIMIT_MAX; i++) {
+ if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
+ continue;
+ if (pfctl_load_limit(pf, i, pf->limit[i]))
+ error = 1;
+ }
+
+ /*
+ * If we've set the limit, but haven't explicitly set adaptive
+ * timeouts, do it now with a start of 60% and end of 120%.
+ */
+ if (pf->limit_set[PF_LIMIT_STATES] &&
+ !pf->timeout_set[PFTM_ADAPTIVE_START] &&
+ !pf->timeout_set[PFTM_ADAPTIVE_END]) {
+ pf->timeout[PFTM_ADAPTIVE_START] =
+ (pf->limit[PF_LIMIT_STATES] / 10) * 6;
+ pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
+ pf->timeout[PFTM_ADAPTIVE_END] =
+ (pf->limit[PF_LIMIT_STATES] / 10) * 12;
+ pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
+ }
+
+ /* load timeouts */
+ for (i = 0; i < PFTM_MAX; i++) {
+ if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
+ continue;
+ if (pfctl_load_timeout(pf, i, pf->timeout[i]))
+ error = 1;
+ }
+
+ /* load debug */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
+ if (pfctl_load_debug(pf, pf->debug))
+ error = 1;
+
+ /* load logif */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
+ if (pfctl_load_logif(pf, pf->ifname))
+ error = 1;
+
+ /* load hostid */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
+ if (pfctl_load_hostid(pf, pf->hostid))
+ error = 1;
+
+ return (error);
+}
+
+int
+pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
+{
+ int i;
+
+
+ for (i = 0; pf_limits[i].name; i++) {
+ if (strcasecmp(opt, pf_limits[i].name) == 0) {
+ pf->limit[pf_limits[i].index] = limit;
+ pf->limit_set[pf_limits[i].index] = 1;
+ break;
+ }
+ }
+ if (pf_limits[i].name == NULL) {
+ warnx("Bad pool name.");
+ return (1);
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set limit %s %d\n", opt, limit);
+
+ return (0);
+}
+
+int
+pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
+{
+ struct pfioc_limit pl;
+
+ memset(&pl, 0, sizeof(pl));
+ pl.index = index;
+ pl.limit = limit;
+ if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
+ if (errno == EBUSY)
+ warnx("Current pool size exceeds requested hard limit");
+ else
+ warnx("DIOCSETLIMIT");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
+{
+ int i;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ for (i = 0; pf_timeouts[i].name; i++) {
+ if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
+ pf->timeout[pf_timeouts[i].timeout] = seconds;
+ pf->timeout_set[pf_timeouts[i].timeout] = 1;
+ break;
+ }
+ }
+
+ if (pf_timeouts[i].name == NULL) {
+ warnx("Bad timeout name.");
+ return (1);
+ }
+
+
+ if (pf->opts & PF_OPT_VERBOSE && ! quiet)
+ printf("set timeout %s %d\n", opt, seconds);
+
+ return (0);
+}
+
+int
+pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
+{
+ struct pfioc_tm pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.timeout = timeout;
+ pt.seconds = seconds;
+ if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
+ warnx("DIOCSETTIMEOUT");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_optimization(struct pfctl *pf, const char *opt)
+{
+ const struct pf_hint *hint;
+ int i, r;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ for (i = 0; pf_hints[i].name; i++)
+ if (strcasecmp(opt, pf_hints[i].name) == 0)
+ break;
+
+ hint = pf_hints[i].hint;
+ if (hint == NULL) {
+ warnx("invalid state timeouts optimization");
+ return (1);
+ }
+
+ for (i = 0; hint[i].name; i++)
+ if ((r = pfctl_set_timeout(pf, hint[i].name,
+ hint[i].timeout, 1)))
+ return (r);
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set optimization %s\n", opt);
+
+ return (0);
+}
+
+int
+pfctl_set_logif(struct pfctl *pf, char *ifname)
+{
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ if (!strcmp(ifname, "none")) {
+ free(pf->ifname);
+ pf->ifname = NULL;
+ } else {
+ pf->ifname = strdup(ifname);
+ if (!pf->ifname)
+ errx(1, "pfctl_set_logif: strdup");
+ }
+ pf->ifname_set = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set loginterface %s\n", ifname);
+
+ return (0);
+}
+
+int
+pfctl_load_logif(struct pfctl *pf, char *ifname)
+{
+ struct pfioc_if pi;
+
+ memset(&pi, 0, sizeof(pi));
+ if (ifname && strlcpy(pi.ifname, ifname,
+ sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
+ warnx("pfctl_load_logif: strlcpy");
+ return (1);
+ }
+ if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
+ warnx("DIOCSETSTATUSIF");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ HTONL(hostid);
+
+ pf->hostid = hostid;
+ pf->hostid_set = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set hostid 0x%08x\n", ntohl(hostid));
+
+ return (0);
+}
+
+int
+pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
+ warnx("DIOCSETHOSTID");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_debug(struct pfctl *pf, char *d)
+{
+ u_int32_t level;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ if (!strcmp(d, "none"))
+ pf->debug = PF_DEBUG_NONE;
+ else if (!strcmp(d, "urgent"))
+ pf->debug = PF_DEBUG_URGENT;
+ else if (!strcmp(d, "misc"))
+ pf->debug = PF_DEBUG_MISC;
+ else if (!strcmp(d, "loud"))
+ pf->debug = PF_DEBUG_NOISY;
+ else {
+ warnx("unknown debug level \"%s\"", d);
+ return (-1);
+ }
+
+ pf->debug_set = 1;
+ level = pf->debug;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ if (ioctl(dev, DIOCSETDEBUG, &level))
+ err(1, "DIOCSETDEBUG");
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set debug %s\n", d);
+
+ return (0);
+}
+
+int
+pfctl_load_debug(struct pfctl *pf, unsigned int level)
+{
+ if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
+ warnx("DIOCSETDEBUG");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
+{
+ struct pfioc_iface pi;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ bzero(&pi, sizeof(pi));
+
+ pi.pfiio_flags = flags;
+
+ if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
+ sizeof(pi.pfiio_name))
+ errx(1, "pfctl_set_interface_flags: strlcpy");
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (how == 0) {
+ if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
+ err(1, "DIOCCLRIFFLAG");
+ } else {
+ if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
+ err(1, "DIOCSETIFFLAG");
+ }
+ }
+ return (0);
+}
+
+void
+pfctl_debug(int dev, u_int32_t level, int opts)
+{
+ if (ioctl(dev, DIOCSETDEBUG, &level))
+ err(1, "DIOCSETDEBUG");
+ if ((opts & PF_OPT_QUIET) == 0) {
+ fprintf(stderr, "debug level set to '");
+ switch (level) {
+ case PF_DEBUG_NONE:
+ fprintf(stderr, "none");
+ break;
+ case PF_DEBUG_URGENT:
+ fprintf(stderr, "urgent");
+ break;
+ case PF_DEBUG_MISC:
+ fprintf(stderr, "misc");
+ break;
+ case PF_DEBUG_NOISY:
+ fprintf(stderr, "loud");
+ break;
+ default:
+ fprintf(stderr, "<invalid>");
+ break;
+ }
+ fprintf(stderr, "'\n");
+ }
+}
+
+int
+pfctl_test_altqsupport(int dev, int opts)
+{
+ struct pfioc_altq pa;
+
+ if (ioctl(dev, DIOCGETALTQS, &pa)) {
+ if (errno == ENODEV) {
+ if (opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "No ALTQ support in kernel\n"
+ "ALTQ related functions disabled\n");
+ return (0);
+ } else
+ err(1, "DIOCGETALTQS");
+ }
+ return (1);
+}
+
+int
+pfctl_show_anchors(int dev, int opts, char *anchorname)
+{
+ struct pfioc_ruleset pr;
+ u_int32_t mnr, nr;
+
+ memset(&pr, 0, sizeof(pr));
+ memcpy(pr.path, anchorname, sizeof(pr.path));
+ if (ioctl(dev, DIOCGETRULESETS, &pr)) {
+ if (errno == EINVAL)
+ fprintf(stderr, "Anchor '%s' not found.\n",
+ anchorname);
+ else
+ err(1, "DIOCGETRULESETS");
+ return (-1);
+ }
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ char sub[MAXPATHLEN];
+
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULESET, &pr))
+ err(1, "DIOCGETRULESET");
+ if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
+ continue;
+ sub[0] = 0;
+ if (pr.path[0]) {
+ strlcat(sub, pr.path, sizeof(sub));
+ strlcat(sub, "/", sizeof(sub));
+ }
+ strlcat(sub, pr.name, sizeof(sub));
+ if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s\n", sub);
+ if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
+ return (-1);
+ }
+ return (0);
+}
+
+const char *
+pfctl_lookup_option(char *cmd, const char * const *list)
+{
+ if (cmd != NULL && *cmd)
+ for (; *list; list++)
+ if (!strncmp(cmd, *list, strlen(cmd)))
+ return (*list);
+ return (NULL);
+}
+
+#ifdef __rtems__
+static int main(int argc, char *argv[]);
+
+RTEMS_LINKER_RWSET(bsd_prog_pfctl, char);
+
+int
+rtems_bsd_command_pfctl(int argc, char *argv[])
+{
+ int exit_code;
+ void *data_begin;
+ size_t data_size;
+
+ data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_pfctl);
+ data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_pfctl);
+
+ rtems_bsd_program_lock();
+ exit_code = rtems_bsd_program_call_main_with_data_restore("pfctl",
+ main, argc, argv, data_begin, data_size);
+ rtems_bsd_program_unlock();
+
+ return exit_code;
+}
+#endif /* __rtems__ */
+int
+main(int argc, char *argv[])
+{
+ int error = 0;
+ int ch;
+ int mode = O_RDONLY;
+ int opts = 0;
+ int optimize = PF_OPTIMIZE_BASIC;
+ char anchorname[MAXPATHLEN];
+ char *path;
+#ifdef __rtems__
+ struct getopt_data getopt_data;
+ memset(&getopt_data, 0, sizeof(getopt_data));
+#define optind getopt_data.optind
+#define optarg getopt_data.optarg
+#define opterr getopt_data.opterr
+#define optopt getopt_data.optopt
+#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data)
+#endif /* __rtems__ */
+
+ if (argc < 2)
+ usage();
+
+ while ((ch = getopt(argc, argv,
+ "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
+ switch (ch) {
+ case 'a':
+ anchoropt = optarg;
+ break;
+ case 'd':
+ opts |= PF_OPT_DISABLE;
+ mode = O_RDWR;
+ break;
+ case 'D':
+ if (pfctl_cmdline_symset(optarg) < 0)
+ warnx("could not parse macro definition %s",
+ optarg);
+ break;
+ case 'e':
+ opts |= PF_OPT_ENABLE;
+ mode = O_RDWR;
+ break;
+ case 'q':
+ opts |= PF_OPT_QUIET;
+ break;
+ case 'F':
+ clearopt = pfctl_lookup_option(optarg, clearopt_list);
+ if (clearopt == NULL) {
+ warnx("Unknown flush modifier '%s'", optarg);
+ usage();
+ }
+ mode = O_RDWR;
+ break;
+ case 'i':
+ ifaceopt = optarg;
+ break;
+ case 'k':
+ if (state_killers >= 2) {
+ warnx("can only specify -k twice");
+ usage();
+ /* NOTREACHED */
+ }
+ state_kill[state_killers++] = optarg;
+ mode = O_RDWR;
+ break;
+ case 'K':
+ if (src_node_killers >= 2) {
+ warnx("can only specify -K twice");
+ usage();
+ /* NOTREACHED */
+ }
+ src_node_kill[src_node_killers++] = optarg;
+ mode = O_RDWR;
+ break;
+ case 'm':
+ opts |= PF_OPT_MERGE;
+ break;
+ case 'n':
+ opts |= PF_OPT_NOACTION;
+ break;
+ case 'N':
+ loadopt |= PFCTL_FLAG_NAT;
+ break;
+ case 'r':
+ opts |= PF_OPT_USEDNS;
+ break;
+ case 'f':
+ rulesopt = optarg;
+ mode = O_RDWR;
+ break;
+ case 'g':
+ opts |= PF_OPT_DEBUG;
+ break;
+ case 'A':
+ loadopt |= PFCTL_FLAG_ALTQ;
+ break;
+ case 'R':
+ loadopt |= PFCTL_FLAG_FILTER;
+ break;
+ case 'o':
+ optiopt = pfctl_lookup_option(optarg, optiopt_list);
+ if (optiopt == NULL) {
+ warnx("Unknown optimization '%s'", optarg);
+ usage();
+ }
+ opts |= PF_OPT_OPTIMIZE;
+ break;
+ case 'O':
+ loadopt |= PFCTL_FLAG_OPTION;
+ break;
+ case 'p':
+ pf_device = optarg;
+ break;
+ case 'P':
+ opts |= PF_OPT_NUMERIC;
+ break;
+ case 's':
+ showopt = pfctl_lookup_option(optarg, showopt_list);
+ if (showopt == NULL) {
+ warnx("Unknown show modifier '%s'", optarg);
+ usage();
+ }
+ break;
+ case 't':
+ tableopt = optarg;
+ break;
+ case 'T':
+ tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
+ if (tblcmdopt == NULL) {
+ warnx("Unknown table command '%s'", optarg);
+ usage();
+ }
+ break;
+ case 'v':
+ if (opts & PF_OPT_VERBOSE)
+ opts |= PF_OPT_VERBOSE2;
+ opts |= PF_OPT_VERBOSE;
+ break;
+ case 'x':
+ debugopt = pfctl_lookup_option(optarg, debugopt_list);
+ if (debugopt == NULL) {
+ warnx("Unknown debug level '%s'", optarg);
+ usage();
+ }
+ mode = O_RDWR;
+ break;
+ case 'z':
+ opts |= PF_OPT_CLRRULECTRS;
+ mode = O_RDWR;
+ break;
+ case 'h':
+ /* FALLTHROUGH */
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ if (tblcmdopt != NULL) {
+ argc -= optind;
+ argv += optind;
+ ch = *tblcmdopt;
+ if (ch == 'l') {
+ loadopt |= PFCTL_FLAG_TABLE;
+ tblcmdopt = NULL;
+ } else
+ mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
+ } else if (argc != optind) {
+ warnx("unknown command line argument: %s ...", argv[optind]);
+ usage();
+ /* NOTREACHED */
+ }
+ if (loadopt == 0)
+ loadopt = ~0;
+
+ if ((path = calloc(1, MAXPATHLEN)) == NULL)
+ errx(1, "pfctl: calloc");
+ memset(anchorname, 0, sizeof(anchorname));
+ if (anchoropt != NULL) {
+ int len = strlen(anchoropt);
+
+ if (anchoropt[len - 1] == '*') {
+ if (len >= 2 && anchoropt[len - 2] == '/')
+ anchoropt[len - 2] = '\0';
+ else
+ anchoropt[len - 1] = '\0';
+ opts |= PF_OPT_RECURSE;
+ }
+ if (strlcpy(anchorname, anchoropt,
+ sizeof(anchorname)) >= sizeof(anchorname))
+ errx(1, "anchor name '%s' too long",
+ anchoropt);
+ loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
+ }
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ dev = open(pf_device, mode);
+ if (dev == -1)
+ err(1, "%s", pf_device);
+ altqsupport = pfctl_test_altqsupport(dev, opts);
+ } else {
+ dev = open(pf_device, O_RDONLY);
+ if (dev >= 0)
+ opts |= PF_OPT_DUMMYACTION;
+ /* turn off options */
+ opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
+ clearopt = showopt = debugopt = NULL;
+#if !defined(ENABLE_ALTQ)
+ altqsupport = 0;
+#else
+ altqsupport = 1;
+#endif
+ }
+
+ if (opts & PF_OPT_DISABLE)
+ if (pfctl_disable(dev, opts))
+ error = 1;
+
+ if (showopt != NULL) {
+ switch (*showopt) {
+ case 'A':
+ pfctl_show_anchors(dev, opts, anchorname);
+ break;
+ case 'r':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
+ anchorname, 0);
+ break;
+ case 'l':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
+ anchorname, 0);
+ break;
+ case 'n':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_nat(dev, opts, anchorname);
+ break;
+ case 'q':
+ pfctl_show_altq(dev, ifaceopt, opts,
+ opts & PF_OPT_VERBOSE2);
+ break;
+ case 's':
+ pfctl_show_states(dev, ifaceopt, opts);
+ break;
+ case 'S':
+ pfctl_show_src_nodes(dev, opts);
+ break;
+ case 'i':
+ pfctl_show_status(dev, opts);
+ break;
+ case 't':
+ pfctl_show_timeouts(dev, opts);
+ break;
+ case 'm':
+ pfctl_show_limits(dev, opts);
+ break;
+ case 'a':
+ opts |= PF_OPT_SHOWALL;
+ pfctl_load_fingerprints(dev, opts);
+
+ pfctl_show_nat(dev, opts, anchorname);
+ pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
+ pfctl_show_altq(dev, ifaceopt, opts, 0);
+ pfctl_show_states(dev, ifaceopt, opts);
+ pfctl_show_src_nodes(dev, opts);
+ pfctl_show_status(dev, opts);
+ pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
+ pfctl_show_timeouts(dev, opts);
+ pfctl_show_limits(dev, opts);
+ pfctl_show_tables(anchorname, opts);
+ pfctl_show_fingerprints(opts);
+ break;
+ case 'T':
+ pfctl_show_tables(anchorname, opts);
+ break;
+ case 'o':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_fingerprints(opts);
+ break;
+ case 'I':
+ pfctl_show_ifaces(ifaceopt, opts);
+ break;
+ }
+ }
+
+ if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
+ anchorname, 0);
+
+ if (clearopt != NULL) {
+ if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
+ errx(1, "anchor names beginning with '_' cannot "
+ "be modified from the command line");
+
+ switch (*clearopt) {
+ case 'r':
+ pfctl_clear_rules(dev, opts, anchorname);
+ break;
+ case 'n':
+ pfctl_clear_nat(dev, opts, anchorname);
+ break;
+ case 'q':
+ pfctl_clear_altq(dev, opts);
+ break;
+ case 's':
+ pfctl_clear_states(dev, ifaceopt, opts);
+ break;
+ case 'S':
+ pfctl_clear_src_nodes(dev, opts);
+ break;
+ case 'i':
+ pfctl_clear_stats(dev, opts);
+ break;
+ case 'a':
+ pfctl_clear_rules(dev, opts, anchorname);
+ pfctl_clear_nat(dev, opts, anchorname);
+ pfctl_clear_tables(anchorname, opts);
+ if (!*anchorname) {
+ pfctl_clear_altq(dev, opts);
+ pfctl_clear_states(dev, ifaceopt, opts);
+ pfctl_clear_src_nodes(dev, opts);
+ pfctl_clear_stats(dev, opts);
+ pfctl_clear_fingerprints(dev, opts);
+ pfctl_clear_interface_flags(dev, opts);
+ }
+ break;
+ case 'o':
+ pfctl_clear_fingerprints(dev, opts);
+ break;
+ case 'T':
+ pfctl_clear_tables(anchorname, opts);
+ break;
+ }
+ }
+ if (state_killers) {
+ if (!strcmp(state_kill[0], "label"))
+ pfctl_label_kill_states(dev, ifaceopt, opts);
+ else if (!strcmp(state_kill[0], "id"))
+ pfctl_id_kill_states(dev, ifaceopt, opts);
+ else
+ pfctl_net_kill_states(dev, ifaceopt, opts);
+ }
+
+ if (src_node_killers)
+ pfctl_kill_src_nodes(dev, ifaceopt, opts);
+
+ if (tblcmdopt != NULL) {
+ error = pfctl_command_tables(argc, argv, tableopt,
+ tblcmdopt, rulesopt, anchorname, opts);
+ rulesopt = NULL;
+ }
+ if (optiopt != NULL) {
+ switch (*optiopt) {
+ case 'n':
+ optimize = 0;
+ break;
+ case 'b':
+ optimize |= PF_OPTIMIZE_BASIC;
+ break;
+ case 'o':
+ case 'p':
+ optimize |= PF_OPTIMIZE_PROFILE;
+ break;
+ }
+ }
+
+ if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
+ !anchorname[0])
+ if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
+ error = 1;
+
+ if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
+ !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
+ if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
+ error = 1;
+
+ if (rulesopt != NULL) {
+ if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
+ errx(1, "anchor names beginning with '_' cannot "
+ "be modified from the command line");
+ if (pfctl_rules(dev, rulesopt, opts, optimize,
+ anchorname, NULL))
+ error = 1;
+ else if (!(opts & PF_OPT_NOACTION) &&
+ (loadopt & PFCTL_FLAG_TABLE))
+ warn_namespace_collision(NULL);
+ }
+
+ if (opts & PF_OPT_ENABLE)
+ if (pfctl_enable(dev, opts))
+ error = 1;
+
+ if (debugopt != NULL) {
+ switch (*debugopt) {
+ case 'n':
+ pfctl_debug(dev, PF_DEBUG_NONE, opts);
+ break;
+ case 'u':
+ pfctl_debug(dev, PF_DEBUG_URGENT, opts);
+ break;
+ case 'm':
+ pfctl_debug(dev, PF_DEBUG_MISC, opts);
+ break;
+ case 'l':
+ pfctl_debug(dev, PF_DEBUG_NOISY, opts);
+ break;
+ }
+ }
+
+ exit(error);
+}
diff --git a/freebsd/sbin/pfctl/pfctl.h b/freebsd/sbin/pfctl/pfctl.h
new file mode 100644
index 00000000..2c69bc20
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl.h
@@ -0,0 +1,130 @@
+/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PFCTL_H_
+#define _PFCTL_H_
+
+enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING };
+
+enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
+ PFRB_IFACES, PFRB_TRANS, PFRB_MAX };
+struct pfr_buffer {
+ int pfrb_type; /* type of content, see enum above */
+ int pfrb_size; /* number of objects in buffer */
+ int pfrb_msize; /* maximum number of objects in buffer */
+ void *pfrb_caddr; /* malloc'ated memory area */
+};
+#define PFRB_FOREACH(var, buf) \
+ for ((var) = pfr_buf_next((buf), NULL); \
+ (var) != NULL; \
+ (var) = pfr_buf_next((buf), (var)))
+
+int pfr_get_fd(void);
+int pfr_clr_tables(struct pfr_table *, int *, int);
+int pfr_add_tables(struct pfr_table *, int, int *, int);
+int pfr_del_tables(struct pfr_table *, int, int *, int);
+int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int);
+int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int);
+int pfr_clr_tstats(struct pfr_table *, int, int *, int);
+int pfr_clr_addrs(struct pfr_table *, int *, int);
+int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
+ int *, int *, int *, int);
+int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
+int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
+int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
+ int *, int, int);
+void pfr_buf_clear(struct pfr_buffer *);
+int pfr_buf_add(struct pfr_buffer *, const void *);
+void *pfr_buf_next(struct pfr_buffer *, const void *);
+int pfr_buf_grow(struct pfr_buffer *, int);
+int pfr_buf_load(struct pfr_buffer *, char *, int,
+ int (*)(struct pfr_buffer *, char *, int));
+char *pfr_strerror(int);
+int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
+int pfi_clr_istats(const char *, int *, int);
+
+void pfctl_print_title(char *);
+int pfctl_clear_tables(const char *, int);
+int pfctl_show_tables(const char *, int);
+int pfctl_command_tables(int, char *[], char *, const char *, char *,
+ const char *, int);
+int pfctl_show_altq(int, const char *, int, int);
+void warn_namespace_collision(const char *);
+int pfctl_show_ifaces(const char *, int);
+FILE *pfctl_fopen(const char *, const char *);
+
+#ifdef __FreeBSD__
+extern int altqsupport;
+extern int dummynetsupport;
+#define HTONL(x) (x) = htonl((__uint32_t)(x))
+#endif
+
+#ifndef DEFAULT_PRIORITY
+#define DEFAULT_PRIORITY 1
+#endif
+
+#ifndef DEFAULT_QLIMIT
+#define DEFAULT_QLIMIT 50
+#endif
+
+/*
+ * generalized service curve used for admission control
+ */
+struct segment {
+ LIST_ENTRY(segment) _next;
+ double x, y, d, m;
+};
+
+extern int loadopt;
+
+int check_commit_altq(int, int);
+void pfaltq_store(struct pf_altq *);
+struct pf_altq *pfaltq_lookup(const char *);
+char *rate2str(double);
+
+void print_addr(struct pf_addr_wrap *, sa_family_t, int);
+void print_host(struct pf_addr *, u_int16_t p, sa_family_t, int);
+void print_seq(struct pfsync_state_peer *);
+void print_state(struct pfsync_state *, int);
+int unmask(struct pf_addr *, sa_family_t);
+
+int pfctl_cmdline_symset(char *);
+int pfctl_add_trans(struct pfr_buffer *, int, const char *);
+u_int32_t
+ pfctl_get_ticket(struct pfr_buffer *, int, const char *);
+int pfctl_trans(int, struct pfr_buffer *, u_long, int);
+
+#endif /* _PFCTL_H_ */
diff --git a/freebsd/sbin/pfctl/pfctl_altq.c b/freebsd/sbin/pfctl/pfctl_altq.c
new file mode 100644
index 00000000..145d60ae
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_altq.c
@@ -0,0 +1,1536 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2002
+ * Sony Computer Science Laboratories Inc.
+ * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_altq-data.h"
+#endif /* __rtems__ */
+
+#define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0))
+
+static TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs);
+static LIST_HEAD(gen_sc, segment) rtsc, lssc;
+
+struct pf_altq *qname_to_pfaltq(const char *, const char *);
+u_int32_t qname_to_qid(const char *);
+
+static int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *);
+static int cbq_compute_idletime(struct pfctl *, struct pf_altq *);
+static int check_commit_cbq(int, int, struct pf_altq *);
+static int print_cbq_opts(const struct pf_altq *);
+
+static int print_codel_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+
+static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *);
+static int check_commit_priq(int, int, struct pf_altq *);
+static int print_priq_opts(const struct pf_altq *);
+
+static int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *);
+static int check_commit_hfsc(int, int, struct pf_altq *);
+static int print_hfsc_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+
+static int eval_pfqueue_fairq(struct pfctl *, struct pf_altq *);
+static int print_fairq_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+static int check_commit_fairq(int, int, struct pf_altq *);
+
+static void gsc_add_sc(struct gen_sc *, struct service_curve *);
+static int is_gsc_under_sc(struct gen_sc *,
+ struct service_curve *);
+static void gsc_destroy(struct gen_sc *);
+static struct segment *gsc_getentry(struct gen_sc *, double);
+static int gsc_add_seg(struct gen_sc *, double, double, double,
+ double);
+static double sc_x2y(struct service_curve *, double);
+
+#ifdef __FreeBSD__
+u_int32_t getifspeed(int, char *);
+#else
+u_int32_t getifspeed(char *);
+#endif
+u_long getifmtu(char *);
+int eval_queue_opts(struct pf_altq *, struct node_queue_opt *,
+ u_int32_t);
+u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t);
+void print_hfsc_sc(const char *, u_int, u_int, u_int,
+ const struct node_hfsc_sc *);
+void print_fairq_sc(const char *, u_int, u_int, u_int,
+ const struct node_fairq_sc *);
+
+void
+pfaltq_store(struct pf_altq *a)
+{
+ struct pf_altq *altq;
+
+ if ((altq = malloc(sizeof(*altq))) == NULL)
+ err(1, "malloc");
+ memcpy(altq, a, sizeof(struct pf_altq));
+ TAILQ_INSERT_TAIL(&altqs, altq, entries);
+}
+
+struct pf_altq *
+pfaltq_lookup(const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
+ altq->qname[0] == 0)
+ return (altq);
+ }
+ return (NULL);
+}
+
+struct pf_altq *
+qname_to_pfaltq(const char *qname, const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
+ strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
+ return (altq);
+ }
+ return (NULL);
+}
+
+u_int32_t
+qname_to_qid(const char *qname)
+{
+ struct pf_altq *altq;
+
+ /*
+ * We guarantee that same named queues on different interfaces
+ * have the same qid, so we do NOT need to limit matching on
+ * one interface!
+ */
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
+ return (altq->qid);
+ }
+ return (0);
+}
+
+void
+print_altq(const struct pf_altq *a, unsigned int level,
+ struct node_queue_bw *bw, struct node_queue_opt *qopts)
+{
+ if (a->qname[0] != 0) {
+ print_queue(a, level, bw, 1, qopts);
+ return;
+ }
+
+#ifdef __FreeBSD__
+ if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
+ printf("INACTIVE ");
+#endif
+
+ printf("altq on %s ", a->ifname);
+
+ switch (a->scheduler) {
+ case ALTQT_CBQ:
+ if (!print_cbq_opts(a))
+ printf("cbq ");
+ break;
+ case ALTQT_PRIQ:
+ if (!print_priq_opts(a))
+ printf("priq ");
+ break;
+ case ALTQT_HFSC:
+ if (!print_hfsc_opts(a, qopts))
+ printf("hfsc ");
+ break;
+ case ALTQT_FAIRQ:
+ if (!print_fairq_opts(a, qopts))
+ printf("fairq ");
+ break;
+ case ALTQT_CODEL:
+ if (!print_codel_opts(a, qopts))
+ printf("codel ");
+ break;
+ }
+
+ if (bw != NULL && bw->bw_percent > 0) {
+ if (bw->bw_percent < 100)
+ printf("bandwidth %u%% ", bw->bw_percent);
+ } else
+ printf("bandwidth %s ", rate2str((double)a->ifbandwidth));
+
+ if (a->qlimit != DEFAULT_QLIMIT)
+ printf("qlimit %u ", a->qlimit);
+ printf("tbrsize %u ", a->tbrsize);
+}
+
+void
+print_queue(const struct pf_altq *a, unsigned int level,
+ struct node_queue_bw *bw, int print_interface,
+ struct node_queue_opt *qopts)
+{
+ unsigned int i;
+
+#ifdef __FreeBSD__
+ if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
+ printf("INACTIVE ");
+#endif
+ printf("queue ");
+ for (i = 0; i < level; ++i)
+ printf(" ");
+ printf("%s ", a->qname);
+ if (print_interface)
+ printf("on %s ", a->ifname);
+ if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC ||
+ a->scheduler == ALTQT_FAIRQ) {
+ if (bw != NULL && bw->bw_percent > 0) {
+ if (bw->bw_percent < 100)
+ printf("bandwidth %u%% ", bw->bw_percent);
+ } else
+ printf("bandwidth %s ", rate2str((double)a->bandwidth));
+ }
+ if (a->priority != DEFAULT_PRIORITY)
+ printf("priority %u ", a->priority);
+ if (a->qlimit != DEFAULT_QLIMIT)
+ printf("qlimit %u ", a->qlimit);
+ switch (a->scheduler) {
+ case ALTQT_CBQ:
+ print_cbq_opts(a);
+ break;
+ case ALTQT_PRIQ:
+ print_priq_opts(a);
+ break;
+ case ALTQT_HFSC:
+ print_hfsc_opts(a, qopts);
+ break;
+ case ALTQT_FAIRQ:
+ print_fairq_opts(a, qopts);
+ break;
+ }
+}
+
+/*
+ * eval_pfaltq computes the discipline parameters.
+ */
+int
+eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
+ struct node_queue_opt *opts)
+{
+ u_int rate, size, errors = 0;
+
+ if (bw->bw_absolute > 0)
+ pa->ifbandwidth = bw->bw_absolute;
+ else
+#ifdef __FreeBSD__
+ if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) {
+#else
+ if ((rate = getifspeed(pa->ifname)) == 0) {
+#endif
+ fprintf(stderr, "interface %s does not know its bandwidth, "
+ "please specify an absolute bandwidth\n",
+ pa->ifname);
+ errors++;
+ } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
+ pa->ifbandwidth = rate;
+
+ errors += eval_queue_opts(pa, opts, pa->ifbandwidth);
+
+ /* if tbrsize is not specified, use heuristics */
+ if (pa->tbrsize == 0) {
+ rate = pa->ifbandwidth;
+ if (rate <= 1 * 1000 * 1000)
+ size = 1;
+ else if (rate <= 10 * 1000 * 1000)
+ size = 4;
+ else if (rate <= 200 * 1000 * 1000)
+ size = 8;
+ else
+ size = 24;
+ size = size * getifmtu(pa->ifname);
+ if (size > 0xffff)
+ size = 0xffff;
+ pa->tbrsize = size;
+ }
+ return (errors);
+}
+
+/*
+ * check_commit_altq does consistency check for each interface
+ */
+int
+check_commit_altq(int dev, int opts)
+{
+ struct pf_altq *altq;
+ int error = 0;
+
+ /* call the discipline check for each interface. */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (altq->qname[0] == 0) {
+ switch (altq->scheduler) {
+ case ALTQT_CBQ:
+ error = check_commit_cbq(dev, opts, altq);
+ break;
+ case ALTQT_PRIQ:
+ error = check_commit_priq(dev, opts, altq);
+ break;
+ case ALTQT_HFSC:
+ error = check_commit_hfsc(dev, opts, altq);
+ break;
+ case ALTQT_FAIRQ:
+ error = check_commit_fairq(dev, opts, altq);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return (error);
+}
+
+/*
+ * eval_pfqueue computes the queue parameters.
+ */
+int
+eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
+ struct node_queue_opt *opts)
+{
+ /* should be merged with expand_queue */
+ struct pf_altq *if_pa, *parent, *altq;
+ u_int32_t bwsum;
+ int error = 0;
+
+ /* find the corresponding interface and copy fields used by queues */
+ if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) {
+ fprintf(stderr, "altq not defined on %s\n", pa->ifname);
+ return (1);
+ }
+ pa->scheduler = if_pa->scheduler;
+ pa->ifbandwidth = if_pa->ifbandwidth;
+
+ if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) {
+ fprintf(stderr, "queue %s already exists on interface %s\n",
+ pa->qname, pa->ifname);
+ return (1);
+ }
+ pa->qid = qname_to_qid(pa->qname);
+
+ parent = NULL;
+ if (pa->parent[0] != 0) {
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL) {
+ fprintf(stderr, "parent %s not found for %s\n",
+ pa->parent, pa->qname);
+ return (1);
+ }
+ pa->parent_qid = parent->qid;
+ }
+ if (pa->qlimit == 0)
+ pa->qlimit = DEFAULT_QLIMIT;
+
+ if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC ||
+ pa->scheduler == ALTQT_FAIRQ) {
+ pa->bandwidth = eval_bwspec(bw,
+ parent == NULL ? 0 : parent->bandwidth);
+
+ if (pa->bandwidth > pa->ifbandwidth) {
+ fprintf(stderr, "bandwidth for %s higher than "
+ "interface\n", pa->qname);
+ return (1);
+ }
+ /* check the sum of the child bandwidth is under parent's */
+ if (parent != NULL) {
+ if (pa->bandwidth > parent->bandwidth) {
+ warnx("bandwidth for %s higher than parent",
+ pa->qname);
+ return (1);
+ }
+ bwsum = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname,
+ IFNAMSIZ) == 0 &&
+ altq->qname[0] != 0 &&
+ strncmp(altq->parent, pa->parent,
+ PF_QNAME_SIZE) == 0)
+ bwsum += altq->bandwidth;
+ }
+ bwsum += pa->bandwidth;
+ if (bwsum > parent->bandwidth) {
+ warnx("the sum of the child bandwidth higher"
+ " than parent \"%s\"", parent->qname);
+ }
+ }
+ }
+
+ if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth))
+ return (1);
+
+ switch (pa->scheduler) {
+ case ALTQT_CBQ:
+ error = eval_pfqueue_cbq(pf, pa);
+ break;
+ case ALTQT_PRIQ:
+ error = eval_pfqueue_priq(pf, pa);
+ break;
+ case ALTQT_HFSC:
+ error = eval_pfqueue_hfsc(pf, pa);
+ break;
+ case ALTQT_FAIRQ:
+ error = eval_pfqueue_fairq(pf, pa);
+ break;
+ default:
+ break;
+ }
+ return (error);
+}
+
+/*
+ * CBQ support functions
+ */
+#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */
+#define RM_NS_PER_SEC (1000000000)
+
+static int
+eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct cbq_opts *opts;
+ u_int ifmtu;
+
+ if (pa->priority >= CBQ_MAXPRI) {
+ warnx("priority out of range: max %d", CBQ_MAXPRI - 1);
+ return (-1);
+ }
+
+ ifmtu = getifmtu(pa->ifname);
+ opts = &pa->pq_u.cbq_opts;
+
+ if (opts->pktsize == 0) { /* use default */
+ opts->pktsize = ifmtu;
+ if (opts->pktsize > MCLBYTES) /* do what TCP does */
+ opts->pktsize &= ~MCLBYTES;
+ } else if (opts->pktsize > ifmtu)
+ opts->pktsize = ifmtu;
+ if (opts->maxpktsize == 0) /* use default */
+ opts->maxpktsize = ifmtu;
+ else if (opts->maxpktsize > ifmtu)
+ opts->pktsize = ifmtu;
+
+ if (opts->pktsize > opts->maxpktsize)
+ opts->pktsize = opts->maxpktsize;
+
+ if (pa->parent[0] == 0)
+ opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR);
+
+ cbq_compute_idletime(pf, pa);
+ return (0);
+}
+
+/*
+ * compute ns_per_byte, maxidle, minidle, and offtime
+ */
+static int
+cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct cbq_opts *opts;
+ double maxidle_s, maxidle, minidle;
+ double offtime, nsPerByte, ifnsPerByte, ptime, cptime;
+ double z, g, f, gton, gtom;
+ u_int minburst, maxburst;
+
+ opts = &pa->pq_u.cbq_opts;
+ ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8;
+ minburst = opts->minburst;
+ maxburst = opts->maxburst;
+
+ if (pa->bandwidth == 0)
+ f = 0.0001; /* small enough? */
+ else
+ f = ((double) pa->bandwidth / (double) pa->ifbandwidth);
+
+ nsPerByte = ifnsPerByte / f;
+ ptime = (double)opts->pktsize * ifnsPerByte;
+ cptime = ptime * (1.0 - f) / f;
+
+ if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) {
+ /*
+ * this causes integer overflow in kernel!
+ * (bandwidth < 6Kbps when max_pkt_size=1500)
+ */
+ if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0)
+ warnx("queue bandwidth must be larger than %s",
+ rate2str(ifnsPerByte * (double)opts->maxpktsize /
+ (double)INT_MAX * (double)pa->ifbandwidth));
+ fprintf(stderr, "cbq: queue %s is too slow!\n",
+ pa->qname);
+ nsPerByte = (double)(INT_MAX / opts->maxpktsize);
+ }
+
+ if (maxburst == 0) { /* use default */
+ if (cptime > 10.0 * 1000000)
+ maxburst = 4;
+ else
+ maxburst = 16;
+ }
+ if (minburst == 0) /* use default */
+ minburst = 2;
+ if (minburst > maxburst)
+ minburst = maxburst;
+
+ z = (double)(1 << RM_FILTER_GAIN);
+ g = (1.0 - 1.0 / z);
+ gton = pow(g, (double)maxburst);
+ gtom = pow(g, (double)(minburst-1));
+ maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton));
+ maxidle_s = (1.0 - g);
+ if (maxidle > maxidle_s)
+ maxidle = ptime * maxidle;
+ else
+ maxidle = ptime * maxidle_s;
+ offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
+ minidle = -((double)opts->maxpktsize * (double)nsPerByte);
+
+ /* scale parameters */
+ maxidle = ((maxidle * 8.0) / nsPerByte) *
+ pow(2.0, (double)RM_FILTER_GAIN);
+ offtime = (offtime * 8.0) / nsPerByte *
+ pow(2.0, (double)RM_FILTER_GAIN);
+ minidle = ((minidle * 8.0) / nsPerByte) *
+ pow(2.0, (double)RM_FILTER_GAIN);
+
+ maxidle = maxidle / 1000.0;
+ offtime = offtime / 1000.0;
+ minidle = minidle / 1000.0;
+
+ opts->minburst = minburst;
+ opts->maxburst = maxburst;
+ opts->ns_per_byte = (u_int)nsPerByte;
+ opts->maxidle = (u_int)fabs(maxidle);
+ opts->minidle = (int)minidle;
+ opts->offtime = (u_int)fabs(offtime);
+
+ return (0);
+}
+
+static int
+check_commit_cbq(int dev, int opts, struct pf_altq *pa)
+{
+ struct pf_altq *altq;
+ int root_class, default_class;
+ int error = 0;
+
+ /*
+ * check if cbq has one root queue and one default queue
+ * for this interface
+ */
+ root_class = default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS)
+ root_class++;
+ if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS)
+ default_class++;
+ }
+ if (root_class != 1) {
+ warnx("should have one root queue on %s", pa->ifname);
+ error++;
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ error++;
+ }
+ return (error);
+}
+
+static int
+print_cbq_opts(const struct pf_altq *a)
+{
+ const struct cbq_opts *opts;
+
+ opts = &a->pq_u.cbq_opts;
+ if (opts->flags) {
+ printf("cbq(");
+ if (opts->flags & CBQCLF_RED)
+ printf(" red");
+ if (opts->flags & CBQCLF_ECN)
+ printf(" ecn");
+ if (opts->flags & CBQCLF_RIO)
+ printf(" rio");
+ if (opts->flags & CBQCLF_CODEL)
+ printf(" codel");
+ if (opts->flags & CBQCLF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & CBQCLF_FLOWVALVE)
+ printf(" flowvalve");
+ if (opts->flags & CBQCLF_BORROW)
+ printf(" borrow");
+ if (opts->flags & CBQCLF_WRR)
+ printf(" wrr");
+ if (opts->flags & CBQCLF_EFFICIENT)
+ printf(" efficient");
+ if (opts->flags & CBQCLF_ROOTCLASS)
+ printf(" root");
+ if (opts->flags & CBQCLF_DEFCLASS)
+ printf(" default");
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * PRIQ support functions
+ */
+static int
+eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct pf_altq *altq;
+
+ if (pa->priority >= PRIQ_MAXPRI) {
+ warnx("priority out of range: max %d", PRIQ_MAXPRI - 1);
+ return (-1);
+ }
+ /* the priority should be unique for the interface */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 &&
+ altq->qname[0] != 0 && altq->priority == pa->priority) {
+ warnx("%s and %s have the same priority",
+ altq->qname, pa->qname);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+check_commit_priq(int dev, int opts, struct pf_altq *pa)
+{
+ struct pf_altq *altq;
+ int default_class;
+ int error = 0;
+
+ /*
+ * check if priq has one default class for this interface
+ */
+ default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS)
+ default_class++;
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ error++;
+ }
+ return (error);
+}
+
+static int
+print_priq_opts(const struct pf_altq *a)
+{
+ const struct priq_opts *opts;
+
+ opts = &a->pq_u.priq_opts;
+
+ if (opts->flags) {
+ printf("priq(");
+ if (opts->flags & PRCF_RED)
+ printf(" red");
+ if (opts->flags & PRCF_ECN)
+ printf(" ecn");
+ if (opts->flags & PRCF_RIO)
+ printf(" rio");
+ if (opts->flags & PRCF_CODEL)
+ printf(" codel");
+ if (opts->flags & PRCF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & PRCF_DEFAULTCLASS)
+ printf(" default");
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * HFSC support functions
+ */
+static int
+eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *parent;
+ struct hfsc_opts *opts;
+ struct service_curve sc;
+
+ opts = &pa->pq_u.hfsc_opts;
+
+ if (pa->parent[0] == 0) {
+ /* root queue */
+ opts->lssc_m1 = pa->ifbandwidth;
+ opts->lssc_m2 = pa->ifbandwidth;
+ opts->lssc_d = 0;
+ return (0);
+ }
+
+ LIST_INIT(&rtsc);
+ LIST_INIT(&lssc);
+
+ /* if link_share is not specified, use bandwidth */
+ if (opts->lssc_m2 == 0)
+ opts->lssc_m2 = pa->bandwidth;
+
+ if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) ||
+ (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) ||
+ (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) {
+ warnx("m2 is zero for %s", pa->qname);
+ return (-1);
+ }
+
+ if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
+ (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) ||
+ (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) {
+ warnx("m1 must be zero for convex curve: %s", pa->qname);
+ return (-1);
+ }
+
+ /*
+ * admission control:
+ * for the real-time service curve, the sum of the service curves
+ * should not exceed 80% of the interface bandwidth. 20% is reserved
+ * not to over-commit the actual interface bandwidth.
+ * for the linkshare service curve, the sum of the child service
+ * curve should not exceed the parent service curve.
+ * for the upper-limit service curve, the assigned bandwidth should
+ * be smaller than the interface bandwidth, and the upper-limit should
+ * be larger than the real-time service curve when both are defined.
+ */
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found for %s", pa->parent, pa->qname);
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+
+ /* if the class has a real-time service curve, add it. */
+ if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) {
+ sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1;
+ sc.d = altq->pq_u.hfsc_opts.rtsc_d;
+ sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2;
+ gsc_add_sc(&rtsc, &sc);
+ }
+
+ if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
+ continue;
+
+ /* if the class has a linkshare service curve, add it. */
+ if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) {
+ sc.m1 = altq->pq_u.hfsc_opts.lssc_m1;
+ sc.d = altq->pq_u.hfsc_opts.lssc_d;
+ sc.m2 = altq->pq_u.hfsc_opts.lssc_m2;
+ gsc_add_sc(&lssc, &sc);
+ }
+ }
+
+ /* check the real-time service curve. reserve 20% of interface bw */
+ if (opts->rtsc_m2 != 0) {
+ /* add this queue to the sum */
+ sc.m1 = opts->rtsc_m1;
+ sc.d = opts->rtsc_d;
+ sc.m2 = opts->rtsc_m2;
+ gsc_add_sc(&rtsc, &sc);
+ /* compare the sum with 80% of the interface */
+ sc.m1 = 0;
+ sc.d = 0;
+ sc.m2 = pa->ifbandwidth / 100 * 80;
+ if (!is_gsc_under_sc(&rtsc, &sc)) {
+ warnx("real-time sc exceeds 80%% of the interface "
+ "bandwidth (%s)", rate2str((double)sc.m2));
+ goto err_ret;
+ }
+ }
+
+ /* check the linkshare service curve. */
+ if (opts->lssc_m2 != 0) {
+ /* add this queue to the child sum */
+ sc.m1 = opts->lssc_m1;
+ sc.d = opts->lssc_d;
+ sc.m2 = opts->lssc_m2;
+ gsc_add_sc(&lssc, &sc);
+ /* compare the sum of the children with parent's sc */
+ sc.m1 = parent->pq_u.hfsc_opts.lssc_m1;
+ sc.d = parent->pq_u.hfsc_opts.lssc_d;
+ sc.m2 = parent->pq_u.hfsc_opts.lssc_m2;
+ if (!is_gsc_under_sc(&lssc, &sc)) {
+ warnx("linkshare sc exceeds parent's sc");
+ goto err_ret;
+ }
+ }
+
+ /* check the upper-limit service curve. */
+ if (opts->ulsc_m2 != 0) {
+ if (opts->ulsc_m1 > pa->ifbandwidth ||
+ opts->ulsc_m2 > pa->ifbandwidth) {
+ warnx("upper-limit larger than interface bandwidth");
+ goto err_ret;
+ }
+ if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) {
+ warnx("upper-limit sc smaller than real-time sc");
+ goto err_ret;
+ }
+ }
+
+ gsc_destroy(&rtsc);
+ gsc_destroy(&lssc);
+
+ return (0);
+
+err_ret:
+ gsc_destroy(&rtsc);
+ gsc_destroy(&lssc);
+ return (-1);
+}
+
+/*
+ * FAIRQ support functions
+ */
+static int
+eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *parent;
+ struct fairq_opts *opts;
+ struct service_curve sc;
+
+ opts = &pa->pq_u.fairq_opts;
+
+ if (pa->parent[0] == 0) {
+ /* root queue */
+ opts->lssc_m1 = pa->ifbandwidth;
+ opts->lssc_m2 = pa->ifbandwidth;
+ opts->lssc_d = 0;
+ return (0);
+ }
+
+ LIST_INIT(&lssc);
+
+ /* if link_share is not specified, use bandwidth */
+ if (opts->lssc_m2 == 0)
+ opts->lssc_m2 = pa->bandwidth;
+
+ /*
+ * admission control:
+ * for the real-time service curve, the sum of the service curves
+ * should not exceed 80% of the interface bandwidth. 20% is reserved
+ * not to over-commit the actual interface bandwidth.
+ * for the link-sharing service curve, the sum of the child service
+ * curve should not exceed the parent service curve.
+ * for the upper-limit service curve, the assigned bandwidth should
+ * be smaller than the interface bandwidth, and the upper-limit should
+ * be larger than the real-time service curve when both are defined.
+ */
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found for %s", pa->parent, pa->qname);
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+
+ if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
+ continue;
+
+ /* if the class has a link-sharing service curve, add it. */
+ if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) {
+ sc.m1 = altq->pq_u.fairq_opts.lssc_m1;
+ sc.d = altq->pq_u.fairq_opts.lssc_d;
+ sc.m2 = altq->pq_u.fairq_opts.lssc_m2;
+ gsc_add_sc(&lssc, &sc);
+ }
+ }
+
+ /* check the link-sharing service curve. */
+ if (opts->lssc_m2 != 0) {
+ sc.m1 = parent->pq_u.fairq_opts.lssc_m1;
+ sc.d = parent->pq_u.fairq_opts.lssc_d;
+ sc.m2 = parent->pq_u.fairq_opts.lssc_m2;
+ if (!is_gsc_under_sc(&lssc, &sc)) {
+ warnx("link-sharing sc exceeds parent's sc");
+ goto err_ret;
+ }
+ }
+
+ gsc_destroy(&lssc);
+
+ return (0);
+
+err_ret:
+ gsc_destroy(&lssc);
+ return (-1);
+}
+
+static int
+check_commit_hfsc(int dev, int opts, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *def = NULL;
+ int default_class;
+ int error = 0;
+
+ /* check if hfsc has one default queue for this interface */
+ default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->parent[0] == 0) /* dummy root */
+ continue;
+ if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) {
+ default_class++;
+ def = altq;
+ }
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ return (1);
+ }
+ /* make sure the default queue is a leaf */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
+ warnx("default queue is not a leaf");
+ error++;
+ }
+ }
+ return (error);
+}
+
+static int
+check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *def = NULL;
+ int default_class;
+ int error = 0;
+
+ /* check if fairq has one default queue for this interface */
+ default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) {
+ default_class++;
+ def = altq;
+ }
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ return (1);
+ }
+ /* make sure the default queue is a leaf */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
+ warnx("default queue is not a leaf");
+ error++;
+ }
+ }
+ return (error);
+}
+
+static int
+print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct hfsc_opts *opts;
+ const struct node_hfsc_sc *rtsc, *lssc, *ulsc;
+
+ opts = &a->pq_u.hfsc_opts;
+ if (qopts == NULL)
+ rtsc = lssc = ulsc = NULL;
+ else {
+ rtsc = &qopts->data.hfsc_opts.realtime;
+ lssc = &qopts->data.hfsc_opts.linkshare;
+ ulsc = &qopts->data.hfsc_opts.upperlimit;
+ }
+
+ if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 ||
+ (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))) {
+ printf("hfsc(");
+ if (opts->flags & HFCF_RED)
+ printf(" red");
+ if (opts->flags & HFCF_ECN)
+ printf(" ecn");
+ if (opts->flags & HFCF_RIO)
+ printf(" rio");
+ if (opts->flags & HFCF_CODEL)
+ printf(" codel");
+ if (opts->flags & HFCF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & HFCF_DEFAULTCLASS)
+ printf(" default");
+ if (opts->rtsc_m2 != 0)
+ print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d,
+ opts->rtsc_m2, rtsc);
+ if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))
+ print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d,
+ opts->lssc_m2, lssc);
+ if (opts->ulsc_m2 != 0)
+ print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d,
+ opts->ulsc_m2, ulsc);
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+static int
+print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct codel_opts *opts;
+
+ opts = &a->pq_u.codel_opts;
+ if (opts->target || opts->interval || opts->ecn) {
+ printf("codel(");
+ if (opts->target)
+ printf(" target %d", opts->target);
+ if (opts->interval)
+ printf(" interval %d", opts->interval);
+ if (opts->ecn)
+ printf("ecn");
+ printf(" ) ");
+
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct fairq_opts *opts;
+ const struct node_fairq_sc *loc_lssc;
+
+ opts = &a->pq_u.fairq_opts;
+ if (qopts == NULL)
+ loc_lssc = NULL;
+ else
+ loc_lssc = &qopts->data.fairq_opts.linkshare;
+
+ if (opts->flags ||
+ (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))) {
+ printf("fairq(");
+ if (opts->flags & FARF_RED)
+ printf(" red");
+ if (opts->flags & FARF_ECN)
+ printf(" ecn");
+ if (opts->flags & FARF_RIO)
+ printf(" rio");
+ if (opts->flags & FARF_CODEL)
+ printf(" codel");
+ if (opts->flags & FARF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & FARF_DEFAULTCLASS)
+ printf(" default");
+ if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))
+ print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d,
+ opts->lssc_m2, loc_lssc);
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * admission control using generalized service curve
+ */
+
+/* add a new service curve to a generalized service curve */
+static void
+gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc)
+{
+ if (is_sc_null(sc))
+ return;
+ if (sc->d != 0)
+ gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1);
+ gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2);
+}
+
+/*
+ * check whether all points of a generalized service curve have
+ * their y-coordinates no larger than a given two-piece linear
+ * service curve.
+ */
+static int
+is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc)
+{
+ struct segment *s, *last, *end;
+ double y;
+
+ if (is_sc_null(sc)) {
+ if (LIST_EMPTY(gsc))
+ return (1);
+ LIST_FOREACH(s, gsc, _next) {
+ if (s->m != 0)
+ return (0);
+ }
+ return (1);
+ }
+ /*
+ * gsc has a dummy entry at the end with x = INFINITY.
+ * loop through up to this dummy entry.
+ */
+ end = gsc_getentry(gsc, INFINITY);
+ if (end == NULL)
+ return (1);
+ last = NULL;
+ for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) {
+ if (s->y > sc_x2y(sc, s->x))
+ return (0);
+ last = s;
+ }
+ /* last now holds the real last segment */
+ if (last == NULL)
+ return (1);
+ if (last->m > sc->m2)
+ return (0);
+ if (last->x < sc->d && last->m > sc->m1) {
+ y = last->y + (sc->d - last->x) * last->m;
+ if (y > sc_x2y(sc, sc->d))
+ return (0);
+ }
+ return (1);
+}
+
+static void
+gsc_destroy(struct gen_sc *gsc)
+{
+ struct segment *s;
+
+ while ((s = LIST_FIRST(gsc)) != NULL) {
+ LIST_REMOVE(s, _next);
+ free(s);
+ }
+}
+
+/*
+ * return a segment entry starting at x.
+ * if gsc has no entry starting at x, a new entry is created at x.
+ */
+static struct segment *
+gsc_getentry(struct gen_sc *gsc, double x)
+{
+ struct segment *new, *prev, *s;
+
+ prev = NULL;
+ LIST_FOREACH(s, gsc, _next) {
+ if (s->x == x)
+ return (s); /* matching entry found */
+ else if (s->x < x)
+ prev = s;
+ else
+ break;
+ }
+
+ /* we have to create a new entry */
+ if ((new = calloc(1, sizeof(struct segment))) == NULL)
+ return (NULL);
+
+ new->x = x;
+ if (x == INFINITY || s == NULL)
+ new->d = 0;
+ else if (s->x == INFINITY)
+ new->d = INFINITY;
+ else
+ new->d = s->x - x;
+ if (prev == NULL) {
+ /* insert the new entry at the head of the list */
+ new->y = 0;
+ new->m = 0;
+ LIST_INSERT_HEAD(gsc, new, _next);
+ } else {
+ /*
+ * the start point intersects with the segment pointed by
+ * prev. divide prev into 2 segments
+ */
+ if (x == INFINITY) {
+ prev->d = INFINITY;
+ if (prev->m == 0)
+ new->y = prev->y;
+ else
+ new->y = INFINITY;
+ } else {
+ prev->d = x - prev->x;
+ new->y = prev->d * prev->m + prev->y;
+ }
+ new->m = prev->m;
+ LIST_INSERT_AFTER(prev, new, _next);
+ }
+ return (new);
+}
+
+/* add a segment to a generalized service curve */
+static int
+gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m)
+{
+ struct segment *start, *end, *s;
+ double x2;
+
+ if (d == INFINITY)
+ x2 = INFINITY;
+ else
+ x2 = x + d;
+ start = gsc_getentry(gsc, x);
+ end = gsc_getentry(gsc, x2);
+ if (start == NULL || end == NULL)
+ return (-1);
+
+ for (s = start; s != end; s = LIST_NEXT(s, _next)) {
+ s->m += m;
+ s->y += y + (s->x - x) * m;
+ }
+
+ end = gsc_getentry(gsc, INFINITY);
+ for (; s != end; s = LIST_NEXT(s, _next)) {
+ s->y += m * d;
+ }
+
+ return (0);
+}
+
+/* get y-projection of a service curve */
+static double
+sc_x2y(struct service_curve *sc, double x)
+{
+ double y;
+
+ if (x <= (double)sc->d)
+ /* y belongs to the 1st segment */
+ y = x * (double)sc->m1;
+ else
+ /* y belongs to the 2nd segment */
+ y = (double)sc->d * (double)sc->m1
+ + (x - (double)sc->d) * (double)sc->m2;
+ return (y);
+}
+
+/*
+ * misc utilities
+ */
+#define R2S_BUFS 8
+#define RATESTR_MAX 16
+
+#ifdef __rtems__
+static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */
+static int idx = 0;
+#endif /* __rtems__ */
+char *
+rate2str(double rate)
+{
+ char *buf;
+#ifndef __rtems__
+ static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */
+ static int idx = 0;
+#endif /* __rtems__ */
+ int i;
+ static const char unit[] = " KMG";
+
+ buf = r2sbuf[idx++];
+ if (idx == R2S_BUFS)
+ idx = 0;
+
+ for (i = 0; rate >= 1000 && i <= 3; i++)
+ rate /= 1000;
+
+ if ((int)(rate * 100) % 100)
+ snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]);
+ else
+ snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]);
+
+ return (buf);
+}
+
+#ifdef __FreeBSD__
+/*
+ * XXX
+ * FreeBSD does not have SIOCGIFDATA.
+ * To emulate this, DIOCGIFSPEED ioctl added to pf.
+ */
+u_int32_t
+getifspeed(int pfdev, char *ifname)
+{
+ struct pf_ifspeed io;
+
+ bzero(&io, sizeof io);
+ if (strlcpy(io.ifname, ifname, IFNAMSIZ) >=
+ sizeof(io.ifname))
+ errx(1, "getifspeed: strlcpy");
+ if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1)
+ err(1, "DIOCGIFSPEED");
+ return ((u_int32_t)io.baudrate);
+}
+#else
+u_int32_t
+getifspeed(char *ifname)
+{
+ int s;
+ struct ifreq ifr;
+ struct if_data ifrdat;
+
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ bzero(&ifr, sizeof(ifr));
+ if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
+ sizeof(ifr.ifr_name))
+ errx(1, "getifspeed: strlcpy");
+ ifr.ifr_data = (caddr_t)&ifrdat;
+ if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGIFDATA");
+ if (close(s))
+ err(1, "close");
+ return ((u_int32_t)ifrdat.ifi_baudrate);
+}
+#endif
+
+u_long
+getifmtu(char *ifname)
+{
+ int s;
+ struct ifreq ifr;
+
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ bzero(&ifr, sizeof(ifr));
+ if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
+ sizeof(ifr.ifr_name))
+ errx(1, "getifmtu: strlcpy");
+ if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1)
+#ifdef __FreeBSD__
+ ifr.ifr_mtu = 1500;
+#else
+ err(1, "SIOCGIFMTU");
+#endif
+ if (close(s))
+ err(1, "close");
+ if (ifr.ifr_mtu > 0)
+ return (ifr.ifr_mtu);
+ else {
+ warnx("could not get mtu for %s, assuming 1500", ifname);
+ return (1500);
+ }
+}
+
+int
+eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
+ u_int32_t ref_bw)
+{
+ int errors = 0;
+
+ switch (pa->scheduler) {
+ case ALTQT_CBQ:
+ pa->pq_u.cbq_opts = opts->data.cbq_opts;
+ break;
+ case ALTQT_PRIQ:
+ pa->pq_u.priq_opts = opts->data.priq_opts;
+ break;
+ case ALTQT_HFSC:
+ pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags;
+ if (opts->data.hfsc_opts.linkshare.used) {
+ pa->pq_u.hfsc_opts.lssc_m1 =
+ eval_bwspec(&opts->data.hfsc_opts.linkshare.m1,
+ ref_bw);
+ pa->pq_u.hfsc_opts.lssc_m2 =
+ eval_bwspec(&opts->data.hfsc_opts.linkshare.m2,
+ ref_bw);
+ pa->pq_u.hfsc_opts.lssc_d =
+ opts->data.hfsc_opts.linkshare.d;
+ }
+ if (opts->data.hfsc_opts.realtime.used) {
+ pa->pq_u.hfsc_opts.rtsc_m1 =
+ eval_bwspec(&opts->data.hfsc_opts.realtime.m1,
+ ref_bw);
+ pa->pq_u.hfsc_opts.rtsc_m2 =
+ eval_bwspec(&opts->data.hfsc_opts.realtime.m2,
+ ref_bw);
+ pa->pq_u.hfsc_opts.rtsc_d =
+ opts->data.hfsc_opts.realtime.d;
+ }
+ if (opts->data.hfsc_opts.upperlimit.used) {
+ pa->pq_u.hfsc_opts.ulsc_m1 =
+ eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1,
+ ref_bw);
+ pa->pq_u.hfsc_opts.ulsc_m2 =
+ eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2,
+ ref_bw);
+ pa->pq_u.hfsc_opts.ulsc_d =
+ opts->data.hfsc_opts.upperlimit.d;
+ }
+ break;
+ case ALTQT_FAIRQ:
+ pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags;
+ pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets;
+ pa->pq_u.fairq_opts.hogs_m1 =
+ eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw);
+
+ if (opts->data.fairq_opts.linkshare.used) {
+ pa->pq_u.fairq_opts.lssc_m1 =
+ eval_bwspec(&opts->data.fairq_opts.linkshare.m1,
+ ref_bw);
+ pa->pq_u.fairq_opts.lssc_m2 =
+ eval_bwspec(&opts->data.fairq_opts.linkshare.m2,
+ ref_bw);
+ pa->pq_u.fairq_opts.lssc_d =
+ opts->data.fairq_opts.linkshare.d;
+ }
+ break;
+ case ALTQT_CODEL:
+ pa->pq_u.codel_opts.target = opts->data.codel_opts.target;
+ pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval;
+ pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn;
+ break;
+ default:
+ warnx("eval_queue_opts: unknown scheduler type %u",
+ opts->qtype);
+ errors++;
+ break;
+ }
+
+ return (errors);
+}
+
+u_int32_t
+eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw)
+{
+ if (bw->bw_absolute > 0)
+ return (bw->bw_absolute);
+
+ if (bw->bw_percent > 0)
+ return (ref_bw / 100 * bw->bw_percent);
+
+ return (0);
+}
+
+void
+print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2,
+ const struct node_hfsc_sc *sc)
+{
+ printf(" %s", scname);
+
+ if (d != 0) {
+ printf("(");
+ if (sc != NULL && sc->m1.bw_percent > 0)
+ printf("%u%%", sc->m1.bw_percent);
+ else
+ printf("%s", rate2str((double)m1));
+ printf(" %u", d);
+ }
+
+ if (sc != NULL && sc->m2.bw_percent > 0)
+ printf(" %u%%", sc->m2.bw_percent);
+ else
+ printf(" %s", rate2str((double)m2));
+
+ if (d != 0)
+ printf(")");
+}
+
+void
+print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2,
+ const struct node_fairq_sc *sc)
+{
+ printf(" %s", scname);
+
+ if (d != 0) {
+ printf("(");
+ if (sc != NULL && sc->m1.bw_percent > 0)
+ printf("%u%%", sc->m1.bw_percent);
+ else
+ printf("%s", rate2str((double)m1));
+ printf(" %u", d);
+ }
+
+ if (sc != NULL && sc->m2.bw_percent > 0)
+ printf(" %u%%", sc->m2.bw_percent);
+ else
+ printf(" %s", rate2str((double)m2));
+
+ if (d != 0)
+ printf(")");
+}
diff --git a/freebsd/sbin/pfctl/pfctl_optimize.c b/freebsd/sbin/pfctl/pfctl_optimize.c
new file mode 100644
index 00000000..b8f44e8b
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_optimize.c
@@ -0,0 +1,1705 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_optimize.c,v 1.17 2008/05/06 03:45:21 mpf Exp $ */
+
+/*
+ * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+struct pf_rule_field {
+ const char *prf_name;
+ int prf_type;
+ size_t prf_offset;
+ size_t prf_size;
+};
+#include "rtems-bsd-pfctl-pfctl_optimize-data.h"
+#endif /* __rtems__ */
+
+/* The size at which a table becomes faster than individual rules */
+#define TABLE_THRESHOLD 6
+
+
+/* #define OPT_DEBUG 1 */
+#ifdef OPT_DEBUG
+# define DEBUG(str, v...) \
+ printf("%s: " str "\n", __FUNCTION__ , ## v)
+#else
+# define DEBUG(str, v...) ((void)0)
+#endif
+
+
+/*
+ * A container that lets us sort a superblock to optimize the skip step jumps
+ */
+struct pf_skip_step {
+ int ps_count; /* number of items */
+ TAILQ_HEAD( , pf_opt_rule) ps_rules;
+ TAILQ_ENTRY(pf_skip_step) ps_entry;
+};
+
+
+/*
+ * A superblock is a block of adjacent rules of similar action. If there
+ * are five PASS rules in a row, they all become members of a superblock.
+ * Once we have a superblock, we are free to re-order any rules within it
+ * in order to improve performance; if a packet is passed, it doesn't matter
+ * who passed it.
+ */
+struct superblock {
+ TAILQ_HEAD( , pf_opt_rule) sb_rules;
+ TAILQ_ENTRY(superblock) sb_entry;
+ struct superblock *sb_profiled_block;
+ TAILQ_HEAD(skiplist, pf_skip_step) sb_skipsteps[PF_SKIP_COUNT];
+};
+TAILQ_HEAD(superblocks, superblock);
+
+
+/*
+ * Description of the PF rule structure.
+ */
+enum {
+ BARRIER, /* the presence of the field puts the rule in it's own block */
+ BREAK, /* the field may not differ between rules in a superblock */
+ NOMERGE, /* the field may not differ between rules when combined */
+ COMBINED, /* the field may itself be combined with other rules */
+ DC, /* we just don't care about the field */
+ NEVER}; /* we should never see this field set?!? */
+#ifndef __rtems__
+static struct pf_rule_field {
+ const char *prf_name;
+ int prf_type;
+ size_t prf_offset;
+ size_t prf_size;
+} pf_rule_desc[] = {
+#else /* __rtems__ */
+static struct pf_rule_field pf_rule_desc[] = {
+#endif /* __rtems__ */
+#define PF_RULE_FIELD(field, ty) \
+ {#field, \
+ ty, \
+ offsetof(struct pf_rule, field), \
+ sizeof(((struct pf_rule *)0)->field)}
+
+
+ /*
+ * The presence of these fields in a rule put the rule in it's own
+ * superblock. Thus it will not be optimized. It also prevents the
+ * rule from being re-ordered at all.
+ */
+ PF_RULE_FIELD(label, BARRIER),
+ PF_RULE_FIELD(prob, BARRIER),
+ PF_RULE_FIELD(max_states, BARRIER),
+ PF_RULE_FIELD(max_src_nodes, BARRIER),
+ PF_RULE_FIELD(max_src_states, BARRIER),
+ PF_RULE_FIELD(max_src_conn, BARRIER),
+ PF_RULE_FIELD(max_src_conn_rate, BARRIER),
+ PF_RULE_FIELD(anchor, BARRIER), /* for now */
+
+ /*
+ * These fields must be the same between all rules in the same superblock.
+ * These rules are allowed to be re-ordered but only among like rules.
+ * For instance we can re-order all 'tag "foo"' rules because they have the
+ * same tag. But we can not re-order between a 'tag "foo"' and a
+ * 'tag "bar"' since that would change the meaning of the ruleset.
+ */
+ PF_RULE_FIELD(tagname, BREAK),
+ PF_RULE_FIELD(keep_state, BREAK),
+ PF_RULE_FIELD(qname, BREAK),
+ PF_RULE_FIELD(pqname, BREAK),
+ PF_RULE_FIELD(rt, BREAK),
+ PF_RULE_FIELD(allow_opts, BREAK),
+ PF_RULE_FIELD(rule_flag, BREAK),
+ PF_RULE_FIELD(action, BREAK),
+ PF_RULE_FIELD(log, BREAK),
+ PF_RULE_FIELD(quick, BREAK),
+ PF_RULE_FIELD(return_ttl, BREAK),
+ PF_RULE_FIELD(overload_tblname, BREAK),
+ PF_RULE_FIELD(flush, BREAK),
+ PF_RULE_FIELD(rpool, BREAK),
+ PF_RULE_FIELD(logif, BREAK),
+
+ /*
+ * Any fields not listed in this structure act as BREAK fields
+ */
+
+
+ /*
+ * These fields must not differ when we merge two rules together but
+ * their difference isn't enough to put the rules in different superblocks.
+ * There are no problems re-ordering any rules with these fields.
+ */
+ PF_RULE_FIELD(af, NOMERGE),
+ PF_RULE_FIELD(ifnot, NOMERGE),
+ PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */
+ PF_RULE_FIELD(match_tag_not, NOMERGE),
+ PF_RULE_FIELD(match_tagname, NOMERGE),
+ PF_RULE_FIELD(os_fingerprint, NOMERGE),
+ PF_RULE_FIELD(timeout, NOMERGE),
+ PF_RULE_FIELD(return_icmp, NOMERGE),
+ PF_RULE_FIELD(return_icmp6, NOMERGE),
+ PF_RULE_FIELD(uid, NOMERGE),
+ PF_RULE_FIELD(gid, NOMERGE),
+ PF_RULE_FIELD(direction, NOMERGE),
+ PF_RULE_FIELD(proto, NOMERGE),
+ PF_RULE_FIELD(type, NOMERGE),
+ PF_RULE_FIELD(code, NOMERGE),
+ PF_RULE_FIELD(flags, NOMERGE),
+ PF_RULE_FIELD(flagset, NOMERGE),
+ PF_RULE_FIELD(tos, NOMERGE),
+ PF_RULE_FIELD(src.port, NOMERGE),
+ PF_RULE_FIELD(dst.port, NOMERGE),
+ PF_RULE_FIELD(src.port_op, NOMERGE),
+ PF_RULE_FIELD(dst.port_op, NOMERGE),
+ PF_RULE_FIELD(src.neg, NOMERGE),
+ PF_RULE_FIELD(dst.neg, NOMERGE),
+
+ /* These fields can be merged */
+ PF_RULE_FIELD(src.addr, COMBINED),
+ PF_RULE_FIELD(dst.addr, COMBINED),
+
+ /* We just don't care about these fields. They're set by the kernel */
+ PF_RULE_FIELD(skip, DC),
+ PF_RULE_FIELD(evaluations, DC),
+ PF_RULE_FIELD(packets, DC),
+ PF_RULE_FIELD(bytes, DC),
+ PF_RULE_FIELD(kif, DC),
+ PF_RULE_FIELD(states_cur, DC),
+ PF_RULE_FIELD(states_tot, DC),
+ PF_RULE_FIELD(src_nodes, DC),
+ PF_RULE_FIELD(nr, DC),
+ PF_RULE_FIELD(entries, DC),
+ PF_RULE_FIELD(qid, DC),
+ PF_RULE_FIELD(pqid, DC),
+ PF_RULE_FIELD(anchor_relative, DC),
+ PF_RULE_FIELD(anchor_wildcard, DC),
+ PF_RULE_FIELD(tag, DC),
+ PF_RULE_FIELD(match_tag, DC),
+ PF_RULE_FIELD(overload_tbl, DC),
+
+ /* These fields should never be set in a PASS/BLOCK rule */
+ PF_RULE_FIELD(natpass, NEVER),
+ PF_RULE_FIELD(max_mss, NEVER),
+ PF_RULE_FIELD(min_ttl, NEVER),
+ PF_RULE_FIELD(set_tos, NEVER),
+};
+
+
+
+int add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t,
+ struct pf_rule_addr *);
+int addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *);
+int addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *);
+int block_feedback(struct pfctl *, struct superblock *);
+int combine_rules(struct pfctl *, struct superblock *);
+void comparable_rule(struct pf_rule *, const struct pf_rule *, int);
+int construct_superblocks(struct pfctl *, struct pf_opt_queue *,
+ struct superblocks *);
+void exclude_supersets(struct pf_rule *, struct pf_rule *);
+int interface_group(const char *);
+int load_feedback_profile(struct pfctl *, struct superblocks *);
+int optimize_superblock(struct pfctl *, struct superblock *);
+int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *);
+void remove_from_skipsteps(struct skiplist *, struct superblock *,
+ struct pf_opt_rule *, struct pf_skip_step *);
+int remove_identical_rules(struct pfctl *, struct superblock *);
+int reorder_rules(struct pfctl *, struct superblock *, int);
+int rules_combineable(struct pf_rule *, struct pf_rule *);
+void skip_append(struct superblock *, int, struct pf_skip_step *,
+ struct pf_opt_rule *);
+int skip_compare(int, struct pf_skip_step *, struct pf_opt_rule *);
+void skip_init(void);
+int skip_cmp_af(struct pf_rule *, struct pf_rule *);
+int skip_cmp_dir(struct pf_rule *, struct pf_rule *);
+int skip_cmp_dst_addr(struct pf_rule *, struct pf_rule *);
+int skip_cmp_dst_port(struct pf_rule *, struct pf_rule *);
+int skip_cmp_ifp(struct pf_rule *, struct pf_rule *);
+int skip_cmp_proto(struct pf_rule *, struct pf_rule *);
+int skip_cmp_src_addr(struct pf_rule *, struct pf_rule *);
+int skip_cmp_src_port(struct pf_rule *, struct pf_rule *);
+int superblock_inclusive(struct superblock *, struct pf_opt_rule *);
+void superblock_free(struct pfctl *, struct superblock *);
+
+
+static int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *,
+ struct pf_rule *);
+static const char *skip_comparitors_names[PF_SKIP_COUNT];
+#define PF_SKIP_COMPARITORS { \
+ { "ifp", PF_SKIP_IFP, skip_cmp_ifp }, \
+ { "dir", PF_SKIP_DIR, skip_cmp_dir }, \
+ { "af", PF_SKIP_AF, skip_cmp_af }, \
+ { "proto", PF_SKIP_PROTO, skip_cmp_proto }, \
+ { "saddr", PF_SKIP_SRC_ADDR, skip_cmp_src_addr }, \
+ { "sport", PF_SKIP_SRC_PORT, skip_cmp_src_port }, \
+ { "daddr", PF_SKIP_DST_ADDR, skip_cmp_dst_addr }, \
+ { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port } \
+}
+
+static struct pfr_buffer table_buffer;
+static int table_identifier;
+
+
+int
+pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs)
+{
+ struct superblocks superblocks;
+ struct pf_opt_queue opt_queue;
+ struct superblock *block;
+ struct pf_opt_rule *por;
+ struct pf_rule *r;
+ struct pf_rulequeue *old_rules;
+
+ DEBUG("optimizing ruleset");
+ memset(&table_buffer, 0, sizeof(table_buffer));
+ skip_init();
+ TAILQ_INIT(&opt_queue);
+
+ old_rules = rs->rules[PF_RULESET_FILTER].active.ptr;
+ rs->rules[PF_RULESET_FILTER].active.ptr =
+ rs->rules[PF_RULESET_FILTER].inactive.ptr;
+ rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules;
+
+ /*
+ * XXX expanding the pf_opt_rule format throughout pfctl might allow
+ * us to avoid all this copying.
+ */
+ while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr))
+ != NULL) {
+ TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r,
+ entries);
+ if ((por = calloc(1, sizeof(*por))) == NULL)
+ err(1, "calloc");
+ memcpy(&por->por_rule, r, sizeof(*r));
+ if (TAILQ_FIRST(&r->rpool.list) != NULL) {
+ TAILQ_INIT(&por->por_rule.rpool.list);
+ pfctl_move_pool(&r->rpool, &por->por_rule.rpool);
+ } else
+ bzero(&por->por_rule.rpool,
+ sizeof(por->por_rule.rpool));
+
+
+ TAILQ_INSERT_TAIL(&opt_queue, por, por_entry);
+ }
+
+ TAILQ_INIT(&superblocks);
+ if (construct_superblocks(pf, &opt_queue, &superblocks))
+ goto error;
+
+ if (pf->optimize & PF_OPTIMIZE_PROFILE) {
+ if (load_feedback_profile(pf, &superblocks))
+ goto error;
+ }
+
+ TAILQ_FOREACH(block, &superblocks, sb_entry) {
+ if (optimize_superblock(pf, block))
+ goto error;
+ }
+
+ rs->anchor->refcnt = 0;
+ while ((block = TAILQ_FIRST(&superblocks))) {
+ TAILQ_REMOVE(&superblocks, block, sb_entry);
+
+ while ((por = TAILQ_FIRST(&block->sb_rules))) {
+ TAILQ_REMOVE(&block->sb_rules, por, por_entry);
+ por->por_rule.nr = rs->anchor->refcnt++;
+ if ((r = calloc(1, sizeof(*r))) == NULL)
+ err(1, "calloc");
+ memcpy(r, &por->por_rule, sizeof(*r));
+ TAILQ_INIT(&r->rpool.list);
+ pfctl_move_pool(&por->por_rule.rpool, &r->rpool);
+ TAILQ_INSERT_TAIL(
+ rs->rules[PF_RULESET_FILTER].active.ptr,
+ r, entries);
+ free(por);
+ }
+ free(block);
+ }
+
+ return (0);
+
+error:
+ while ((por = TAILQ_FIRST(&opt_queue))) {
+ TAILQ_REMOVE(&opt_queue, por, por_entry);
+ if (por->por_src_tbl) {
+ pfr_buf_clear(por->por_src_tbl->pt_buf);
+ free(por->por_src_tbl->pt_buf);
+ free(por->por_src_tbl);
+ }
+ if (por->por_dst_tbl) {
+ pfr_buf_clear(por->por_dst_tbl->pt_buf);
+ free(por->por_dst_tbl->pt_buf);
+ free(por->por_dst_tbl);
+ }
+ free(por);
+ }
+ while ((block = TAILQ_FIRST(&superblocks))) {
+ TAILQ_REMOVE(&superblocks, block, sb_entry);
+ superblock_free(pf, block);
+ }
+ return (1);
+}
+
+
+/*
+ * Go ahead and optimize a superblock
+ */
+int
+optimize_superblock(struct pfctl *pf, struct superblock *block)
+{
+#ifdef OPT_DEBUG
+ struct pf_opt_rule *por;
+#endif /* OPT_DEBUG */
+
+ /* We have a few optimization passes:
+ * 1) remove duplicate rules or rules that are a subset of other
+ * rules
+ * 2) combine otherwise identical rules with different IP addresses
+ * into a single rule and put the addresses in a table.
+ * 3) re-order the rules to improve kernel skip steps
+ * 4) re-order the 'quick' rules based on feedback from the
+ * active ruleset statistics
+ *
+ * XXX combine_rules() doesn't combine v4 and v6 rules. would just
+ * have to keep af in the table container, make af 'COMBINE' and
+ * twiddle the af on the merged rule
+ * XXX maybe add a weighting to the metric on skipsteps when doing
+ * reordering. sometimes two sequential tables will be better
+ * that four consecutive interfaces.
+ * XXX need to adjust the skipstep count of everything after PROTO,
+ * since they aren't actually checked on a proto mismatch in
+ * pf_test_{tcp, udp, icmp}()
+ * XXX should i treat proto=0, af=0 or dir=0 special in skepstep
+ * calculation since they are a DC?
+ * XXX keep last skiplist of last superblock to influence this
+ * superblock. '5 inet6 log' should make '3 inet6' come before '4
+ * inet' in the next superblock.
+ * XXX would be useful to add tables for ports
+ * XXX we can also re-order some mutually exclusive superblocks to
+ * try merging superblocks before any of these optimization passes.
+ * for instance a single 'log in' rule in the middle of non-logging
+ * out rules.
+ */
+
+ /* shortcut. there will be a lot of 1-rule superblocks */
+ if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry))
+ return (0);
+
+#ifdef OPT_DEBUG
+ printf("--- Superblock ---\n");
+ TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
+ printf(" ");
+ print_rule(&por->por_rule, por->por_rule.anchor ?
+ por->por_rule.anchor->name : "", 1, 0);
+ }
+#endif /* OPT_DEBUG */
+
+
+ if (remove_identical_rules(pf, block))
+ return (1);
+ if (combine_rules(pf, block))
+ return (1);
+ if ((pf->optimize & PF_OPTIMIZE_PROFILE) &&
+ TAILQ_FIRST(&block->sb_rules)->por_rule.quick &&
+ block->sb_profiled_block) {
+ if (block_feedback(pf, block))
+ return (1);
+ } else if (reorder_rules(pf, block, 0)) {
+ return (1);
+ }
+
+ /*
+ * Don't add any optimization passes below reorder_rules(). It will
+ * have divided superblocks into smaller blocks for further refinement
+ * and doesn't put them back together again. What once was a true
+ * superblock might have been split into multiple superblocks.
+ */
+
+#ifdef OPT_DEBUG
+ printf("--- END Superblock ---\n");
+#endif /* OPT_DEBUG */
+ return (0);
+}
+
+
+/*
+ * Optimization pass #1: remove identical rules
+ */
+int
+remove_identical_rules(struct pfctl *pf, struct superblock *block)
+{
+ struct pf_opt_rule *por1, *por2, *por_next, *por2_next;
+ struct pf_rule a, a2, b, b2;
+
+ for (por1 = TAILQ_FIRST(&block->sb_rules); por1; por1 = por_next) {
+ por_next = TAILQ_NEXT(por1, por_entry);
+ for (por2 = por_next; por2; por2 = por2_next) {
+ por2_next = TAILQ_NEXT(por2, por_entry);
+ comparable_rule(&a, &por1->por_rule, DC);
+ comparable_rule(&b, &por2->por_rule, DC);
+ memcpy(&a2, &a, sizeof(a2));
+ memcpy(&b2, &b, sizeof(b2));
+
+ exclude_supersets(&a, &b);
+ exclude_supersets(&b2, &a2);
+ if (memcmp(&a, &b, sizeof(a)) == 0) {
+ DEBUG("removing identical rule nr%d = *nr%d*",
+ por1->por_rule.nr, por2->por_rule.nr);
+ TAILQ_REMOVE(&block->sb_rules, por2, por_entry);
+ if (por_next == por2)
+ por_next = TAILQ_NEXT(por1, por_entry);
+ free(por2);
+ } else if (memcmp(&a2, &b2, sizeof(a2)) == 0) {
+ DEBUG("removing identical rule *nr%d* = nr%d",
+ por1->por_rule.nr, por2->por_rule.nr);
+ TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
+ free(por1);
+ break;
+ }
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Optimization pass #2: combine similar rules with different addresses
+ * into a single rule and a table
+ */
+int
+combine_rules(struct pfctl *pf, struct superblock *block)
+{
+ struct pf_opt_rule *p1, *p2, *por_next;
+ int src_eq, dst_eq;
+
+ if ((pf->loadopt & PFCTL_FLAG_TABLE) == 0) {
+ warnx("Must enable table loading for optimizations");
+ return (1);
+ }
+
+ /* First we make a pass to combine the rules. O(n log n) */
+ TAILQ_FOREACH(p1, &block->sb_rules, por_entry) {
+ for (p2 = TAILQ_NEXT(p1, por_entry); p2; p2 = por_next) {
+ por_next = TAILQ_NEXT(p2, por_entry);
+
+ src_eq = addrs_equal(&p1->por_rule.src,
+ &p2->por_rule.src);
+ dst_eq = addrs_equal(&p1->por_rule.dst,
+ &p2->por_rule.dst);
+
+ if (src_eq && !dst_eq && p1->por_src_tbl == NULL &&
+ p2->por_dst_tbl == NULL &&
+ p2->por_src_tbl == NULL &&
+ rules_combineable(&p1->por_rule, &p2->por_rule) &&
+ addrs_combineable(&p1->por_rule.dst,
+ &p2->por_rule.dst)) {
+ DEBUG("can combine rules nr%d = nr%d",
+ p1->por_rule.nr, p2->por_rule.nr);
+ if (p1->por_dst_tbl == NULL &&
+ add_opt_table(pf, &p1->por_dst_tbl,
+ p1->por_rule.af, &p1->por_rule.dst))
+ return (1);
+ if (add_opt_table(pf, &p1->por_dst_tbl,
+ p1->por_rule.af, &p2->por_rule.dst))
+ return (1);
+ p2->por_dst_tbl = p1->por_dst_tbl;
+ if (p1->por_dst_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ TAILQ_REMOVE(&block->sb_rules, p2,
+ por_entry);
+ free(p2);
+ }
+ } else if (!src_eq && dst_eq && p1->por_dst_tbl == NULL
+ && p2->por_src_tbl == NULL &&
+ p2->por_dst_tbl == NULL &&
+ rules_combineable(&p1->por_rule, &p2->por_rule) &&
+ addrs_combineable(&p1->por_rule.src,
+ &p2->por_rule.src)) {
+ DEBUG("can combine rules nr%d = nr%d",
+ p1->por_rule.nr, p2->por_rule.nr);
+ if (p1->por_src_tbl == NULL &&
+ add_opt_table(pf, &p1->por_src_tbl,
+ p1->por_rule.af, &p1->por_rule.src))
+ return (1);
+ if (add_opt_table(pf, &p1->por_src_tbl,
+ p1->por_rule.af, &p2->por_rule.src))
+ return (1);
+ p2->por_src_tbl = p1->por_src_tbl;
+ if (p1->por_src_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ TAILQ_REMOVE(&block->sb_rules, p2,
+ por_entry);
+ free(p2);
+ }
+ }
+ }
+ }
+
+
+ /*
+ * Then we make a final pass to create a valid table name and
+ * insert the name into the rules.
+ */
+ for (p1 = TAILQ_FIRST(&block->sb_rules); p1; p1 = por_next) {
+ por_next = TAILQ_NEXT(p1, por_entry);
+ assert(p1->por_src_tbl == NULL || p1->por_dst_tbl == NULL);
+
+ if (p1->por_src_tbl && p1->por_src_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ if (p1->por_src_tbl->pt_generated) {
+ /* This rule is included in a table */
+ TAILQ_REMOVE(&block->sb_rules, p1, por_entry);
+ free(p1);
+ continue;
+ }
+ p1->por_src_tbl->pt_generated = 1;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0 &&
+ pf_opt_create_table(pf, p1->por_src_tbl))
+ return (1);
+
+ pf->tdirty = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(p1->por_src_tbl->pt_name,
+ PFR_TFLAG_CONST, 1,
+ &p1->por_src_tbl->pt_nodes);
+
+ memset(&p1->por_rule.src.addr, 0,
+ sizeof(p1->por_rule.src.addr));
+ p1->por_rule.src.addr.type = PF_ADDR_TABLE;
+ strlcpy(p1->por_rule.src.addr.v.tblname,
+ p1->por_src_tbl->pt_name,
+ sizeof(p1->por_rule.src.addr.v.tblname));
+
+ pfr_buf_clear(p1->por_src_tbl->pt_buf);
+ free(p1->por_src_tbl->pt_buf);
+ p1->por_src_tbl->pt_buf = NULL;
+ }
+ if (p1->por_dst_tbl && p1->por_dst_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ if (p1->por_dst_tbl->pt_generated) {
+ /* This rule is included in a table */
+ TAILQ_REMOVE(&block->sb_rules, p1, por_entry);
+ free(p1);
+ continue;
+ }
+ p1->por_dst_tbl->pt_generated = 1;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0 &&
+ pf_opt_create_table(pf, p1->por_dst_tbl))
+ return (1);
+ pf->tdirty = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(p1->por_dst_tbl->pt_name,
+ PFR_TFLAG_CONST, 1,
+ &p1->por_dst_tbl->pt_nodes);
+
+ memset(&p1->por_rule.dst.addr, 0,
+ sizeof(p1->por_rule.dst.addr));
+ p1->por_rule.dst.addr.type = PF_ADDR_TABLE;
+ strlcpy(p1->por_rule.dst.addr.v.tblname,
+ p1->por_dst_tbl->pt_name,
+ sizeof(p1->por_rule.dst.addr.v.tblname));
+
+ pfr_buf_clear(p1->por_dst_tbl->pt_buf);
+ free(p1->por_dst_tbl->pt_buf);
+ p1->por_dst_tbl->pt_buf = NULL;
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Optimization pass #3: re-order rules to improve skip steps
+ */
+int
+reorder_rules(struct pfctl *pf, struct superblock *block, int depth)
+{
+ struct superblock *newblock;
+ struct pf_skip_step *skiplist;
+ struct pf_opt_rule *por;
+ int i, largest, largest_list, rule_count = 0;
+ TAILQ_HEAD( , pf_opt_rule) head;
+
+ /*
+ * Calculate the best-case skip steps. We put each rule in a list
+ * of other rules with common fields
+ */
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
+ TAILQ_FOREACH(skiplist, &block->sb_skipsteps[i],
+ ps_entry) {
+ if (skip_compare(i, skiplist, por) == 0)
+ break;
+ }
+ if (skiplist == NULL) {
+ if ((skiplist = calloc(1, sizeof(*skiplist))) ==
+ NULL)
+ err(1, "calloc");
+ TAILQ_INIT(&skiplist->ps_rules);
+ TAILQ_INSERT_TAIL(&block->sb_skipsteps[i],
+ skiplist, ps_entry);
+ }
+ skip_append(block, i, skiplist, por);
+ }
+ }
+
+ TAILQ_FOREACH(por, &block->sb_rules, por_entry)
+ rule_count++;
+
+ /*
+ * Now we're going to ignore any fields that are identical between
+ * all of the rules in the superblock and those fields which differ
+ * between every rule in the superblock.
+ */
+ largest = 0;
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]);
+ if (skiplist->ps_count == rule_count) {
+ DEBUG("(%d) original skipstep '%s' is all rules",
+ depth, skip_comparitors_names[i]);
+ skiplist->ps_count = 0;
+ } else if (skiplist->ps_count == 1) {
+ skiplist->ps_count = 0;
+ } else {
+ DEBUG("(%d) original skipstep '%s' largest jump is %d",
+ depth, skip_comparitors_names[i],
+ skiplist->ps_count);
+ if (skiplist->ps_count > largest)
+ largest = skiplist->ps_count;
+ }
+ }
+ if (largest == 0) {
+ /* Ugh. There is NO commonality in the superblock on which
+ * optimize the skipsteps optimization.
+ */
+ goto done;
+ }
+
+ /*
+ * Now we're going to empty the superblock rule list and re-create
+ * it based on a more optimal skipstep order.
+ */
+ TAILQ_INIT(&head);
+ while ((por = TAILQ_FIRST(&block->sb_rules))) {
+ TAILQ_REMOVE(&block->sb_rules, por, por_entry);
+ TAILQ_INSERT_TAIL(&head, por, por_entry);
+ }
+
+
+ while (!TAILQ_EMPTY(&head)) {
+ largest = 1;
+
+ /*
+ * Find the most useful skip steps remaining
+ */
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]);
+ if (skiplist->ps_count > largest) {
+ largest = skiplist->ps_count;
+ largest_list = i;
+ }
+ }
+
+ if (largest <= 1) {
+ /*
+ * Nothing useful left. Leave remaining rules in order.
+ */
+ DEBUG("(%d) no more commonality for skip steps", depth);
+ while ((por = TAILQ_FIRST(&head))) {
+ TAILQ_REMOVE(&head, por, por_entry);
+ TAILQ_INSERT_TAIL(&block->sb_rules, por,
+ por_entry);
+ }
+ } else {
+ /*
+ * There is commonality. Extract those common rules
+ * and place them in the ruleset adjacent to each
+ * other.
+ */
+ skiplist = TAILQ_FIRST(&block->sb_skipsteps[
+ largest_list]);
+ DEBUG("(%d) skipstep '%s' largest jump is %d @ #%d",
+ depth, skip_comparitors_names[largest_list],
+ largest, TAILQ_FIRST(&TAILQ_FIRST(&block->
+ sb_skipsteps [largest_list])->ps_rules)->
+ por_rule.nr);
+ TAILQ_REMOVE(&block->sb_skipsteps[largest_list],
+ skiplist, ps_entry);
+
+
+ /*
+ * There may be further commonality inside these
+ * rules. So we'll split them off into they're own
+ * superblock and pass it back into the optimizer.
+ */
+ if (skiplist->ps_count > 2) {
+ if ((newblock = calloc(1, sizeof(*newblock)))
+ == NULL) {
+ warn("calloc");
+ return (1);
+ }
+ TAILQ_INIT(&newblock->sb_rules);
+ for (i = 0; i < PF_SKIP_COUNT; i++)
+ TAILQ_INIT(&newblock->sb_skipsteps[i]);
+ TAILQ_INSERT_BEFORE(block, newblock, sb_entry);
+ DEBUG("(%d) splitting off %d rules from superblock @ #%d",
+ depth, skiplist->ps_count,
+ TAILQ_FIRST(&skiplist->ps_rules)->
+ por_rule.nr);
+ } else {
+ newblock = block;
+ }
+
+ while ((por = TAILQ_FIRST(&skiplist->ps_rules))) {
+ TAILQ_REMOVE(&head, por, por_entry);
+ TAILQ_REMOVE(&skiplist->ps_rules, por,
+ por_skip_entry[largest_list]);
+ TAILQ_INSERT_TAIL(&newblock->sb_rules, por,
+ por_entry);
+
+ /* Remove this rule from all other skiplists */
+ remove_from_skipsteps(&block->sb_skipsteps[
+ largest_list], block, por, skiplist);
+ }
+ free(skiplist);
+ if (newblock != block)
+ if (reorder_rules(pf, newblock, depth + 1))
+ return (1);
+ }
+ }
+
+done:
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ while ((skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]))) {
+ TAILQ_REMOVE(&block->sb_skipsteps[i], skiplist,
+ ps_entry);
+ free(skiplist);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Optimization pass #4: re-order 'quick' rules based on feedback from the
+ * currently running ruleset
+ */
+int
+block_feedback(struct pfctl *pf, struct superblock *block)
+{
+ TAILQ_HEAD( , pf_opt_rule) queue;
+ struct pf_opt_rule *por1, *por2;
+ u_int64_t total_count = 0;
+ struct pf_rule a, b;
+
+
+ /*
+ * Walk through all of the profiled superblock's rules and copy
+ * the counters onto our rules.
+ */
+ TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) {
+ comparable_rule(&a, &por1->por_rule, DC);
+ total_count += por1->por_rule.packets[0] +
+ por1->por_rule.packets[1];
+ TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
+ if (por2->por_profile_count)
+ continue;
+ comparable_rule(&b, &por2->por_rule, DC);
+ if (memcmp(&a, &b, sizeof(a)) == 0) {
+ por2->por_profile_count =
+ por1->por_rule.packets[0] +
+ por1->por_rule.packets[1];
+ break;
+ }
+ }
+ }
+ superblock_free(pf, block->sb_profiled_block);
+ block->sb_profiled_block = NULL;
+
+ /*
+ * Now we pull all of the rules off the superblock and re-insert them
+ * in sorted order.
+ */
+
+ TAILQ_INIT(&queue);
+ while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) {
+ TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
+ TAILQ_INSERT_TAIL(&queue, por1, por_entry);
+ }
+
+ while ((por1 = TAILQ_FIRST(&queue)) != NULL) {
+ TAILQ_REMOVE(&queue, por1, por_entry);
+/* XXX I should sort all of the unused rules based on skip steps */
+ TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
+ if (por1->por_profile_count > por2->por_profile_count) {
+ TAILQ_INSERT_BEFORE(por2, por1, por_entry);
+ break;
+ }
+ }
+#ifdef __FreeBSD__
+ if (por2 == NULL)
+#else
+ if (por2 == TAILQ_END(&block->sb_rules))
+#endif
+ TAILQ_INSERT_TAIL(&block->sb_rules, por1, por_entry);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Load the current ruleset from the kernel and try to associate them with
+ * the ruleset we're optimizing.
+ */
+int
+load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
+{
+ struct superblock *block, *blockcur;
+ struct superblocks prof_superblocks;
+ struct pf_opt_rule *por;
+ struct pf_opt_queue queue;
+ struct pfioc_rule pr;
+ struct pf_rule a, b;
+ int nr, mnr;
+
+ TAILQ_INIT(&queue);
+ TAILQ_INIT(&prof_superblocks);
+
+ memset(&pr, 0, sizeof(pr));
+ pr.rule.action = PF_PASS;
+ if (ioctl(pf->dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ return (1);
+ }
+ mnr = pr.nr;
+
+ DEBUG("Loading %d active rules for a feedback profile", mnr);
+ for (nr = 0; nr < mnr; ++nr) {
+ struct pf_ruleset *rs;
+ if ((por = calloc(1, sizeof(*por))) == NULL) {
+ warn("calloc");
+ return (1);
+ }
+ pr.nr = nr;
+ if (ioctl(pf->dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULES");
+ return (1);
+ }
+ memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule));
+ rs = pf_find_or_create_ruleset(pr.anchor_call);
+ por->por_rule.anchor = rs->anchor;
+ if (TAILQ_EMPTY(&por->por_rule.rpool.list))
+ memset(&por->por_rule.rpool, 0,
+ sizeof(por->por_rule.rpool));
+ TAILQ_INSERT_TAIL(&queue, por, por_entry);
+
+ /* XXX pfctl_get_pool(pf->dev, &pr.rule.rpool, nr, pr.ticket,
+ * PF_PASS, pf->anchor) ???
+ * ... pfctl_clear_pool(&pr.rule.rpool)
+ */
+ }
+
+ if (construct_superblocks(pf, &queue, &prof_superblocks))
+ return (1);
+
+
+ /*
+ * Now we try to associate the active ruleset's superblocks with
+ * the superblocks we're compiling.
+ */
+ block = TAILQ_FIRST(superblocks);
+ blockcur = TAILQ_FIRST(&prof_superblocks);
+ while (block && blockcur) {
+ comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule,
+ BREAK);
+ comparable_rule(&b, &TAILQ_FIRST(&blockcur->sb_rules)->por_rule,
+ BREAK);
+ if (memcmp(&a, &b, sizeof(a)) == 0) {
+ /* The two superblocks lined up */
+ block->sb_profiled_block = blockcur;
+ } else {
+ DEBUG("superblocks don't line up between #%d and #%d",
+ TAILQ_FIRST(&block->sb_rules)->por_rule.nr,
+ TAILQ_FIRST(&blockcur->sb_rules)->por_rule.nr);
+ break;
+ }
+ block = TAILQ_NEXT(block, sb_entry);
+ blockcur = TAILQ_NEXT(blockcur, sb_entry);
+ }
+
+
+
+ /* Free any superblocks we couldn't link */
+ while (blockcur) {
+ block = TAILQ_NEXT(blockcur, sb_entry);
+ superblock_free(pf, blockcur);
+ blockcur = block;
+ }
+ return (0);
+}
+
+
+/*
+ * Compare a rule to a skiplist to see if the rule is a member
+ */
+int
+skip_compare(int skipnum, struct pf_skip_step *skiplist,
+ struct pf_opt_rule *por)
+{
+ struct pf_rule *a, *b;
+ if (skipnum >= PF_SKIP_COUNT || skipnum < 0)
+ errx(1, "skip_compare() out of bounds");
+ a = &por->por_rule;
+ b = &TAILQ_FIRST(&skiplist->ps_rules)->por_rule;
+
+ return ((skip_comparitors[skipnum])(a, b));
+}
+
+
+/*
+ * Add a rule to a skiplist
+ */
+void
+skip_append(struct superblock *superblock, int skipnum,
+ struct pf_skip_step *skiplist, struct pf_opt_rule *por)
+{
+ struct pf_skip_step *prev;
+
+ skiplist->ps_count++;
+ TAILQ_INSERT_TAIL(&skiplist->ps_rules, por, por_skip_entry[skipnum]);
+
+ /* Keep the list of skiplists sorted by whichever is larger */
+ while ((prev = TAILQ_PREV(skiplist, skiplist, ps_entry)) &&
+ prev->ps_count < skiplist->ps_count) {
+ TAILQ_REMOVE(&superblock->sb_skipsteps[skipnum],
+ skiplist, ps_entry);
+ TAILQ_INSERT_BEFORE(prev, skiplist, ps_entry);
+ }
+}
+
+
+/*
+ * Remove a rule from the other skiplist calculations.
+ */
+void
+remove_from_skipsteps(struct skiplist *head, struct superblock *block,
+ struct pf_opt_rule *por, struct pf_skip_step *active_list)
+{
+ struct pf_skip_step *sk, *next;
+ struct pf_opt_rule *p2;
+ int i, found;
+
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ sk = TAILQ_FIRST(&block->sb_skipsteps[i]);
+ if (sk == NULL || sk == active_list || sk->ps_count <= 1)
+ continue;
+ found = 0;
+ do {
+ TAILQ_FOREACH(p2, &sk->ps_rules, por_skip_entry[i])
+ if (p2 == por) {
+ TAILQ_REMOVE(&sk->ps_rules, p2,
+ por_skip_entry[i]);
+ found = 1;
+ sk->ps_count--;
+ break;
+ }
+ } while (!found && (sk = TAILQ_NEXT(sk, ps_entry)));
+ if (found && sk) {
+ /* Does this change the sorting order? */
+ while ((next = TAILQ_NEXT(sk, ps_entry)) &&
+ next->ps_count > sk->ps_count) {
+ TAILQ_REMOVE(head, sk, ps_entry);
+ TAILQ_INSERT_AFTER(head, next, sk, ps_entry);
+ }
+#ifdef OPT_DEBUG
+ next = TAILQ_NEXT(sk, ps_entry);
+ assert(next == NULL || next->ps_count <= sk->ps_count);
+#endif /* OPT_DEBUG */
+ }
+ }
+}
+
+
+/* Compare two rules AF field for skiplist construction */
+int
+skip_cmp_af(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->af != b->af || a->af == 0)
+ return (1);
+ return (0);
+}
+
+/* Compare two rules DIRECTION field for skiplist construction */
+int
+skip_cmp_dir(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->direction == 0 || a->direction != b->direction)
+ return (1);
+ return (0);
+}
+
+/* Compare two rules DST Address field for skiplist construction */
+int
+skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->dst.neg != b->dst.neg ||
+ a->dst.addr.type != b->dst.addr.type)
+ return (1);
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ switch (a->dst.addr.type) {
+ case PF_ADDR_ADDRMASK:
+ if (memcmp(&a->dst.addr.v.a.addr, &b->dst.addr.v.a.addr,
+ sizeof(a->dst.addr.v.a.addr)) ||
+ memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask,
+ sizeof(a->dst.addr.v.a.mask)) ||
+ (a->dst.addr.v.a.addr.addr32[0] == 0 &&
+ a->dst.addr.v.a.addr.addr32[1] == 0 &&
+ a->dst.addr.v.a.addr.addr32[2] == 0 &&
+ a->dst.addr.v.a.addr.addr32[3] == 0))
+ return (1);
+ return (0);
+ case PF_ADDR_DYNIFTL:
+ if (strcmp(a->dst.addr.v.ifname, b->dst.addr.v.ifname) != 0 ||
+ a->dst.addr.iflags != a->dst.addr.iflags ||
+ memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask,
+ sizeof(a->dst.addr.v.a.mask)))
+ return (1);
+ return (0);
+ case PF_ADDR_NOROUTE:
+ case PF_ADDR_URPFFAILED:
+ return (0);
+ case PF_ADDR_TABLE:
+ return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname));
+ }
+ return (1);
+}
+
+/* Compare two rules DST port field for skiplist construction */
+int
+skip_cmp_dst_port(struct pf_rule *a, struct pf_rule *b)
+{
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ if (a->dst.port_op == PF_OP_NONE || a->dst.port_op != b->dst.port_op ||
+ a->dst.port[0] != b->dst.port[0] ||
+ a->dst.port[1] != b->dst.port[1])
+ return (1);
+ return (0);
+}
+
+/* Compare two rules IFP field for skiplist construction */
+int
+skip_cmp_ifp(struct pf_rule *a, struct pf_rule *b)
+{
+ if (strcmp(a->ifname, b->ifname) || a->ifname[0] == '\0')
+ return (1);
+ return (a->ifnot != b->ifnot);
+}
+
+/* Compare two rules PROTO field for skiplist construction */
+int
+skip_cmp_proto(struct pf_rule *a, struct pf_rule *b)
+{
+ return (a->proto != b->proto || a->proto == 0);
+}
+
+/* Compare two rules SRC addr field for skiplist construction */
+int
+skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->src.neg != b->src.neg ||
+ a->src.addr.type != b->src.addr.type)
+ return (1);
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ switch (a->src.addr.type) {
+ case PF_ADDR_ADDRMASK:
+ if (memcmp(&a->src.addr.v.a.addr, &b->src.addr.v.a.addr,
+ sizeof(a->src.addr.v.a.addr)) ||
+ memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask,
+ sizeof(a->src.addr.v.a.mask)) ||
+ (a->src.addr.v.a.addr.addr32[0] == 0 &&
+ a->src.addr.v.a.addr.addr32[1] == 0 &&
+ a->src.addr.v.a.addr.addr32[2] == 0 &&
+ a->src.addr.v.a.addr.addr32[3] == 0))
+ return (1);
+ return (0);
+ case PF_ADDR_DYNIFTL:
+ if (strcmp(a->src.addr.v.ifname, b->src.addr.v.ifname) != 0 ||
+ a->src.addr.iflags != a->src.addr.iflags ||
+ memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask,
+ sizeof(a->src.addr.v.a.mask)))
+ return (1);
+ return (0);
+ case PF_ADDR_NOROUTE:
+ case PF_ADDR_URPFFAILED:
+ return (0);
+ case PF_ADDR_TABLE:
+ return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname));
+ }
+ return (1);
+}
+
+/* Compare two rules SRC port field for skiplist construction */
+int
+skip_cmp_src_port(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->src.port_op == PF_OP_NONE || a->src.port_op != b->src.port_op ||
+ a->src.port[0] != b->src.port[0] ||
+ a->src.port[1] != b->src.port[1])
+ return (1);
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ return (0);
+}
+
+
+void
+skip_init(void)
+{
+ struct {
+ char *name;
+ int skipnum;
+ int (*func)(struct pf_rule *, struct pf_rule *);
+ } comps[] = PF_SKIP_COMPARITORS;
+ int skipnum, i;
+
+ for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) {
+ for (i = 0; i < sizeof(comps)/sizeof(*comps); i++)
+ if (comps[i].skipnum == skipnum) {
+ skip_comparitors[skipnum] = comps[i].func;
+ skip_comparitors_names[skipnum] = comps[i].name;
+ }
+ }
+ for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++)
+ if (skip_comparitors[skipnum] == NULL)
+ errx(1, "Need to add skip step comparitor to pfctl?!");
+}
+
+/*
+ * Add a host/netmask to a table
+ */
+#ifdef __rtems__
+static int add_opt_tablenum = 0;
+#endif /* __rtems__ */
+int
+add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af,
+ struct pf_rule_addr *addr)
+{
+#ifdef OPT_DEBUG
+ char buf[128];
+#endif /* OPT_DEBUG */
+#ifndef __rtems__
+ static int tablenum = 0;
+#endif /* __rtems__ */
+ struct node_host node_host;
+
+ if (*tbl == NULL) {
+ if ((*tbl = calloc(1, sizeof(**tbl))) == NULL ||
+ ((*tbl)->pt_buf = calloc(1, sizeof(*(*tbl)->pt_buf))) ==
+ NULL)
+ err(1, "calloc");
+ (*tbl)->pt_buf->pfrb_type = PFRB_ADDRS;
+ SIMPLEQ_INIT(&(*tbl)->pt_nodes);
+
+ /* This is just a temporary table name */
+ snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d",
+#ifndef __rtems__
+ PF_OPT_TABLE_PREFIX, tablenum++);
+#else /* __rtems__ */
+ PF_OPT_TABLE_PREFIX, add_opt_tablenum++);
+#endif /* __rtems__ */
+ DEBUG("creating table <%s>", (*tbl)->pt_name);
+ }
+
+ memset(&node_host, 0, sizeof(node_host));
+ node_host.af = af;
+ node_host.addr = addr->addr;
+
+#ifdef OPT_DEBUG
+ DEBUG("<%s> adding %s/%d", (*tbl)->pt_name, inet_ntop(af,
+ &node_host.addr.v.a.addr, buf, sizeof(buf)),
+ unmask(&node_host.addr.v.a.mask, af));
+#endif /* OPT_DEBUG */
+
+ if (append_addr_host((*tbl)->pt_buf, &node_host, 0, 0)) {
+ warn("failed to add host");
+ return (1);
+ }
+ if (pf->opts & PF_OPT_VERBOSE) {
+ struct node_tinit *ti;
+
+ if ((ti = calloc(1, sizeof(*ti))) == NULL)
+ err(1, "malloc");
+ if ((ti->host = malloc(sizeof(*ti->host))) == NULL)
+ err(1, "malloc");
+ memcpy(ti->host, &node_host, sizeof(*ti->host));
+ SIMPLEQ_INSERT_TAIL(&(*tbl)->pt_nodes, ti, entries);
+ }
+
+ (*tbl)->pt_rulecount++;
+ if ((*tbl)->pt_rulecount == TABLE_THRESHOLD)
+ DEBUG("table <%s> now faster than skip steps", (*tbl)->pt_name);
+
+ return (0);
+}
+
+
+/*
+ * Do the dirty work of choosing an unused table name and creating it.
+ * (be careful with the table name, it might already be used in another anchor)
+ */
+#ifdef __rtems__
+static int pf_opt_create_tablenum;
+#endif /* __rtems__ */
+int
+pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl)
+{
+#ifndef __rtems__
+ static int tablenum;
+#endif /* __rtems__ */
+ struct pfr_table *t;
+
+ if (table_buffer.pfrb_type == 0) {
+ /* Initialize the list of tables */
+ table_buffer.pfrb_type = PFRB_TABLES;
+ for (;;) {
+ pfr_buf_grow(&table_buffer, table_buffer.pfrb_size);
+ table_buffer.pfrb_size = table_buffer.pfrb_msize;
+ if (pfr_get_tables(NULL, table_buffer.pfrb_caddr,
+ &table_buffer.pfrb_size, PFR_FLAG_ALLRSETS))
+ err(1, "pfr_get_tables");
+ if (table_buffer.pfrb_size <= table_buffer.pfrb_msize)
+ break;
+ }
+ table_identifier = arc4random();
+ }
+
+ /* XXX would be *really* nice to avoid duplicating identical tables */
+
+ /* Now we have to pick a table name that isn't used */
+again:
+ DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name,
+#ifndef __rtems__
+ PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+#else /* __rtems__ */
+ PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_tablenum);
+#endif /* __rtems__ */
+ snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d",
+#ifndef __rtems__
+ PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+#else /* __rtems__ */
+ PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_tablenum);
+#endif /* __rtems__ */
+ PFRB_FOREACH(t, &table_buffer) {
+ if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) {
+ /* Collision. Try again */
+ DEBUG("wow, table <%s> in use. trying again",
+ tbl->pt_name);
+ table_identifier = arc4random();
+ goto again;
+ }
+ }
+#ifndef __rtems__
+ tablenum++;
+#else /* __rtems__ */
+ pf_opt_create_tablenum++;
+#endif /* __rtems__ */
+
+
+ if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1,
+ pf->astack[0]->name, tbl->pt_buf, pf->astack[0]->ruleset.tticket)) {
+ warn("failed to create table %s in %s",
+ tbl->pt_name, pf->astack[0]->name);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Partition the flat ruleset into a list of distinct superblocks
+ */
+int
+construct_superblocks(struct pfctl *pf, struct pf_opt_queue *opt_queue,
+ struct superblocks *superblocks)
+{
+ struct superblock *block = NULL;
+ struct pf_opt_rule *por;
+ int i;
+
+ while (!TAILQ_EMPTY(opt_queue)) {
+ por = TAILQ_FIRST(opt_queue);
+ TAILQ_REMOVE(opt_queue, por, por_entry);
+ if (block == NULL || !superblock_inclusive(block, por)) {
+ if ((block = calloc(1, sizeof(*block))) == NULL) {
+ warn("calloc");
+ return (1);
+ }
+ TAILQ_INIT(&block->sb_rules);
+ for (i = 0; i < PF_SKIP_COUNT; i++)
+ TAILQ_INIT(&block->sb_skipsteps[i]);
+ TAILQ_INSERT_TAIL(superblocks, block, sb_entry);
+ }
+ TAILQ_INSERT_TAIL(&block->sb_rules, por, por_entry);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Compare two rule addresses
+ */
+int
+addrs_equal(struct pf_rule_addr *a, struct pf_rule_addr *b)
+{
+ if (a->neg != b->neg)
+ return (0);
+ return (memcmp(&a->addr, &b->addr, sizeof(a->addr)) == 0);
+}
+
+
+/*
+ * The addresses are not equal, but can we combine them into one table?
+ */
+int
+addrs_combineable(struct pf_rule_addr *a, struct pf_rule_addr *b)
+{
+ if (a->addr.type != PF_ADDR_ADDRMASK ||
+ b->addr.type != PF_ADDR_ADDRMASK)
+ return (0);
+ if (a->neg != b->neg || a->port_op != b->port_op ||
+ a->port[0] != b->port[0] || a->port[1] != b->port[1])
+ return (0);
+ return (1);
+}
+
+
+/*
+ * Are we allowed to combine these two rules
+ */
+int
+rules_combineable(struct pf_rule *p1, struct pf_rule *p2)
+{
+ struct pf_rule a, b;
+
+ comparable_rule(&a, p1, COMBINED);
+ comparable_rule(&b, p2, COMBINED);
+ return (memcmp(&a, &b, sizeof(a)) == 0);
+}
+
+
+/*
+ * Can a rule be included inside a superblock
+ */
+int
+superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
+{
+ struct pf_rule a, b;
+ int i, j;
+
+ /* First check for hard breaks */
+ for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) {
+ if (pf_rule_desc[i].prf_type == BARRIER) {
+ for (j = 0; j < pf_rule_desc[i].prf_size; j++)
+ if (((char *)&por->por_rule)[j +
+ pf_rule_desc[i].prf_offset] != 0)
+ return (0);
+ }
+ }
+
+ /* per-rule src-track is also a hard break */
+ if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK)
+ return (0);
+
+ /*
+ * Have to handle interface groups separately. Consider the following
+ * rules:
+ * block on EXTIFS to any port 22
+ * pass on em0 to any port 22
+ * (where EXTIFS is an arbitrary interface group)
+ * The optimizer may decide to re-order the pass rule in front of the
+ * block rule. But what if EXTIFS includes em0??? Such a reordering
+ * would change the meaning of the ruleset.
+ * We can't just lookup the EXTIFS group and check if em0 is a member
+ * because the user is allowed to add interfaces to a group during
+ * runtime.
+ * Ergo interface groups become a defacto superblock break :-(
+ */
+ if (interface_group(por->por_rule.ifname) ||
+ interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) {
+ if (strcasecmp(por->por_rule.ifname,
+ TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0)
+ return (0);
+ }
+
+ comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE);
+ comparable_rule(&b, &por->por_rule, NOMERGE);
+ if (memcmp(&a, &b, sizeof(a)) == 0)
+ return (1);
+
+#ifdef OPT_DEBUG
+ for (i = 0; i < sizeof(por->por_rule); i++) {
+ int closest = -1;
+ if (((u_int8_t *)&a)[i] != ((u_int8_t *)&b)[i]) {
+ for (j = 0; j < sizeof(pf_rule_desc) /
+ sizeof(*pf_rule_desc); j++) {
+ if (i >= pf_rule_desc[j].prf_offset &&
+ i < pf_rule_desc[j].prf_offset +
+ pf_rule_desc[j].prf_size) {
+ DEBUG("superblock break @ %d due to %s",
+ por->por_rule.nr,
+ pf_rule_desc[j].prf_name);
+ return (0);
+ }
+ if (i > pf_rule_desc[j].prf_offset) {
+ if (closest == -1 ||
+ i-pf_rule_desc[j].prf_offset <
+ i-pf_rule_desc[closest].prf_offset)
+ closest = j;
+ }
+ }
+
+ if (closest >= 0)
+ DEBUG("superblock break @ %d on %s+%xh",
+ por->por_rule.nr,
+ pf_rule_desc[closest].prf_name,
+ i - pf_rule_desc[closest].prf_offset -
+ pf_rule_desc[closest].prf_size);
+ else
+ DEBUG("superblock break @ %d on field @ %d",
+ por->por_rule.nr, i);
+ return (0);
+ }
+ }
+#endif /* OPT_DEBUG */
+
+ return (0);
+}
+
+
+/*
+ * Figure out if an interface name is an actual interface or actually a
+ * group of interfaces.
+ */
+int
+interface_group(const char *ifname)
+{
+ if (ifname == NULL || !ifname[0])
+ return (0);
+
+ /* Real interfaces must end in a number, interface groups do not */
+ if (isdigit(ifname[strlen(ifname) - 1]))
+ return (0);
+ else
+ return (1);
+}
+
+
+/*
+ * Make a rule that can directly compared by memcmp()
+ */
+void
+comparable_rule(struct pf_rule *dst, const struct pf_rule *src, int type)
+{
+ int i;
+ /*
+ * To simplify the comparison, we just zero out the fields that are
+ * allowed to be different and then do a simple memcmp()
+ */
+ memcpy(dst, src, sizeof(*dst));
+ for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++)
+ if (pf_rule_desc[i].prf_type >= type) {
+#ifdef OPT_DEBUG
+ assert(pf_rule_desc[i].prf_type != NEVER ||
+ *(((char *)dst) + pf_rule_desc[i].prf_offset) == 0);
+#endif /* OPT_DEBUG */
+ memset(((char *)dst) + pf_rule_desc[i].prf_offset, 0,
+ pf_rule_desc[i].prf_size);
+ }
+}
+
+
+/*
+ * Remove superset information from two rules so we can directly compare them
+ * with memcmp()
+ */
+void
+exclude_supersets(struct pf_rule *super, struct pf_rule *sub)
+{
+ if (super->ifname[0] == '\0')
+ memset(sub->ifname, 0, sizeof(sub->ifname));
+ if (super->direction == PF_INOUT)
+ sub->direction = PF_INOUT;
+ if ((super->proto == 0 || super->proto == sub->proto) &&
+ super->flags == 0 && super->flagset == 0 && (sub->flags ||
+ sub->flagset)) {
+ sub->flags = super->flags;
+ sub->flagset = super->flagset;
+ }
+ if (super->proto == 0)
+ sub->proto = 0;
+
+ if (super->src.port_op == 0) {
+ sub->src.port_op = 0;
+ sub->src.port[0] = 0;
+ sub->src.port[1] = 0;
+ }
+ if (super->dst.port_op == 0) {
+ sub->dst.port_op = 0;
+ sub->dst.port[0] = 0;
+ sub->dst.port[1] = 0;
+ }
+
+ if (super->src.addr.type == PF_ADDR_ADDRMASK && !super->src.neg &&
+ !sub->src.neg && super->src.addr.v.a.mask.addr32[0] == 0 &&
+ super->src.addr.v.a.mask.addr32[1] == 0 &&
+ super->src.addr.v.a.mask.addr32[2] == 0 &&
+ super->src.addr.v.a.mask.addr32[3] == 0)
+ memset(&sub->src.addr, 0, sizeof(sub->src.addr));
+ else if (super->src.addr.type == PF_ADDR_ADDRMASK &&
+ sub->src.addr.type == PF_ADDR_ADDRMASK &&
+ super->src.neg == sub->src.neg &&
+ super->af == sub->af &&
+ unmask(&super->src.addr.v.a.mask, super->af) <
+ unmask(&sub->src.addr.v.a.mask, sub->af) &&
+ super->src.addr.v.a.addr.addr32[0] ==
+ (sub->src.addr.v.a.addr.addr32[0] &
+ super->src.addr.v.a.mask.addr32[0]) &&
+ super->src.addr.v.a.addr.addr32[1] ==
+ (sub->src.addr.v.a.addr.addr32[1] &
+ super->src.addr.v.a.mask.addr32[1]) &&
+ super->src.addr.v.a.addr.addr32[2] ==
+ (sub->src.addr.v.a.addr.addr32[2] &
+ super->src.addr.v.a.mask.addr32[2]) &&
+ super->src.addr.v.a.addr.addr32[3] ==
+ (sub->src.addr.v.a.addr.addr32[3] &
+ super->src.addr.v.a.mask.addr32[3])) {
+ /* sub->src.addr is a subset of super->src.addr/mask */
+ memcpy(&sub->src.addr, &super->src.addr, sizeof(sub->src.addr));
+ }
+
+ if (super->dst.addr.type == PF_ADDR_ADDRMASK && !super->dst.neg &&
+ !sub->dst.neg && super->dst.addr.v.a.mask.addr32[0] == 0 &&
+ super->dst.addr.v.a.mask.addr32[1] == 0 &&
+ super->dst.addr.v.a.mask.addr32[2] == 0 &&
+ super->dst.addr.v.a.mask.addr32[3] == 0)
+ memset(&sub->dst.addr, 0, sizeof(sub->dst.addr));
+ else if (super->dst.addr.type == PF_ADDR_ADDRMASK &&
+ sub->dst.addr.type == PF_ADDR_ADDRMASK &&
+ super->dst.neg == sub->dst.neg &&
+ super->af == sub->af &&
+ unmask(&super->dst.addr.v.a.mask, super->af) <
+ unmask(&sub->dst.addr.v.a.mask, sub->af) &&
+ super->dst.addr.v.a.addr.addr32[0] ==
+ (sub->dst.addr.v.a.addr.addr32[0] &
+ super->dst.addr.v.a.mask.addr32[0]) &&
+ super->dst.addr.v.a.addr.addr32[1] ==
+ (sub->dst.addr.v.a.addr.addr32[1] &
+ super->dst.addr.v.a.mask.addr32[1]) &&
+ super->dst.addr.v.a.addr.addr32[2] ==
+ (sub->dst.addr.v.a.addr.addr32[2] &
+ super->dst.addr.v.a.mask.addr32[2]) &&
+ super->dst.addr.v.a.addr.addr32[3] ==
+ (sub->dst.addr.v.a.addr.addr32[3] &
+ super->dst.addr.v.a.mask.addr32[3])) {
+ /* sub->dst.addr is a subset of super->dst.addr/mask */
+ memcpy(&sub->dst.addr, &super->dst.addr, sizeof(sub->dst.addr));
+ }
+
+ if (super->af == 0)
+ sub->af = 0;
+}
+
+
+void
+superblock_free(struct pfctl *pf, struct superblock *block)
+{
+ struct pf_opt_rule *por;
+ while ((por = TAILQ_FIRST(&block->sb_rules))) {
+ TAILQ_REMOVE(&block->sb_rules, por, por_entry);
+ if (por->por_src_tbl) {
+ if (por->por_src_tbl->pt_buf) {
+ pfr_buf_clear(por->por_src_tbl->pt_buf);
+ free(por->por_src_tbl->pt_buf);
+ }
+ free(por->por_src_tbl);
+ }
+ if (por->por_dst_tbl) {
+ if (por->por_dst_tbl->pt_buf) {
+ pfr_buf_clear(por->por_dst_tbl->pt_buf);
+ free(por->por_dst_tbl->pt_buf);
+ }
+ free(por->por_dst_tbl);
+ }
+ free(por);
+ }
+ if (block->sb_profiled_block)
+ superblock_free(pf, block->sb_profiled_block);
+ free(block);
+}
+
diff --git a/freebsd/sbin/pfctl/pfctl_osfp.c b/freebsd/sbin/pfctl/pfctl_osfp.c
new file mode 100644
index 00000000..dd672623
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_osfp.c
@@ -0,0 +1,1123 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */
+
+/*
+ * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_osfp-data.h"
+#endif /* __rtems__ */
+
+#ifndef MIN
+# define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+#ifndef MAX
+# define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* MAX */
+
+
+#if 0
+# define DEBUG(fp, str, v...) \
+ fprintf(stderr, "%s:%s:%s " str "\n", (fp)->fp_os.fp_class_nm, \
+ (fp)->fp_os.fp_version_nm, (fp)->fp_os.fp_subtype_nm , ## v);
+#else
+# define DEBUG(fp, str, v...) ((void)0)
+#endif
+
+
+struct name_entry;
+LIST_HEAD(name_list, name_entry);
+struct name_entry {
+ LIST_ENTRY(name_entry) nm_entry;
+ int nm_num;
+ char nm_name[PF_OSFP_LEN];
+
+ struct name_list nm_sublist;
+ int nm_sublist_num;
+};
+static struct name_list classes = LIST_HEAD_INITIALIZER(&classes);
+static int class_count;
+static int fingerprint_count;
+
+void add_fingerprint(int, int, struct pf_osfp_ioctl *);
+struct name_entry *fingerprint_name_entry(struct name_list *, char *);
+void pfctl_flush_my_fingerprints(struct name_list *);
+char *get_field(char **, size_t *, int *);
+int get_int(char **, size_t *, int *, int *, const char *,
+ int, int, const char *, int);
+int get_str(char **, size_t *, char **, const char *, int,
+ const char *, int);
+int get_tcpopts(const char *, int, const char *,
+ pf_tcpopts_t *, int *, int *, int *, int *, int *,
+ int *);
+void import_fingerprint(struct pf_osfp_ioctl *);
+const char *print_ioctl(struct pf_osfp_ioctl *);
+void print_name_list(int, struct name_list *, const char *);
+void sort_name_list(int, struct name_list *);
+struct name_entry *lookup_name_list(struct name_list *, const char *);
+
+/* Load fingerprints from a file */
+int
+pfctl_file_fingerprints(int dev, int opts, const char *fp_filename)
+{
+ FILE *in;
+ char *line;
+ size_t len;
+ int i, lineno = 0;
+ int window, w_mod, ttl, df, psize, p_mod, mss, mss_mod, wscale,
+ wscale_mod, optcnt, ts0;
+ pf_tcpopts_t packed_tcpopts;
+ char *class, *version, *subtype, *desc, *tcpopts;
+ struct pf_osfp_ioctl fp;
+
+ pfctl_flush_my_fingerprints(&classes);
+
+ if ((in = pfctl_fopen(fp_filename, "r")) == NULL) {
+ warn("%s", fp_filename);
+ return (1);
+ }
+ class = version = subtype = desc = tcpopts = NULL;
+
+ if ((opts & PF_OPT_NOACTION) == 0)
+ pfctl_clear_fingerprints(dev, opts);
+
+ while ((line = fgetln(in, &len)) != NULL) {
+ lineno++;
+ if (class)
+ free(class);
+ if (version)
+ free(version);
+ if (subtype)
+ free(subtype);
+ if (desc)
+ free(desc);
+ if (tcpopts)
+ free(tcpopts);
+ class = version = subtype = desc = tcpopts = NULL;
+ memset(&fp, 0, sizeof(fp));
+
+ /* Chop off comment */
+ for (i = 0; i < len; i++)
+ if (line[i] == '#') {
+ len = i;
+ break;
+ }
+ /* Chop off whitespace */
+ while (len > 0 && isspace(line[len - 1]))
+ len--;
+ while (len > 0 && isspace(line[0])) {
+ len--;
+ line++;
+ }
+ if (len == 0)
+ continue;
+
+#define T_DC 0x01 /* Allow don't care */
+#define T_MSS 0x02 /* Allow MSS multiple */
+#define T_MTU 0x04 /* Allow MTU multiple */
+#define T_MOD 0x08 /* Allow modulus */
+
+#define GET_INT(v, mod, n, ty, mx) \
+ get_int(&line, &len, &v, mod, n, ty, mx, fp_filename, lineno)
+#define GET_STR(v, n, mn) \
+ get_str(&line, &len, &v, n, mn, fp_filename, lineno)
+
+ if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU|
+ T_MOD, 0xffff) ||
+ GET_INT(ttl, NULL, "ttl", 0, 0xff) ||
+ GET_INT(df, NULL, "don't fragment frag", 0, 1) ||
+ GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC,
+ 8192) ||
+ GET_STR(tcpopts, "TCP Options", 1) ||
+ GET_STR(class, "OS class", 1) ||
+ GET_STR(version, "OS version", 0) ||
+ GET_STR(subtype, "OS subtype", 0) ||
+ GET_STR(desc, "OS description", 2))
+ continue;
+ if (get_tcpopts(fp_filename, lineno, tcpopts, &packed_tcpopts,
+ &optcnt, &mss, &mss_mod, &wscale, &wscale_mod, &ts0))
+ continue;
+ if (len != 0) {
+ fprintf(stderr, "%s:%d excess field\n", fp_filename,
+ lineno);
+ continue;
+ }
+
+ fp.fp_ttl = ttl;
+ if (df)
+ fp.fp_flags |= PF_OSFP_DF;
+ switch (w_mod) {
+ case 0:
+ break;
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_WSIZE_DC;
+ break;
+ case T_MSS:
+ fp.fp_flags |= PF_OSFP_WSIZE_MSS;
+ break;
+ case T_MTU:
+ fp.fp_flags |= PF_OSFP_WSIZE_MTU;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_WSIZE_MOD;
+ break;
+ }
+ fp.fp_wsize = window;
+
+ switch (p_mod) {
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_PSIZE_DC;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_PSIZE_MOD;
+ }
+ fp.fp_psize = psize;
+
+
+ switch (wscale_mod) {
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_WSCALE_DC;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_WSCALE_MOD;
+ }
+ fp.fp_wscale = wscale;
+
+ switch (mss_mod) {
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_MSS_DC;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_MSS_MOD;
+ break;
+ }
+ fp.fp_mss = mss;
+
+ fp.fp_tcpopts = packed_tcpopts;
+ fp.fp_optcnt = optcnt;
+ if (ts0)
+ fp.fp_flags |= PF_OSFP_TS0;
+
+ if (class[0] == '@')
+ fp.fp_os.fp_enflags |= PF_OSFP_GENERIC;
+ if (class[0] == '*')
+ fp.fp_os.fp_enflags |= PF_OSFP_NODETAIL;
+
+ if (class[0] == '@' || class[0] == '*')
+ strlcpy(fp.fp_os.fp_class_nm, class + 1,
+ sizeof(fp.fp_os.fp_class_nm));
+ else
+ strlcpy(fp.fp_os.fp_class_nm, class,
+ sizeof(fp.fp_os.fp_class_nm));
+ strlcpy(fp.fp_os.fp_version_nm, version,
+ sizeof(fp.fp_os.fp_version_nm));
+ strlcpy(fp.fp_os.fp_subtype_nm, subtype,
+ sizeof(fp.fp_os.fp_subtype_nm));
+
+ add_fingerprint(dev, opts, &fp);
+
+ fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6);
+ fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip);
+ add_fingerprint(dev, opts, &fp);
+ }
+
+ if (class)
+ free(class);
+ if (version)
+ free(version);
+ if (subtype)
+ free(subtype);
+ if (desc)
+ free(desc);
+ if (tcpopts)
+ free(tcpopts);
+
+ fclose(in);
+
+ if (opts & PF_OPT_VERBOSE2)
+ printf("Loaded %d passive OS fingerprints\n",
+ fingerprint_count);
+ return (0);
+}
+
+/* flush the kernel's fingerprints */
+void
+pfctl_clear_fingerprints(int dev, int opts)
+{
+ if (ioctl(dev, DIOCOSFPFLUSH))
+ err(1, "DIOCOSFPFLUSH");
+}
+
+/* flush pfctl's view of the fingerprints */
+void
+pfctl_flush_my_fingerprints(struct name_list *list)
+{
+ struct name_entry *nm;
+
+ while ((nm = LIST_FIRST(list)) != NULL) {
+ LIST_REMOVE(nm, nm_entry);
+ pfctl_flush_my_fingerprints(&nm->nm_sublist);
+ free(nm);
+ }
+ fingerprint_count = 0;
+ class_count = 0;
+}
+
+/* Fetch the active fingerprints from the kernel */
+int
+pfctl_load_fingerprints(int dev, int opts)
+{
+ struct pf_osfp_ioctl io;
+ int i;
+
+ pfctl_flush_my_fingerprints(&classes);
+
+ for (i = 0; i >= 0; i++) {
+ memset(&io, 0, sizeof(io));
+ io.fp_getnum = i;
+ if (ioctl(dev, DIOCOSFPGET, &io)) {
+ if (errno == EBUSY)
+ break;
+ warn("DIOCOSFPGET");
+ return (1);
+ }
+ import_fingerprint(&io);
+ }
+ return (0);
+}
+
+/* List the fingerprints */
+void
+pfctl_show_fingerprints(int opts)
+{
+ if (LIST_FIRST(&classes) != NULL) {
+ if (opts & PF_OPT_SHOWALL) {
+ pfctl_print_title("OS FINGERPRINTS:");
+ printf("%u fingerprints loaded\n", fingerprint_count);
+ } else {
+ printf("Class\tVersion\tSubtype(subversion)\n");
+ printf("-----\t-------\t-------------------\n");
+ sort_name_list(opts, &classes);
+ print_name_list(opts, &classes, "");
+ }
+ }
+}
+
+/* Lookup a fingerprint */
+pf_osfp_t
+pfctl_get_fingerprint(const char *name)
+{
+ struct name_entry *nm, *class_nm, *version_nm, *subtype_nm;
+ pf_osfp_t ret = PF_OSFP_NOMATCH;
+ int class, version, subtype;
+ int unp_class, unp_version, unp_subtype;
+ int wr_len, version_len, subtype_len;
+ char *ptr, *wr_name;
+
+ if (strcasecmp(name, "unknown") == 0)
+ return (PF_OSFP_UNKNOWN);
+
+ /* Try most likely no version and no subtype */
+ if ((nm = lookup_name_list(&classes, name))) {
+ class = nm->nm_num;
+ version = PF_OSFP_ANY;
+ subtype = PF_OSFP_ANY;
+ goto found;
+ } else {
+
+ /* Chop it up into class/version/subtype */
+
+ if ((wr_name = strdup(name)) == NULL)
+ err(1, "malloc");
+ if ((ptr = strchr(wr_name, ' ')) == NULL) {
+ free(wr_name);
+ return (PF_OSFP_NOMATCH);
+ }
+ *ptr++ = '\0';
+
+ /* The class is easy to find since it is delimited by a space */
+ if ((class_nm = lookup_name_list(&classes, wr_name)) == NULL) {
+ free(wr_name);
+ return (PF_OSFP_NOMATCH);
+ }
+ class = class_nm->nm_num;
+
+ /* Try no subtype */
+ if ((version_nm = lookup_name_list(&class_nm->nm_sublist, ptr)))
+ {
+ version = version_nm->nm_num;
+ subtype = PF_OSFP_ANY;
+ free(wr_name);
+ goto found;
+ }
+
+
+ /*
+ * There must be a version and a subtype.
+ * We'll do some fuzzy matching to pick up things like:
+ * Linux 2.2.14 (version=2.2 subtype=14)
+ * FreeBSD 4.0-STABLE (version=4.0 subtype=STABLE)
+ * Windows 2000 SP2 (version=2000 subtype=SP2)
+ */
+#define CONNECTOR(x) ((x) == '.' || (x) == ' ' || (x) == '\t' || (x) == '-')
+ wr_len = strlen(ptr);
+ LIST_FOREACH(version_nm, &class_nm->nm_sublist, nm_entry) {
+ version_len = strlen(version_nm->nm_name);
+ if (wr_len < version_len + 2 ||
+ !CONNECTOR(ptr[version_len]))
+ continue;
+ /* first part of the string must be version */
+ if (strncasecmp(ptr, version_nm->nm_name,
+ version_len))
+ continue;
+
+ LIST_FOREACH(subtype_nm, &version_nm->nm_sublist,
+ nm_entry) {
+ subtype_len = strlen(subtype_nm->nm_name);
+ if (wr_len != version_len + subtype_len + 1)
+ continue;
+
+ /* last part of the string must be subtype */
+ if (strcasecmp(&ptr[version_len+1],
+ subtype_nm->nm_name) != 0)
+ continue;
+
+ /* Found it!! */
+ version = version_nm->nm_num;
+ subtype = subtype_nm->nm_num;
+ free(wr_name);
+ goto found;
+ }
+ }
+
+ free(wr_name);
+ return (PF_OSFP_NOMATCH);
+ }
+
+found:
+ PF_OSFP_PACK(ret, class, version, subtype);
+ if (ret != PF_OSFP_NOMATCH) {
+ PF_OSFP_UNPACK(ret, unp_class, unp_version, unp_subtype);
+ if (class != unp_class) {
+ fprintf(stderr, "warning: fingerprint table overflowed "
+ "classes\n");
+ return (PF_OSFP_NOMATCH);
+ }
+ if (version != unp_version) {
+ fprintf(stderr, "warning: fingerprint table overflowed "
+ "versions\n");
+ return (PF_OSFP_NOMATCH);
+ }
+ if (subtype != unp_subtype) {
+ fprintf(stderr, "warning: fingerprint table overflowed "
+ "subtypes\n");
+ return (PF_OSFP_NOMATCH);
+ }
+ }
+ if (ret == PF_OSFP_ANY) {
+ /* should never happen */
+ fprintf(stderr, "warning: fingerprint packed to 'any'\n");
+ return (PF_OSFP_NOMATCH);
+ }
+
+ return (ret);
+}
+
+/* Lookup a fingerprint name by ID */
+char *
+pfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len)
+{
+ int class, version, subtype;
+ struct name_list *list;
+ struct name_entry *nm;
+
+ char *class_name, *version_name, *subtype_name;
+ class_name = version_name = subtype_name = NULL;
+
+ if (fp == PF_OSFP_UNKNOWN) {
+ strlcpy(buf, "unknown", len);
+ return (buf);
+ }
+ if (fp == PF_OSFP_ANY) {
+ strlcpy(buf, "any", len);
+ return (buf);
+ }
+
+ PF_OSFP_UNPACK(fp, class, version, subtype);
+ if (class >= (1 << _FP_CLASS_BITS) ||
+ version >= (1 << _FP_VERSION_BITS) ||
+ subtype >= (1 << _FP_SUBTYPE_BITS)) {
+ warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp);
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+ }
+
+ LIST_FOREACH(nm, &classes, nm_entry) {
+ if (nm->nm_num == class) {
+ class_name = nm->nm_name;
+ if (version == PF_OSFP_ANY)
+ goto found;
+ list = &nm->nm_sublist;
+ LIST_FOREACH(nm, list, nm_entry) {
+ if (nm->nm_num == version) {
+ version_name = nm->nm_name;
+ if (subtype == PF_OSFP_ANY)
+ goto found;
+ list = &nm->nm_sublist;
+ LIST_FOREACH(nm, list, nm_entry) {
+ if (nm->nm_num == subtype) {
+ subtype_name =
+ nm->nm_name;
+ goto found;
+ }
+ } /* foreach subtype */
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+ }
+ } /* foreach version */
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+ }
+ } /* foreach class */
+
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+
+found:
+ snprintf(buf, len, "%s", class_name);
+ if (version_name) {
+ strlcat(buf, " ", len);
+ strlcat(buf, version_name, len);
+ if (subtype_name) {
+ if (strchr(version_name, ' '))
+ strlcat(buf, " ", len);
+ else if (strchr(version_name, '.') &&
+ isdigit(*subtype_name))
+ strlcat(buf, ".", len);
+ else
+ strlcat(buf, " ", len);
+ strlcat(buf, subtype_name, len);
+ }
+ }
+ return (buf);
+}
+
+/* lookup a name in a list */
+struct name_entry *
+lookup_name_list(struct name_list *list, const char *name)
+{
+ struct name_entry *nm;
+ LIST_FOREACH(nm, list, nm_entry)
+ if (strcasecmp(name, nm->nm_name) == 0)
+ return (nm);
+
+ return (NULL);
+}
+
+
+void
+add_fingerprint(int dev, int opts, struct pf_osfp_ioctl *fp)
+{
+ struct pf_osfp_ioctl fptmp;
+ struct name_entry *nm_class, *nm_version, *nm_subtype;
+ int class, version, subtype;
+
+/* We expand #-# or #.#-#.# version/subtypes into multiple fingerprints */
+#define EXPAND(field) do { \
+ int _dot = -1, _start = -1, _end = -1, _i = 0; \
+ /* pick major version out of #.# */ \
+ if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.') { \
+ _dot = fp->field[_i] - '0'; \
+ _i += 2; \
+ } \
+ if (isdigit(fp->field[_i])) \
+ _start = fp->field[_i++] - '0'; \
+ else \
+ break; \
+ if (isdigit(fp->field[_i])) \
+ _start = (_start * 10) + fp->field[_i++] - '0'; \
+ if (fp->field[_i++] != '-') \
+ break; \
+ if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.' && \
+ fp->field[_i] - '0' == _dot) \
+ _i += 2; \
+ else if (_dot != -1) \
+ break; \
+ if (isdigit(fp->field[_i])) \
+ _end = fp->field[_i++] - '0'; \
+ else \
+ break; \
+ if (isdigit(fp->field[_i])) \
+ _end = (_end * 10) + fp->field[_i++] - '0'; \
+ if (isdigit(fp->field[_i])) \
+ _end = (_end * 10) + fp->field[_i++] - '0'; \
+ if (fp->field[_i] != '\0') \
+ break; \
+ memcpy(&fptmp, fp, sizeof(fptmp)); \
+ for (;_start <= _end; _start++) { \
+ memset(fptmp.field, 0, sizeof(fptmp.field)); \
+ fptmp.fp_os.fp_enflags |= PF_OSFP_EXPANDED; \
+ if (_dot == -1) \
+ snprintf(fptmp.field, sizeof(fptmp.field), \
+ "%d", _start); \
+ else \
+ snprintf(fptmp.field, sizeof(fptmp.field), \
+ "%d.%d", _dot, _start); \
+ add_fingerprint(dev, opts, &fptmp); \
+ } \
+} while(0)
+
+ /* We allow "#-#" as a version or subtype and we'll expand it */
+ EXPAND(fp_os.fp_version_nm);
+ EXPAND(fp_os.fp_subtype_nm);
+
+ if (strcasecmp(fp->fp_os.fp_class_nm, "nomatch") == 0)
+ errx(1, "fingerprint class \"nomatch\" is reserved");
+
+ version = PF_OSFP_ANY;
+ subtype = PF_OSFP_ANY;
+
+ nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm);
+ if (nm_class->nm_num == 0)
+ nm_class->nm_num = ++class_count;
+ class = nm_class->nm_num;
+
+ nm_version = fingerprint_name_entry(&nm_class->nm_sublist,
+ fp->fp_os.fp_version_nm);
+ if (nm_version) {
+ if (nm_version->nm_num == 0)
+ nm_version->nm_num = ++nm_class->nm_sublist_num;
+ version = nm_version->nm_num;
+ nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist,
+ fp->fp_os.fp_subtype_nm);
+ if (nm_subtype) {
+ if (nm_subtype->nm_num == 0)
+ nm_subtype->nm_num =
+ ++nm_version->nm_sublist_num;
+ subtype = nm_subtype->nm_num;
+ }
+ }
+
+
+ DEBUG(fp, "\tsignature %d:%d:%d %s", class, version, subtype,
+ print_ioctl(fp));
+
+ PF_OSFP_PACK(fp->fp_os.fp_os, class, version, subtype);
+ fingerprint_count++;
+
+#ifdef FAKE_PF_KERNEL
+ /* Linked to the sys/net/pf_osfp.c. Call pf_osfp_add() */
+ if ((errno = pf_osfp_add(fp)))
+#else
+ if ((opts & PF_OPT_NOACTION) == 0 && ioctl(dev, DIOCOSFPADD, fp))
+#endif /* FAKE_PF_KERNEL */
+ {
+ if (errno == EEXIST) {
+ warn("Duplicate signature for %s %s %s",
+ fp->fp_os.fp_class_nm,
+ fp->fp_os.fp_version_nm,
+ fp->fp_os.fp_subtype_nm);
+
+ } else {
+ err(1, "DIOCOSFPADD");
+ }
+ }
+}
+
+/* import a fingerprint from the kernel */
+void
+import_fingerprint(struct pf_osfp_ioctl *fp)
+{
+ struct name_entry *nm_class, *nm_version, *nm_subtype;
+ int class, version, subtype;
+
+ PF_OSFP_UNPACK(fp->fp_os.fp_os, class, version, subtype);
+
+ nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm);
+ if (nm_class->nm_num == 0) {
+ nm_class->nm_num = class;
+ class_count = MAX(class_count, class);
+ }
+
+ nm_version = fingerprint_name_entry(&nm_class->nm_sublist,
+ fp->fp_os.fp_version_nm);
+ if (nm_version) {
+ if (nm_version->nm_num == 0) {
+ nm_version->nm_num = version;
+ nm_class->nm_sublist_num = MAX(nm_class->nm_sublist_num,
+ version);
+ }
+ nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist,
+ fp->fp_os.fp_subtype_nm);
+ if (nm_subtype) {
+ if (nm_subtype->nm_num == 0) {
+ nm_subtype->nm_num = subtype;
+ nm_version->nm_sublist_num =
+ MAX(nm_version->nm_sublist_num, subtype);
+ }
+ }
+ }
+
+
+ fingerprint_count++;
+ DEBUG(fp, "import signature %d:%d:%d", class, version, subtype);
+}
+
+/* Find an entry for a fingerprints class/version/subtype */
+struct name_entry *
+fingerprint_name_entry(struct name_list *list, char *name)
+{
+ struct name_entry *nm_entry;
+
+ if (name == NULL || strlen(name) == 0)
+ return (NULL);
+
+ LIST_FOREACH(nm_entry, list, nm_entry) {
+ if (strcasecmp(nm_entry->nm_name, name) == 0) {
+ /* We'll move this to the front of the list later */
+ LIST_REMOVE(nm_entry, nm_entry);
+ break;
+ }
+ }
+ if (nm_entry == NULL) {
+ nm_entry = calloc(1, sizeof(*nm_entry));
+ if (nm_entry == NULL)
+ err(1, "calloc");
+ LIST_INIT(&nm_entry->nm_sublist);
+ strlcpy(nm_entry->nm_name, name, sizeof(nm_entry->nm_name));
+ }
+ LIST_INSERT_HEAD(list, nm_entry, nm_entry);
+ return (nm_entry);
+}
+
+
+void
+print_name_list(int opts, struct name_list *nml, const char *prefix)
+{
+ char newprefix[32];
+ struct name_entry *nm;
+
+ LIST_FOREACH(nm, nml, nm_entry) {
+ snprintf(newprefix, sizeof(newprefix), "%s%s\t", prefix,
+ nm->nm_name);
+ printf("%s\n", newprefix);
+ print_name_list(opts, &nm->nm_sublist, newprefix);
+ }
+}
+
+void
+sort_name_list(int opts, struct name_list *nml)
+{
+ struct name_list new;
+ struct name_entry *nm, *nmsearch, *nmlast;
+
+ /* yes yes, it's a very slow sort. so sue me */
+
+ LIST_INIT(&new);
+
+ while ((nm = LIST_FIRST(nml)) != NULL) {
+ LIST_REMOVE(nm, nm_entry);
+ nmlast = NULL;
+ LIST_FOREACH(nmsearch, &new, nm_entry) {
+ if (strcasecmp(nmsearch->nm_name, nm->nm_name) > 0) {
+ LIST_INSERT_BEFORE(nmsearch, nm, nm_entry);
+ break;
+ }
+ nmlast = nmsearch;
+ }
+ if (nmsearch == NULL) {
+ if (nmlast)
+ LIST_INSERT_AFTER(nmlast, nm, nm_entry);
+ else
+ LIST_INSERT_HEAD(&new, nm, nm_entry);
+ }
+
+ sort_name_list(opts, &nm->nm_sublist);
+ }
+ nmlast = NULL;
+ while ((nm = LIST_FIRST(&new)) != NULL) {
+ LIST_REMOVE(nm, nm_entry);
+ if (nmlast == NULL)
+ LIST_INSERT_HEAD(nml, nm, nm_entry);
+ else
+ LIST_INSERT_AFTER(nmlast, nm, nm_entry);
+ nmlast = nm;
+ }
+}
+
+/* parse the next integer in a formatted config file line */
+int
+get_int(char **line, size_t *len, int *var, int *mod,
+ const char *name, int flags, int max, const char *filename, int lineno)
+{
+ int fieldlen, i;
+ char *field;
+ long val = 0;
+
+ if (mod)
+ *mod = 0;
+ *var = 0;
+
+ field = get_field(line, len, &fieldlen);
+ if (field == NULL)
+ return (1);
+ if (fieldlen == 0) {
+ fprintf(stderr, "%s:%d empty %s\n", filename, lineno, name);
+ return (1);
+ }
+
+ i = 0;
+ if ((*field == '%' || *field == 'S' || *field == 'T' || *field == '*')
+ && fieldlen >= 1) {
+ switch (*field) {
+ case 'S':
+ if (mod && (flags & T_MSS))
+ *mod = T_MSS;
+ if (fieldlen == 1)
+ return (0);
+ break;
+ case 'T':
+ if (mod && (flags & T_MTU))
+ *mod = T_MTU;
+ if (fieldlen == 1)
+ return (0);
+ break;
+ case '*':
+ if (fieldlen != 1) {
+ fprintf(stderr, "%s:%d long '%c' %s\n",
+ filename, lineno, *field, name);
+ return (1);
+ }
+ if (mod && (flags & T_DC)) {
+ *mod = T_DC;
+ return (0);
+ }
+ case '%':
+ if (mod && (flags & T_MOD))
+ *mod = T_MOD;
+ if (fieldlen == 1) {
+ fprintf(stderr, "%s:%d modulus %s must have a "
+ "value\n", filename, lineno, name);
+ return (1);
+ }
+ break;
+ }
+ if (mod == NULL || *mod == 0) {
+ fprintf(stderr, "%s:%d does not allow %c' %s\n",
+ filename, lineno, *field, name);
+ return (1);
+ }
+ i++;
+ }
+
+ for (; i < fieldlen; i++) {
+ if (field[i] < '0' || field[i] > '9') {
+ fprintf(stderr, "%s:%d non-digit character in %s\n",
+ filename, lineno, name);
+ return (1);
+ }
+ val = val * 10 + field[i] - '0';
+ if (val < 0) {
+ fprintf(stderr, "%s:%d %s overflowed\n", filename,
+ lineno, name);
+ return (1);
+ }
+ }
+
+ if (val > max) {
+ fprintf(stderr, "%s:%d %s value %ld > %d\n", filename, lineno,
+ name, val, max);
+ return (1);
+ }
+ *var = (int)val;
+
+ return (0);
+}
+
+/* parse the next string in a formatted config file line */
+int
+get_str(char **line, size_t *len, char **v, const char *name, int minlen,
+ const char *filename, int lineno)
+{
+ int fieldlen;
+ char *ptr;
+
+ ptr = get_field(line, len, &fieldlen);
+ if (ptr == NULL)
+ return (1);
+ if (fieldlen < minlen) {
+ fprintf(stderr, "%s:%d too short %s\n", filename, lineno, name);
+ return (1);
+ }
+ if ((*v = malloc(fieldlen + 1)) == NULL) {
+ perror("malloc()");
+ return (1);
+ }
+ memcpy(*v, ptr, fieldlen);
+ (*v)[fieldlen] = '\0';
+
+ return (0);
+}
+
+/* Parse out the TCP opts */
+int
+get_tcpopts(const char *filename, int lineno, const char *tcpopts,
+ pf_tcpopts_t *packed, int *optcnt, int *mss, int *mss_mod, int *wscale,
+ int *wscale_mod, int *ts0)
+{
+ int i, opt;
+
+ *packed = 0;
+ *optcnt = 0;
+ *wscale = 0;
+ *wscale_mod = T_DC;
+ *mss = 0;
+ *mss_mod = T_DC;
+ *ts0 = 0;
+ if (strcmp(tcpopts, ".") == 0)
+ return (0);
+
+ for (i = 0; tcpopts[i] && *optcnt < PF_OSFP_MAX_OPTS;) {
+ switch ((opt = toupper(tcpopts[i++]))) {
+ case 'N': /* FALLTHROUGH */
+ case 'S':
+ *packed = (*packed << PF_OSFP_TCPOPT_BITS) |
+ (opt == 'N' ? PF_OSFP_TCPOPT_NOP :
+ PF_OSFP_TCPOPT_SACK);
+ break;
+ case 'W': /* FALLTHROUGH */
+ case 'M': {
+ int *this_mod, *this;
+
+ if (opt == 'W') {
+ this = wscale;
+ this_mod = wscale_mod;
+ } else {
+ this = mss;
+ this_mod = mss_mod;
+ }
+ *this = 0;
+ *this_mod = 0;
+
+ *packed = (*packed << PF_OSFP_TCPOPT_BITS) |
+ (opt == 'W' ? PF_OSFP_TCPOPT_WSCALE :
+ PF_OSFP_TCPOPT_MSS);
+ if (tcpopts[i] == '*' && (tcpopts[i + 1] == '\0' ||
+ tcpopts[i + 1] == ',')) {
+ *this_mod = T_DC;
+ i++;
+ break;
+ }
+
+ if (tcpopts[i] == '%') {
+ *this_mod = T_MOD;
+ i++;
+ }
+ do {
+ if (!isdigit(tcpopts[i])) {
+ fprintf(stderr, "%s:%d unknown "
+ "character '%c' in %c TCP opt\n",
+ filename, lineno, tcpopts[i], opt);
+ return (1);
+ }
+ *this = (*this * 10) + tcpopts[i++] - '0';
+ } while(tcpopts[i] != ',' && tcpopts[i] != '\0');
+ break;
+ }
+ case 'T':
+ if (tcpopts[i] == '0') {
+ *ts0 = 1;
+ i++;
+ }
+ *packed = (*packed << PF_OSFP_TCPOPT_BITS) |
+ PF_OSFP_TCPOPT_TS;
+ break;
+ }
+ (*optcnt) ++;
+ if (tcpopts[i] == '\0')
+ break;
+ if (tcpopts[i] != ',') {
+ fprintf(stderr, "%s:%d unknown option to %c TCP opt\n",
+ filename, lineno, opt);
+ return (1);
+ }
+ i++;
+ }
+
+ return (0);
+}
+
+/* rip the next field ouf of a formatted config file line */
+char *
+get_field(char **line, size_t *len, int *fieldlen)
+{
+ char *ret, *ptr = *line;
+ size_t plen = *len;
+
+
+ while (plen && isspace(*ptr)) {
+ plen--;
+ ptr++;
+ }
+ ret = ptr;
+ *fieldlen = 0;
+
+ for (; plen > 0 && *ptr != ':'; plen--, ptr++)
+ (*fieldlen)++;
+ if (plen) {
+ *line = ptr + 1;
+ *len = plen - 1;
+ } else {
+ *len = 0;
+ }
+ while (*fieldlen && isspace(ret[*fieldlen - 1]))
+ (*fieldlen)--;
+ return (ret);
+}
+
+
+const char *
+print_ioctl(struct pf_osfp_ioctl *fp)
+{
+ static char buf[1024];
+ char tmp[32];
+ int i, opt;
+
+ *buf = '\0';
+ if (fp->fp_flags & PF_OSFP_WSIZE_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else if (fp->fp_flags & PF_OSFP_WSIZE_MSS)
+ strlcat(buf, "S", sizeof(buf));
+ else if (fp->fp_flags & PF_OSFP_WSIZE_MTU)
+ strlcat(buf, "T", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_WSIZE_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_wsize);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ strlcat(buf, ":", sizeof(buf));
+
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_ttl);
+ strlcat(buf, tmp, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+
+ if (fp->fp_flags & PF_OSFP_DF)
+ strlcat(buf, "1", sizeof(buf));
+ else
+ strlcat(buf, "0", sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+
+ if (fp->fp_flags & PF_OSFP_PSIZE_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_PSIZE_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_psize);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ strlcat(buf, ":", sizeof(buf));
+
+ if (fp->fp_optcnt == 0)
+ strlcat(buf, ".", sizeof(buf));
+ for (i = fp->fp_optcnt - 1; i >= 0; i--) {
+ opt = fp->fp_tcpopts >> (i * PF_OSFP_TCPOPT_BITS);
+ opt &= (1 << PF_OSFP_TCPOPT_BITS) - 1;
+ switch (opt) {
+ case PF_OSFP_TCPOPT_NOP:
+ strlcat(buf, "N", sizeof(buf));
+ break;
+ case PF_OSFP_TCPOPT_SACK:
+ strlcat(buf, "S", sizeof(buf));
+ break;
+ case PF_OSFP_TCPOPT_TS:
+ strlcat(buf, "T", sizeof(buf));
+ if (fp->fp_flags & PF_OSFP_TS0)
+ strlcat(buf, "0", sizeof(buf));
+ break;
+ case PF_OSFP_TCPOPT_MSS:
+ strlcat(buf, "M", sizeof(buf));
+ if (fp->fp_flags & PF_OSFP_MSS_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_MSS_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_mss);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ break;
+ case PF_OSFP_TCPOPT_WSCALE:
+ strlcat(buf, "W", sizeof(buf));
+ if (fp->fp_flags & PF_OSFP_WSCALE_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_WSCALE_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_wscale);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ break;
+ }
+
+ if (i != 0)
+ strlcat(buf, ",", sizeof(buf));
+ }
+ strlcat(buf, ":", sizeof(buf));
+
+ strlcat(buf, fp->fp_os.fp_class_nm, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+ strlcat(buf, fp->fp_os.fp_version_nm, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+ strlcat(buf, fp->fp_os.fp_subtype_nm, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+
+ snprintf(tmp, sizeof(tmp), "TcpOpts %d 0x%llx", fp->fp_optcnt,
+ (long long int)fp->fp_tcpopts);
+ strlcat(buf, tmp, sizeof(buf));
+
+ return (buf);
+}
diff --git a/freebsd/sbin/pfctl/pfctl_parser.c b/freebsd/sbin/pfctl/pfctl_parser.c
new file mode 100644
index 00000000..0ff7deec
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_parser.c
@@ -0,0 +1,1780 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * Copyright (c) 2002,2003 Henning Brauer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/proc.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <err.h>
+#include <ifaddrs.h>
+#include <unistd.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_parser-data.h"
+#endif /* __rtems__ */
+
+void print_op (u_int8_t, const char *, const char *);
+void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int);
+void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
+void print_flags (u_int8_t);
+void print_fromto(struct pf_rule_addr *, pf_osfp_t,
+ struct pf_rule_addr *, u_int8_t, u_int8_t, int, int);
+int ifa_skip_if(const char *filter, struct node_host *p);
+
+struct node_host *ifa_grouplookup(const char *, int);
+struct node_host *host_if(const char *, int);
+struct node_host *host_v4(const char *, int);
+struct node_host *host_v6(const char *, int);
+struct node_host *host_dns(const char *, int, int);
+
+const char * const tcpflags = "FSRPAUEW";
+
+static const struct icmptypeent icmp_type[] = {
+ { "echoreq", ICMP_ECHO },
+ { "echorep", ICMP_ECHOREPLY },
+ { "unreach", ICMP_UNREACH },
+ { "squench", ICMP_SOURCEQUENCH },
+ { "redir", ICMP_REDIRECT },
+ { "althost", ICMP_ALTHOSTADDR },
+ { "routeradv", ICMP_ROUTERADVERT },
+ { "routersol", ICMP_ROUTERSOLICIT },
+ { "timex", ICMP_TIMXCEED },
+ { "paramprob", ICMP_PARAMPROB },
+ { "timereq", ICMP_TSTAMP },
+ { "timerep", ICMP_TSTAMPREPLY },
+ { "inforeq", ICMP_IREQ },
+ { "inforep", ICMP_IREQREPLY },
+ { "maskreq", ICMP_MASKREQ },
+ { "maskrep", ICMP_MASKREPLY },
+ { "trace", ICMP_TRACEROUTE },
+ { "dataconv", ICMP_DATACONVERR },
+ { "mobredir", ICMP_MOBILE_REDIRECT },
+ { "ipv6-where", ICMP_IPV6_WHEREAREYOU },
+ { "ipv6-here", ICMP_IPV6_IAMHERE },
+ { "mobregreq", ICMP_MOBILE_REGREQUEST },
+ { "mobregrep", ICMP_MOBILE_REGREPLY },
+ { "skip", ICMP_SKIP },
+ { "photuris", ICMP_PHOTURIS }
+};
+
+static const struct icmptypeent icmp6_type[] = {
+ { "unreach", ICMP6_DST_UNREACH },
+ { "toobig", ICMP6_PACKET_TOO_BIG },
+ { "timex", ICMP6_TIME_EXCEEDED },
+ { "paramprob", ICMP6_PARAM_PROB },
+ { "echoreq", ICMP6_ECHO_REQUEST },
+ { "echorep", ICMP6_ECHO_REPLY },
+ { "groupqry", ICMP6_MEMBERSHIP_QUERY },
+ { "listqry", MLD_LISTENER_QUERY },
+ { "grouprep", ICMP6_MEMBERSHIP_REPORT },
+ { "listenrep", MLD_LISTENER_REPORT },
+ { "groupterm", ICMP6_MEMBERSHIP_REDUCTION },
+ { "listendone", MLD_LISTENER_DONE },
+ { "routersol", ND_ROUTER_SOLICIT },
+ { "routeradv", ND_ROUTER_ADVERT },
+ { "neighbrsol", ND_NEIGHBOR_SOLICIT },
+ { "neighbradv", ND_NEIGHBOR_ADVERT },
+ { "redir", ND_REDIRECT },
+ { "routrrenum", ICMP6_ROUTER_RENUMBERING },
+ { "wrureq", ICMP6_WRUREQUEST },
+ { "wrurep", ICMP6_WRUREPLY },
+ { "fqdnreq", ICMP6_FQDN_QUERY },
+ { "fqdnrep", ICMP6_FQDN_REPLY },
+ { "niqry", ICMP6_NI_QUERY },
+ { "nirep", ICMP6_NI_REPLY },
+ { "mtraceresp", MLD_MTRACE_RESP },
+ { "mtrace", MLD_MTRACE }
+};
+
+static const struct icmpcodeent icmp_code[] = {
+ { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET },
+ { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST },
+ { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL },
+ { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT },
+ { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG },
+ { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL },
+ { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN },
+ { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN },
+ { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED },
+ { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB },
+ { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB },
+ { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET },
+ { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST },
+ { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB },
+ { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE },
+ { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF },
+ { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET },
+ { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST },
+ { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET },
+ { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST },
+ { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
+ { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
+ { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS },
+ { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS },
+ { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR },
+ { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT },
+ { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH },
+ { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX },
+ { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED },
+ { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED }
+};
+
+static const struct icmpcodeent icmp6_code[] = {
+ { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
+ { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
+ { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR },
+ { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
+ { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
+ { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
+ { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
+ { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
+ { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
+ { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
+ { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
+ { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER }
+};
+
+const struct pf_timeout pf_timeouts[] = {
+ { "tcp.first", PFTM_TCP_FIRST_PACKET },
+ { "tcp.opening", PFTM_TCP_OPENING },
+ { "tcp.established", PFTM_TCP_ESTABLISHED },
+ { "tcp.closing", PFTM_TCP_CLOSING },
+ { "tcp.finwait", PFTM_TCP_FIN_WAIT },
+ { "tcp.closed", PFTM_TCP_CLOSED },
+ { "tcp.tsdiff", PFTM_TS_DIFF },
+ { "udp.first", PFTM_UDP_FIRST_PACKET },
+ { "udp.single", PFTM_UDP_SINGLE },
+ { "udp.multiple", PFTM_UDP_MULTIPLE },
+ { "icmp.first", PFTM_ICMP_FIRST_PACKET },
+ { "icmp.error", PFTM_ICMP_ERROR_REPLY },
+ { "other.first", PFTM_OTHER_FIRST_PACKET },
+ { "other.single", PFTM_OTHER_SINGLE },
+ { "other.multiple", PFTM_OTHER_MULTIPLE },
+ { "frag", PFTM_FRAG },
+ { "interval", PFTM_INTERVAL },
+ { "adaptive.start", PFTM_ADAPTIVE_START },
+ { "adaptive.end", PFTM_ADAPTIVE_END },
+ { "src.track", PFTM_SRC_NODE },
+ { NULL, 0 }
+};
+
+const struct icmptypeent *
+geticmptypebynumber(u_int8_t type, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_type); i++) {
+ if (type == icmp_type[i].type)
+ return (&icmp_type[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_type); i++) {
+ if (type == icmp6_type[i].type)
+ return (&icmp6_type[i]);
+ }
+ }
+ return (NULL);
+}
+
+const struct icmptypeent *
+geticmptypebyname(char *w, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_type); i++) {
+ if (!strcmp(w, icmp_type[i].name))
+ return (&icmp_type[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_type); i++) {
+ if (!strcmp(w, icmp6_type[i].name))
+ return (&icmp6_type[i]);
+ }
+ }
+ return (NULL);
+}
+
+const struct icmpcodeent *
+geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_code); i++) {
+ if (type == icmp_code[i].type &&
+ code == icmp_code[i].code)
+ return (&icmp_code[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_code); i++) {
+ if (type == icmp6_code[i].type &&
+ code == icmp6_code[i].code)
+ return (&icmp6_code[i]);
+ }
+ }
+ return (NULL);
+}
+
+const struct icmpcodeent *
+geticmpcodebyname(u_long type, char *w, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_code); i++) {
+ if (type == icmp_code[i].type &&
+ !strcmp(w, icmp_code[i].name))
+ return (&icmp_code[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_code); i++) {
+ if (type == icmp6_code[i].type &&
+ !strcmp(w, icmp6_code[i].name))
+ return (&icmp6_code[i]);
+ }
+ }
+ return (NULL);
+}
+
+void
+print_op(u_int8_t op, const char *a1, const char *a2)
+{
+ if (op == PF_OP_IRG)
+ printf(" %s >< %s", a1, a2);
+ else if (op == PF_OP_XRG)
+ printf(" %s <> %s", a1, a2);
+ else if (op == PF_OP_EQ)
+ printf(" = %s", a1);
+ else if (op == PF_OP_NE)
+ printf(" != %s", a1);
+ else if (op == PF_OP_LT)
+ printf(" < %s", a1);
+ else if (op == PF_OP_LE)
+ printf(" <= %s", a1);
+ else if (op == PF_OP_GT)
+ printf(" > %s", a1);
+ else if (op == PF_OP_GE)
+ printf(" >= %s", a1);
+ else if (op == PF_OP_RRG)
+ printf(" %s:%s", a1, a2);
+}
+
+void
+print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numeric)
+{
+ char a1[6], a2[6];
+ struct servent *s;
+
+ if (!numeric)
+ s = getservbyport(p1, proto);
+ else
+ s = NULL;
+ p1 = ntohs(p1);
+ p2 = ntohs(p2);
+ snprintf(a1, sizeof(a1), "%u", p1);
+ snprintf(a2, sizeof(a2), "%u", p2);
+ printf(" port");
+ if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
+ print_op(op, s->s_name, a2);
+ else
+ print_op(op, a1, a2);
+}
+
+void
+print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
+{
+ char a1[11], a2[11];
+
+ snprintf(a1, sizeof(a1), "%u", u1);
+ snprintf(a2, sizeof(a2), "%u", u2);
+ printf(" %s", t);
+ if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
+ print_op(op, "unknown", a2);
+ else
+ print_op(op, a1, a2);
+}
+
+void
+print_flags(u_int8_t f)
+{
+ int i;
+
+ for (i = 0; tcpflags[i]; ++i)
+ if (f & (1 << i))
+ printf("%c", tcpflags[i]);
+}
+
+void
+print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst,
+ sa_family_t af, u_int8_t proto, int verbose, int numeric)
+{
+ char buf[PF_OSFP_LEN*3];
+ if (src->addr.type == PF_ADDR_ADDRMASK &&
+ dst->addr.type == PF_ADDR_ADDRMASK &&
+ PF_AZERO(&src->addr.v.a.addr, AF_INET6) &&
+ PF_AZERO(&src->addr.v.a.mask, AF_INET6) &&
+ PF_AZERO(&dst->addr.v.a.addr, AF_INET6) &&
+ PF_AZERO(&dst->addr.v.a.mask, AF_INET6) &&
+ !src->neg && !dst->neg &&
+ !src->port_op && !dst->port_op &&
+ osfp == PF_OSFP_ANY)
+ printf(" all");
+ else {
+ printf(" from ");
+ if (src->neg)
+ printf("! ");
+ print_addr(&src->addr, af, verbose);
+ if (src->port_op)
+ print_port(src->port_op, src->port[0],
+ src->port[1],
+ proto == IPPROTO_TCP ? "tcp" : "udp",
+ numeric);
+ if (osfp != PF_OSFP_ANY)
+ printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf,
+ sizeof(buf)));
+
+ printf(" to ");
+ if (dst->neg)
+ printf("! ");
+ print_addr(&dst->addr, af, verbose);
+ if (dst->port_op)
+ print_port(dst->port_op, dst->port[0],
+ dst->port[1],
+ proto == IPPROTO_TCP ? "tcp" : "udp",
+ numeric);
+ }
+}
+
+void
+print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
+ sa_family_t af, int id)
+{
+ struct pf_pooladdr *pooladdr;
+
+ if ((TAILQ_FIRST(&pool->list) != NULL) &&
+ TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
+ printf("{ ");
+ TAILQ_FOREACH(pooladdr, &pool->list, entries){
+ switch (id) {
+ case PF_NAT:
+ case PF_RDR:
+ case PF_BINAT:
+ print_addr(&pooladdr->addr, af, 0);
+ break;
+ case PF_PASS:
+ if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
+ printf("%s", pooladdr->ifname);
+ else {
+ printf("(%s ", pooladdr->ifname);
+ print_addr(&pooladdr->addr, af, 0);
+ printf(")");
+ }
+ break;
+ default:
+ break;
+ }
+ if (TAILQ_NEXT(pooladdr, entries) != NULL)
+ printf(", ");
+ else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
+ printf(" }");
+ }
+ switch (id) {
+ case PF_NAT:
+ if ((p1 != PF_NAT_PROXY_PORT_LOW ||
+ p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) {
+ if (p1 == p2)
+ printf(" port %u", p1);
+ else
+ printf(" port %u:%u", p1, p2);
+ }
+ break;
+ case PF_RDR:
+ if (p1) {
+ printf(" port %u", p1);
+ if (p2 && (p2 != p1))
+ printf(":%u", p2);
+ }
+ break;
+ default:
+ break;
+ }
+ switch (pool->opts & PF_POOL_TYPEMASK) {
+ case PF_POOL_NONE:
+ break;
+ case PF_POOL_BITMASK:
+ printf(" bitmask");
+ break;
+ case PF_POOL_RANDOM:
+ printf(" random");
+ break;
+ case PF_POOL_SRCHASH:
+ printf(" source-hash 0x%08x%08x%08x%08x",
+ pool->key.key32[0], pool->key.key32[1],
+ pool->key.key32[2], pool->key.key32[3]);
+ break;
+ case PF_POOL_ROUNDROBIN:
+ printf(" round-robin");
+ break;
+ }
+ if (pool->opts & PF_POOL_STICKYADDR)
+ printf(" sticky-address");
+ if (id == PF_NAT && p1 == 0 && p2 == 0)
+ printf(" static-port");
+}
+
+const char * const pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
+const char * const pf_lcounters[LCNT_MAX+1] = LCNT_NAMES;
+const char * const pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
+const char * const pf_scounters[FCNT_MAX+1] = FCNT_NAMES;
+
+void
+print_status(struct pf_status *s, int opts)
+{
+ char statline[80], *running;
+ time_t runtime;
+ int i;
+ char buf[PF_MD5_DIGEST_LENGTH * 2 + 1];
+ static const char hex[] = "0123456789abcdef";
+
+ runtime = time(NULL) - s->since;
+ running = s->running ? "Enabled" : "Disabled";
+
+ if (s->since) {
+ unsigned int sec, min, hrs, day = runtime;
+
+ sec = day % 60;
+ day /= 60;
+ min = day % 60;
+ day /= 60;
+ hrs = day % 24;
+ day /= 24;
+ snprintf(statline, sizeof(statline),
+ "Status: %s for %u days %.2u:%.2u:%.2u",
+ running, day, hrs, min, sec);
+ } else
+ snprintf(statline, sizeof(statline), "Status: %s", running);
+ printf("%-44s", statline);
+ switch (s->debug) {
+ case PF_DEBUG_NONE:
+ printf("%15s\n\n", "Debug: None");
+ break;
+ case PF_DEBUG_URGENT:
+ printf("%15s\n\n", "Debug: Urgent");
+ break;
+ case PF_DEBUG_MISC:
+ printf("%15s\n\n", "Debug: Misc");
+ break;
+ case PF_DEBUG_NOISY:
+ printf("%15s\n\n", "Debug: Loud");
+ break;
+ }
+
+ if (opts & PF_OPT_VERBOSE) {
+ printf("Hostid: 0x%08x\n", ntohl(s->hostid));
+
+ for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) {
+ buf[i + i] = hex[s->pf_chksum[i] >> 4];
+ buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f];
+ }
+ buf[i + i] = '\0';
+ printf("Checksum: 0x%s\n\n", buf);
+ }
+
+ if (s->ifname[0] != 0) {
+ printf("Interface Stats for %-16s %5s %16s\n",
+ s->ifname, "IPv4", "IPv6");
+ printf(" %-25s %14llu %16llu\n", "Bytes In",
+ (unsigned long long)s->bcounters[0][0],
+ (unsigned long long)s->bcounters[1][0]);
+ printf(" %-25s %14llu %16llu\n", "Bytes Out",
+ (unsigned long long)s->bcounters[0][1],
+ (unsigned long long)s->bcounters[1][1]);
+ printf(" Packets In\n");
+ printf(" %-23s %14llu %16llu\n", "Passed",
+ (unsigned long long)s->pcounters[0][0][PF_PASS],
+ (unsigned long long)s->pcounters[1][0][PF_PASS]);
+ printf(" %-23s %14llu %16llu\n", "Blocked",
+ (unsigned long long)s->pcounters[0][0][PF_DROP],
+ (unsigned long long)s->pcounters[1][0][PF_DROP]);
+ printf(" Packets Out\n");
+ printf(" %-23s %14llu %16llu\n", "Passed",
+ (unsigned long long)s->pcounters[0][1][PF_PASS],
+ (unsigned long long)s->pcounters[1][1][PF_PASS]);
+ printf(" %-23s %14llu %16llu\n\n", "Blocked",
+ (unsigned long long)s->pcounters[0][1][PF_DROP],
+ (unsigned long long)s->pcounters[1][1][PF_DROP]);
+ }
+ printf("%-27s %14s %16s\n", "State Table", "Total", "Rate");
+ printf(" %-25s %14u %14s\n", "current entries", s->states, "");
+ for (i = 0; i < FCNT_MAX; i++) {
+ printf(" %-25s %14llu ", pf_fcounters[i],
+ (unsigned long long)s->fcounters[i]);
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->fcounters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ if (opts & PF_OPT_VERBOSE) {
+ printf("Source Tracking Table\n");
+ printf(" %-25s %14u %14s\n", "current entries",
+ s->src_nodes, "");
+ for (i = 0; i < SCNT_MAX; i++) {
+ printf(" %-25s %14lld ", pf_scounters[i],
+#ifdef __FreeBSD__
+ (long long)s->scounters[i]);
+#else
+ s->scounters[i]);
+#endif
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->scounters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ }
+ printf("Counters\n");
+ for (i = 0; i < PFRES_MAX; i++) {
+ printf(" %-25s %14llu ", pf_reasons[i],
+ (unsigned long long)s->counters[i]);
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->counters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ if (opts & PF_OPT_VERBOSE) {
+ printf("Limit Counters\n");
+ for (i = 0; i < LCNT_MAX; i++) {
+ printf(" %-25s %14lld ", pf_lcounters[i],
+#ifdef __FreeBSD__
+ (unsigned long long)s->lcounters[i]);
+#else
+ s->lcounters[i]);
+#endif
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->lcounters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ }
+}
+
+void
+print_src_node(struct pf_src_node *sn, int opts)
+{
+ struct pf_addr_wrap aw;
+ int min, sec;
+
+ memset(&aw, 0, sizeof(aw));
+ if (sn->af == AF_INET)
+ aw.v.a.mask.addr32[0] = 0xffffffff;
+ else
+ memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
+
+ aw.v.a.addr = sn->addr;
+ print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+ printf(" -> ");
+ aw.v.a.addr = sn->raddr;
+ print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+ printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states,
+ sn->conn, sn->conn_rate.count / 1000,
+ (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds);
+ if (opts & PF_OPT_VERBOSE) {
+ sec = sn->creation % 60;
+ sn->creation /= 60;
+ min = sn->creation % 60;
+ sn->creation /= 60;
+ printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec);
+ if (sn->states == 0) {
+ sec = sn->expire % 60;
+ sn->expire /= 60;
+ min = sn->expire % 60;
+ sn->expire /= 60;
+ printf(", expires in %.2u:%.2u:%.2u",
+ sn->expire, min, sec);
+ }
+ printf(", %llu pkts, %llu bytes",
+#ifdef __FreeBSD__
+ (unsigned long long)(sn->packets[0] + sn->packets[1]),
+ (unsigned long long)(sn->bytes[0] + sn->bytes[1]));
+#else
+ sn->packets[0] + sn->packets[1],
+ sn->bytes[0] + sn->bytes[1]);
+#endif
+ switch (sn->ruletype) {
+ case PF_NAT:
+ if (sn->rule.nr != -1)
+ printf(", nat rule %u", sn->rule.nr);
+ break;
+ case PF_RDR:
+ if (sn->rule.nr != -1)
+ printf(", rdr rule %u", sn->rule.nr);
+ break;
+ case PF_PASS:
+ if (sn->rule.nr != -1)
+ printf(", filter rule %u", sn->rule.nr);
+ break;
+ }
+ printf("\n");
+ }
+}
+
+void
+print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
+{
+ static const char *actiontypes[] = { "pass", "block", "scrub",
+ "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" };
+ static const char *anchortypes[] = { "anchor", "anchor", "anchor",
+ "anchor", "nat-anchor", "nat-anchor", "binat-anchor",
+ "binat-anchor", "rdr-anchor", "rdr-anchor" };
+ int i, opts;
+
+ if (verbose)
+ printf("@%d ", r->nr);
+ if (r->action > PF_NORDR)
+ printf("action(%d)", r->action);
+ else if (anchor_call[0]) {
+ if (anchor_call[0] == '_') {
+ printf("%s", anchortypes[r->action]);
+ } else
+ printf("%s \"%s\"", anchortypes[r->action],
+ anchor_call);
+ } else {
+ printf("%s", actiontypes[r->action]);
+ if (r->natpass)
+ printf(" pass");
+ }
+ if (r->action == PF_DROP) {
+ if (r->rule_flag & PFRULE_RETURN)
+ printf(" return");
+ else if (r->rule_flag & PFRULE_RETURNRST) {
+ if (!r->return_ttl)
+ printf(" return-rst");
+ else
+ printf(" return-rst(ttl %d)", r->return_ttl);
+ } else if (r->rule_flag & PFRULE_RETURNICMP) {
+ const struct icmpcodeent *ic, *ic6;
+
+ ic = geticmpcodebynumber(r->return_icmp >> 8,
+ r->return_icmp & 255, AF_INET);
+ ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
+ r->return_icmp6 & 255, AF_INET6);
+
+ switch (r->af) {
+ case AF_INET:
+ printf(" return-icmp");
+ if (ic == NULL)
+ printf("(%u)", r->return_icmp & 255);
+ else
+ printf("(%s)", ic->name);
+ break;
+ case AF_INET6:
+ printf(" return-icmp6");
+ if (ic6 == NULL)
+ printf("(%u)", r->return_icmp6 & 255);
+ else
+ printf("(%s)", ic6->name);
+ break;
+ default:
+ printf(" return-icmp");
+ if (ic == NULL)
+ printf("(%u, ", r->return_icmp & 255);
+ else
+ printf("(%s, ", ic->name);
+ if (ic6 == NULL)
+ printf("%u)", r->return_icmp6 & 255);
+ else
+ printf("%s)", ic6->name);
+ break;
+ }
+ } else
+ printf(" drop");
+ }
+ if (r->direction == PF_IN)
+ printf(" in");
+ else if (r->direction == PF_OUT)
+ printf(" out");
+ if (r->log) {
+ printf(" log");
+ if (r->log & ~PF_LOG || r->logif) {
+ int count = 0;
+
+ printf(" (");
+ if (r->log & PF_LOG_ALL)
+ printf("%sall", count++ ? ", " : "");
+ if (r->log & PF_LOG_SOCKET_LOOKUP)
+ printf("%suser", count++ ? ", " : "");
+ if (r->logif)
+ printf("%sto pflog%u", count++ ? ", " : "",
+ r->logif);
+ printf(")");
+ }
+ }
+ if (r->quick)
+ printf(" quick");
+ if (r->ifname[0]) {
+ if (r->ifnot)
+ printf(" on ! %s", r->ifname);
+ else
+ printf(" on %s", r->ifname);
+ }
+ if (r->rt) {
+ if (r->rt == PF_ROUTETO)
+ printf(" route-to");
+ else if (r->rt == PF_REPLYTO)
+ printf(" reply-to");
+ else if (r->rt == PF_DUPTO)
+ printf(" dup-to");
+ else if (r->rt == PF_FASTROUTE)
+ printf(" fastroute");
+ if (r->rt != PF_FASTROUTE) {
+ printf(" ");
+ print_pool(&r->rpool, 0, 0, r->af, PF_PASS);
+ }
+ }
+ if (r->af) {
+ if (r->af == AF_INET)
+ printf(" inet");
+ else
+ printf(" inet6");
+ }
+ if (r->proto) {
+ struct protoent *p;
+
+ if ((p = getprotobynumber(r->proto)) != NULL)
+ printf(" proto %s", p->p_name);
+ else
+ printf(" proto %u", r->proto);
+ }
+ print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto,
+ verbose, numeric);
+ if (r->uid.op)
+ print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
+ UID_MAX);
+ if (r->gid.op)
+ print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
+ GID_MAX);
+ if (r->flags || r->flagset) {
+ printf(" flags ");
+ print_flags(r->flags);
+ printf("/");
+ print_flags(r->flagset);
+ } else if (r->action == PF_PASS &&
+ (!r->proto || r->proto == IPPROTO_TCP) &&
+ !(r->rule_flag & PFRULE_FRAGMENT) &&
+ !anchor_call[0] && r->keep_state)
+ printf(" flags any");
+ if (r->type) {
+ const struct icmptypeent *it;
+
+ it = geticmptypebynumber(r->type-1, r->af);
+ if (r->af != AF_INET6)
+ printf(" icmp-type");
+ else
+ printf(" icmp6-type");
+ if (it != NULL)
+ printf(" %s", it->name);
+ else
+ printf(" %u", r->type-1);
+ if (r->code) {
+ const struct icmpcodeent *ic;
+
+ ic = geticmpcodebynumber(r->type-1, r->code-1, r->af);
+ if (ic != NULL)
+ printf(" code %s", ic->name);
+ else
+ printf(" code %u", r->code-1);
+ }
+ }
+ if (r->tos)
+ printf(" tos 0x%2.2x", r->tos);
+ if (r->prio)
+ printf(" prio %u", r->prio == PF_PRIO_ZERO ? 0 : r->prio);
+ if (r->scrub_flags & PFSTATE_SETMASK) {
+ char *comma = "";
+ printf(" set (");
+ if (r->scrub_flags & PFSTATE_SETPRIO) {
+ if (r->set_prio[0] == r->set_prio[1])
+ printf("%s prio %u", comma, r->set_prio[0]);
+ else
+ printf("%s prio(%u, %u)", comma, r->set_prio[0],
+ r->set_prio[1]);
+ comma = ",";
+ }
+ printf(" )");
+ }
+ if (!r->keep_state && r->action == PF_PASS && !anchor_call[0])
+ printf(" no state");
+ else if (r->keep_state == PF_STATE_NORMAL)
+ printf(" keep state");
+ else if (r->keep_state == PF_STATE_MODULATE)
+ printf(" modulate state");
+ else if (r->keep_state == PF_STATE_SYNPROXY)
+ printf(" synproxy state");
+ if (r->prob) {
+ char buf[20];
+
+ snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0));
+ for (i = strlen(buf)-1; i > 0; i--) {
+ if (buf[i] == '0')
+ buf[i] = '\0';
+ else {
+ if (buf[i] == '.')
+ buf[i] = '\0';
+ break;
+ }
+ }
+ printf(" probability %s%%", buf);
+ }
+ opts = 0;
+ if (r->max_states || r->max_src_nodes || r->max_src_states)
+ opts = 1;
+ if (r->rule_flag & PFRULE_NOSYNC)
+ opts = 1;
+ if (r->rule_flag & PFRULE_SRCTRACK)
+ opts = 1;
+ if (r->rule_flag & PFRULE_IFBOUND)
+ opts = 1;
+ if (r->rule_flag & PFRULE_STATESLOPPY)
+ opts = 1;
+ for (i = 0; !opts && i < PFTM_MAX; ++i)
+ if (r->timeout[i])
+ opts = 1;
+ if (opts) {
+ printf(" (");
+ if (r->max_states) {
+ printf("max %u", r->max_states);
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_NOSYNC) {
+ if (!opts)
+ printf(", ");
+ printf("no-sync");
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_SRCTRACK) {
+ if (!opts)
+ printf(", ");
+ printf("source-track");
+ if (r->rule_flag & PFRULE_RULESRCTRACK)
+ printf(" rule");
+ else
+ printf(" global");
+ opts = 0;
+ }
+ if (r->max_src_states) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-states %u", r->max_src_states);
+ opts = 0;
+ }
+ if (r->max_src_conn) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-conn %u", r->max_src_conn);
+ opts = 0;
+ }
+ if (r->max_src_conn_rate.limit) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-conn-rate %u/%u",
+ r->max_src_conn_rate.limit,
+ r->max_src_conn_rate.seconds);
+ opts = 0;
+ }
+ if (r->max_src_nodes) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-nodes %u", r->max_src_nodes);
+ opts = 0;
+ }
+ if (r->overload_tblname[0]) {
+ if (!opts)
+ printf(", ");
+ printf("overload <%s>", r->overload_tblname);
+ if (r->flush)
+ printf(" flush");
+ if (r->flush & PF_FLUSH_GLOBAL)
+ printf(" global");
+ }
+ if (r->rule_flag & PFRULE_IFBOUND) {
+ if (!opts)
+ printf(", ");
+ printf("if-bound");
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_STATESLOPPY) {
+ if (!opts)
+ printf(", ");
+ printf("sloppy");
+ opts = 0;
+ }
+ for (i = 0; i < PFTM_MAX; ++i)
+ if (r->timeout[i]) {
+ int j;
+
+ if (!opts)
+ printf(", ");
+ opts = 0;
+ for (j = 0; pf_timeouts[j].name != NULL;
+ ++j)
+ if (pf_timeouts[j].timeout == i)
+ break;
+ printf("%s %u", pf_timeouts[j].name == NULL ?
+ "inv.timeout" : pf_timeouts[j].name,
+ r->timeout[i]);
+ }
+ printf(")");
+ }
+ if (r->rule_flag & PFRULE_FRAGMENT)
+ printf(" fragment");
+ if (r->rule_flag & PFRULE_NODF)
+ printf(" no-df");
+ if (r->rule_flag & PFRULE_RANDOMID)
+ printf(" random-id");
+ if (r->min_ttl)
+ printf(" min-ttl %d", r->min_ttl);
+ if (r->max_mss)
+ printf(" max-mss %d", r->max_mss);
+ if (r->rule_flag & PFRULE_SET_TOS)
+ printf(" set-tos 0x%2.2x", r->set_tos);
+ if (r->allow_opts)
+ printf(" allow-opts");
+ if (r->action == PF_SCRUB) {
+ if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
+ printf(" reassemble tcp");
+
+ printf(" fragment reassemble");
+ }
+ if (r->label[0])
+ printf(" label \"%s\"", r->label);
+ if (r->qname[0] && r->pqname[0])
+ printf(" queue(%s, %s)", r->qname, r->pqname);
+ else if (r->qname[0])
+ printf(" queue %s", r->qname);
+ if (r->tagname[0])
+ printf(" tag %s", r->tagname);
+ if (r->match_tagname[0]) {
+ if (r->match_tag_not)
+ printf(" !");
+ printf(" tagged %s", r->match_tagname);
+ }
+ if (r->rtableid != -1)
+ printf(" rtable %u", r->rtableid);
+ if (r->divert.port) {
+#ifdef __FreeBSD__
+ printf(" divert-to %u", ntohs(r->divert.port));
+#else
+ if (PF_AZERO(&r->divert.addr, r->af)) {
+ printf(" divert-reply");
+ } else {
+ /* XXX cut&paste from print_addr */
+ char buf[48];
+
+ printf(" divert-to ");
+ if (inet_ntop(r->af, &r->divert.addr, buf,
+ sizeof(buf)) == NULL)
+ printf("?");
+ else
+ printf("%s", buf);
+ printf(" port %u", ntohs(r->divert.port));
+ }
+#endif
+ }
+ if (!anchor_call[0] && (r->action == PF_NAT ||
+ r->action == PF_BINAT || r->action == PF_RDR)) {
+ printf(" -> ");
+ print_pool(&r->rpool, r->rpool.proxy_port[0],
+ r->rpool.proxy_port[1], r->af, r->action);
+ }
+}
+
+void
+print_tabledef(const char *name, int flags, int addrs,
+ struct node_tinithead *nodes)
+{
+ struct node_tinit *ti, *nti;
+ struct node_host *h;
+
+ printf("table <%s>", name);
+ if (flags & PFR_TFLAG_CONST)
+ printf(" const");
+ if (flags & PFR_TFLAG_PERSIST)
+ printf(" persist");
+ if (flags & PFR_TFLAG_COUNTERS)
+ printf(" counters");
+ SIMPLEQ_FOREACH(ti, nodes, entries) {
+ if (ti->file) {
+ printf(" file \"%s\"", ti->file);
+ continue;
+ }
+ printf(" {");
+ for (;;) {
+ for (h = ti->host; h != NULL; h = h->next) {
+ printf(h->not ? " !" : " ");
+ print_addr(&h->addr, h->af, 0);
+ }
+ nti = SIMPLEQ_NEXT(ti, entries);
+ if (nti != NULL && nti->file == NULL)
+ ti = nti; /* merge lists */
+ else
+ break;
+ }
+ printf(" }");
+ }
+ if (addrs && SIMPLEQ_EMPTY(nodes))
+ printf(" { }");
+ printf("\n");
+}
+
+int
+parse_flags(char *s)
+{
+ char *p, *q;
+ u_int8_t f = 0;
+
+ for (p = s; *p; p++) {
+ if ((q = strchr(tcpflags, *p)) == NULL)
+ return -1;
+ else
+ f |= 1 << (q - tcpflags);
+ }
+ return (f ? f : PF_TH_ALL);
+}
+
+void
+set_ipmask(struct node_host *h, u_int8_t b)
+{
+ struct pf_addr *m, *n;
+ int i, j = 0;
+
+ m = &h->addr.v.a.mask;
+ memset(m, 0, sizeof(*m));
+
+ while (b >= 32) {
+ m->addr32[j++] = 0xffffffff;
+ b -= 32;
+ }
+ for (i = 31; i > 31-b; --i)
+ m->addr32[j] |= (1 << i);
+ if (b)
+ m->addr32[j] = htonl(m->addr32[j]);
+
+ /* Mask off bits of the address that will never be used. */
+ n = &h->addr.v.a.addr;
+ if (h->addr.type == PF_ADDR_ADDRMASK)
+ for (i = 0; i < 4; i++)
+ n->addr32[i] = n->addr32[i] & m->addr32[i];
+}
+
+int
+check_netmask(struct node_host *h, sa_family_t af)
+{
+ struct node_host *n = NULL;
+ struct pf_addr *m;
+
+ for (n = h; n != NULL; n = n->next) {
+ if (h->addr.type == PF_ADDR_TABLE)
+ continue;
+ m = &h->addr.v.a.mask;
+ /* fix up netmask for dynaddr */
+ if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL &&
+ unmask(m, AF_INET6) > 32)
+ set_ipmask(n, 32);
+ /* netmasks > 32 bit are invalid on v4 */
+ if (af == AF_INET &&
+ (m->addr32[1] || m->addr32[2] || m->addr32[3])) {
+ fprintf(stderr, "netmask %u invalid for IPv4 address\n",
+ unmask(m, AF_INET6));
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/* interface lookup routines */
+
+static struct node_host *iftab;
+
+void
+ifa_load(void)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct node_host *n = NULL, *h = NULL;
+
+ if (getifaddrs(&ifap) < 0)
+ err(1, "getifaddrs");
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (!(ifa->ifa_addr->sa_family == AF_INET ||
+ ifa->ifa_addr->sa_family == AF_INET6 ||
+ ifa->ifa_addr->sa_family == AF_LINK))
+ continue;
+ n = calloc(1, sizeof(struct node_host));
+ if (n == NULL)
+ err(1, "address: calloc");
+ n->af = ifa->ifa_addr->sa_family;
+ n->ifa_flags = ifa->ifa_flags;
+#ifdef __KAME__
+ if (n->af == AF_INET6 &&
+ IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
+ ifa->ifa_addr)->sin6_addr) &&
+ ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id ==
+ 0) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
+ sin6->sin6_addr.s6_addr[3];
+ sin6->sin6_addr.s6_addr[2] = 0;
+ sin6->sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ n->ifindex = 0;
+ if (n->af == AF_INET) {
+ memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *)
+ ifa->ifa_addr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *)
+ ifa->ifa_netmask)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ if (ifa->ifa_broadaddr != NULL)
+ memcpy(&n->bcast, &((struct sockaddr_in *)
+ ifa->ifa_broadaddr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ if (ifa->ifa_dstaddr != NULL)
+ memcpy(&n->peer, &((struct sockaddr_in *)
+ ifa->ifa_dstaddr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ } else if (n->af == AF_INET6) {
+ memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *)
+ ifa->ifa_addr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *)
+ ifa->ifa_netmask)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ if (ifa->ifa_broadaddr != NULL)
+ memcpy(&n->bcast, &((struct sockaddr_in6 *)
+ ifa->ifa_broadaddr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ if (ifa->ifa_dstaddr != NULL)
+ memcpy(&n->peer, &((struct sockaddr_in6 *)
+ ifa->ifa_dstaddr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ n->ifindex = ((struct sockaddr_in6 *)
+ ifa->ifa_addr)->sin6_scope_id;
+ }
+ if ((n->ifname = strdup(ifa->ifa_name)) == NULL)
+ err(1, "ifa_load: strdup");
+ n->next = NULL;
+ n->tail = n;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n;
+ }
+ }
+
+ iftab = h;
+ freeifaddrs(ifap);
+}
+
+int
+get_socket_domain(void)
+{
+ int sdom;
+
+ sdom = AF_UNSPEC;
+#ifdef WITH_INET6
+ if (sdom == AF_UNSPEC && feature_present("inet6"))
+ sdom = AF_INET6;
+#endif
+#ifdef WITH_INET
+ if (sdom == AF_UNSPEC && feature_present("inet"))
+ sdom = AF_INET;
+#endif
+ if (sdom == AF_UNSPEC)
+ sdom = AF_LINK;
+
+ return (sdom);
+}
+
+struct node_host *
+ifa_exists(const char *ifa_name)
+{
+ struct node_host *n;
+ struct ifgroupreq ifgr;
+ int s;
+
+ if (iftab == NULL)
+ ifa_load();
+
+ /* check wether this is a group */
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1)
+ err(1, "socket");
+ bzero(&ifgr, sizeof(ifgr));
+ strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
+ if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) {
+ /* fake a node_host */
+ if ((n = calloc(1, sizeof(*n))) == NULL)
+ err(1, "calloc");
+ if ((n->ifname = strdup(ifa_name)) == NULL)
+ err(1, "strdup");
+ close(s);
+ return (n);
+ }
+ close(s);
+
+ for (n = iftab; n; n = n->next) {
+ if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
+ return (n);
+ }
+
+ return (NULL);
+}
+
+struct node_host *
+ifa_grouplookup(const char *ifa_name, int flags)
+{
+ struct ifg_req *ifg;
+ struct ifgroupreq ifgr;
+ int s, len;
+ struct node_host *n, *h = NULL;
+
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1)
+ err(1, "socket");
+ bzero(&ifgr, sizeof(ifgr));
+ strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
+ if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
+ close(s);
+ return (NULL);
+ }
+
+ len = ifgr.ifgr_len;
+ if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
+ err(1, "calloc");
+ if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
+ err(1, "SIOCGIFGMEMB");
+
+ for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
+ ifg++) {
+ len -= sizeof(struct ifg_req);
+ if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL)
+ continue;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n->tail;
+ }
+ }
+ free(ifgr.ifgr_groups);
+ close(s);
+
+ return (h);
+}
+
+struct node_host *
+ifa_lookup(const char *ifa_name, int flags)
+{
+ struct node_host *p = NULL, *h = NULL, *n = NULL;
+ int got4 = 0, got6 = 0;
+ const char *last_if = NULL;
+
+ if ((h = ifa_grouplookup(ifa_name, flags)) != NULL)
+ return (h);
+
+ if (!strncmp(ifa_name, "self", IFNAMSIZ))
+ ifa_name = NULL;
+
+ if (iftab == NULL)
+ ifa_load();
+
+ for (p = iftab; p; p = p->next) {
+ if (ifa_skip_if(ifa_name, p))
+ continue;
+ if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET)
+ continue;
+ if ((flags & PFI_AFLAG_BROADCAST) &&
+ !(p->ifa_flags & IFF_BROADCAST))
+ continue;
+ if ((flags & PFI_AFLAG_PEER) &&
+ !(p->ifa_flags & IFF_POINTOPOINT))
+ continue;
+ if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0)
+ continue;
+ if (last_if == NULL || strcmp(last_if, p->ifname))
+ got4 = got6 = 0;
+ last_if = p->ifname;
+ if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4)
+ continue;
+ if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6)
+ continue;
+ if (p->af == AF_INET)
+ got4 = 1;
+ else
+ got6 = 1;
+ n = calloc(1, sizeof(struct node_host));
+ if (n == NULL)
+ err(1, "address: calloc");
+ n->af = p->af;
+ if (flags & PFI_AFLAG_BROADCAST)
+ memcpy(&n->addr.v.a.addr, &p->bcast,
+ sizeof(struct pf_addr));
+ else if (flags & PFI_AFLAG_PEER)
+ memcpy(&n->addr.v.a.addr, &p->peer,
+ sizeof(struct pf_addr));
+ else
+ memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr,
+ sizeof(struct pf_addr));
+ if (flags & PFI_AFLAG_NETWORK)
+ set_ipmask(n, unmask(&p->addr.v.a.mask, n->af));
+ else {
+ if (n->af == AF_INET) {
+ if (p->ifa_flags & IFF_LOOPBACK &&
+ p->ifa_flags & IFF_LINK1)
+ memcpy(&n->addr.v.a.mask,
+ &p->addr.v.a.mask,
+ sizeof(struct pf_addr));
+ else
+ set_ipmask(n, 32);
+ } else
+ set_ipmask(n, 128);
+ }
+ n->ifindex = p->ifindex;
+
+ n->next = NULL;
+ n->tail = n;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n;
+ }
+ }
+ return (h);
+}
+
+int
+ifa_skip_if(const char *filter, struct node_host *p)
+{
+ int n;
+
+ if (p->af != AF_INET && p->af != AF_INET6)
+ return (1);
+ if (filter == NULL || !*filter)
+ return (0);
+ if (!strcmp(p->ifname, filter))
+ return (0); /* exact match */
+ n = strlen(filter);
+ if (n < 1 || n >= IFNAMSIZ)
+ return (1); /* sanity check */
+ if (filter[n-1] >= '0' && filter[n-1] <= '9')
+ return (1); /* only do exact match in that case */
+ if (strncmp(p->ifname, filter, n))
+ return (1); /* prefix doesn't match */
+ return (p->ifname[n] < '0' || p->ifname[n] > '9');
+}
+
+
+struct node_host *
+host(const char *s)
+{
+ struct node_host *h = NULL;
+ int mask, v4mask, v6mask, cont = 1;
+ char *p, *q, *ps;
+
+ if ((p = strrchr(s, '/')) != NULL) {
+ mask = strtol(p+1, &q, 0);
+ if (!q || *q || mask > 128 || q == (p+1)) {
+ fprintf(stderr, "invalid netmask '%s'\n", p);
+ return (NULL);
+ }
+ if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
+ err(1, "host: malloc");
+ strlcpy(ps, s, strlen(s) - strlen(p) + 1);
+ v4mask = v6mask = mask;
+ } else {
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host: strdup");
+ v4mask = 32;
+ v6mask = 128;
+ mask = -1;
+ }
+
+ /* interface with this name exists? */
+ if (cont && (h = host_if(ps, mask)) != NULL)
+ cont = 0;
+
+ /* IPv4 address? */
+ if (cont && (h = host_v4(s, mask)) != NULL)
+ cont = 0;
+
+ /* IPv6 address? */
+ if (cont && (h = host_v6(ps, v6mask)) != NULL)
+ cont = 0;
+
+ /* dns lookup */
+ if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL)
+ cont = 0;
+ free(ps);
+
+ if (h == NULL || cont == 1) {
+ fprintf(stderr, "no IP address found for %s\n", s);
+ return (NULL);
+ }
+ return (h);
+}
+
+struct node_host *
+host_if(const char *s, int mask)
+{
+ struct node_host *n, *h = NULL;
+ char *p, *ps;
+ int flags = 0;
+
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host_if: strdup");
+ while ((p = strrchr(ps, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ free(ps);
+ return (NULL);
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */
+ fprintf(stderr, "illegal combination of interface modifiers\n");
+ free(ps);
+ return (NULL);
+ }
+ if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) {
+ fprintf(stderr, "network or broadcast lookup, but "
+ "extra netmask given\n");
+ free(ps);
+ return (NULL);
+ }
+ if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
+ /* interface with this name exists */
+ h = ifa_lookup(ps, flags);
+ for (n = h; n != NULL && mask > -1; n = n->next)
+ set_ipmask(n, mask);
+ }
+
+ free(ps);
+ return (h);
+}
+
+struct node_host *
+host_v4(const char *s, int mask)
+{
+ struct node_host *h = NULL;
+ struct in_addr ina;
+ int bits = 32;
+
+ memset(&ina, 0, sizeof(struct in_addr));
+ if (strrchr(s, '/') != NULL) {
+ if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
+ return (NULL);
+ } else {
+ if (inet_pton(AF_INET, s, &ina) != 1)
+ return (NULL);
+ }
+
+ h = calloc(1, sizeof(struct node_host));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->ifname = NULL;
+ h->af = AF_INET;
+ h->addr.v.a.addr.addr32[0] = ina.s_addr;
+ set_ipmask(h, bits);
+ h->next = NULL;
+ h->tail = h;
+
+ return (h);
+}
+
+struct node_host *
+host_v6(const char *s, int mask)
+{
+ struct addrinfo hints, *res;
+ struct node_host *h = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(s, "0", &hints, &res) == 0) {
+ h = calloc(1, sizeof(struct node_host));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->ifname = NULL;
+ h->af = AF_INET6;
+ memcpy(&h->addr.v.a.addr,
+ &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
+ sizeof(h->addr.v.a.addr));
+ h->ifindex =
+ ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
+ set_ipmask(h, mask);
+ freeaddrinfo(res);
+ h->next = NULL;
+ h->tail = h;
+ }
+
+ return (h);
+}
+
+struct node_host *
+host_dns(const char *s, int v4mask, int v6mask)
+{
+ struct addrinfo hints, *res0, *res;
+ struct node_host *n, *h = NULL;
+ int error, noalias = 0;
+ int got4 = 0, got6 = 0;
+ char *p, *ps;
+
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host_dns: strdup");
+ if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) {
+ noalias = 1;
+ *p = '\0';
+ }
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM; /* DUMMY */
+ error = getaddrinfo(ps, NULL, &hints, &res0);
+ if (error) {
+ free(ps);
+ return (h);
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ if (res->ai_family != AF_INET &&
+ res->ai_family != AF_INET6)
+ continue;
+ if (noalias) {
+ if (res->ai_family == AF_INET) {
+ if (got4)
+ continue;
+ got4 = 1;
+ } else {
+ if (got6)
+ continue;
+ got6 = 1;
+ }
+ }
+ n = calloc(1, sizeof(struct node_host));
+ if (n == NULL)
+ err(1, "host_dns: calloc");
+ n->ifname = NULL;
+ n->af = res->ai_family;
+ if (res->ai_family == AF_INET) {
+ memcpy(&n->addr.v.a.addr,
+ &((struct sockaddr_in *)
+ res->ai_addr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ set_ipmask(n, v4mask);
+ } else {
+ memcpy(&n->addr.v.a.addr,
+ &((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ n->ifindex =
+ ((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_scope_id;
+ set_ipmask(n, v6mask);
+ }
+ n->next = NULL;
+ n->tail = n;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n;
+ }
+ }
+ freeaddrinfo(res0);
+ free(ps);
+
+ return (h);
+}
+
+/*
+ * convert a hostname to a list of addresses and put them in the given buffer.
+ * test:
+ * if set to 1, only simple addresses are accepted (no netblock, no "!").
+ */
+int
+append_addr(struct pfr_buffer *b, char *s, int test)
+{
+ char *r;
+ struct node_host *h, *n;
+ int rv, not = 0;
+
+ for (r = s; *r == '!'; r++)
+ not = !not;
+ if ((n = host(r)) == NULL) {
+ errno = 0;
+ return (-1);
+ }
+ rv = append_addr_host(b, n, test, not);
+ do {
+ h = n;
+ n = n->next;
+ free(h);
+ } while (n != NULL);
+ return (rv);
+}
+
+/*
+ * same as previous function, but with a pre-parsed input and the ability
+ * to "negate" the result. Does not free the node_host list.
+ * not:
+ * setting it to 1 is equivalent to adding "!" in front of parameter s.
+ */
+int
+append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
+{
+ int bits;
+ struct pfr_addr addr;
+
+ do {
+ bzero(&addr, sizeof(addr));
+ addr.pfra_not = n->not ^ not;
+ addr.pfra_af = n->af;
+ addr.pfra_net = unmask(&n->addr.v.a.mask, n->af);
+ switch (n->af) {
+ case AF_INET:
+ addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0];
+ bits = 32;
+ break;
+ case AF_INET6:
+ memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6,
+ sizeof(struct in6_addr));
+ bits = 128;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((test && (not || addr.pfra_net != bits)) ||
+ addr.pfra_net > bits) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (pfr_buf_add(b, &addr))
+ return (-1);
+ } while ((n = n->next) != NULL);
+
+ return (0);
+}
+
+int
+pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor)
+{
+ struct pfioc_trans_e trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.rs_num = rs_num;
+ if (strlcpy(trans.anchor, anchor,
+ sizeof(trans.anchor)) >= sizeof(trans.anchor))
+ errx(1, "pfctl_add_trans: strlcpy");
+
+ return pfr_buf_add(buf, &trans);
+}
+
+u_int32_t
+pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor)
+{
+ struct pfioc_trans_e *p;
+
+ PFRB_FOREACH(p, buf)
+ if (rs_num == p->rs_num && !strcmp(anchor, p->anchor))
+ return (p->ticket);
+ errx(1, "pfctl_get_ticket: assertion failed");
+}
+
+int
+pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from)
+{
+ struct pfioc_trans trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.size = buf->pfrb_size - from;
+ trans.esize = sizeof(struct pfioc_trans_e);
+ trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from;
+ return ioctl(dev, cmd, &trans);
+}
diff --git a/freebsd/sbin/pfctl/pfctl_parser.h b/freebsd/sbin/pfctl/pfctl_parser.h
new file mode 100644
index 00000000..2b7fea7b
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_parser.h
@@ -0,0 +1,322 @@
+/* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PFCTL_PARSER_H_
+#define _PFCTL_PARSER_H_
+
+#define PF_OSFP_FILE "/etc/pf.os"
+
+#define PF_OPT_DISABLE 0x0001
+#define PF_OPT_ENABLE 0x0002
+#define PF_OPT_VERBOSE 0x0004
+#define PF_OPT_NOACTION 0x0008
+#define PF_OPT_QUIET 0x0010
+#define PF_OPT_CLRRULECTRS 0x0020
+#define PF_OPT_USEDNS 0x0040
+#define PF_OPT_VERBOSE2 0x0080
+#define PF_OPT_DUMMYACTION 0x0100
+#define PF_OPT_DEBUG 0x0200
+#define PF_OPT_SHOWALL 0x0400
+#define PF_OPT_OPTIMIZE 0x0800
+#define PF_OPT_NUMERIC 0x1000
+#define PF_OPT_MERGE 0x2000
+#define PF_OPT_RECURSE 0x4000
+
+#define PF_TH_ALL 0xFF
+
+#define PF_NAT_PROXY_PORT_LOW 50001
+#define PF_NAT_PROXY_PORT_HIGH 65535
+
+#define PF_OPTIMIZE_BASIC 0x0001
+#define PF_OPTIMIZE_PROFILE 0x0002
+
+#define FCNT_NAMES { \
+ "searches", \
+ "inserts", \
+ "removals", \
+ NULL \
+}
+
+struct pfr_buffer; /* forward definition */
+
+
+struct pfctl {
+ int dev;
+ int opts;
+ int optimize;
+ int loadopt;
+ int asd; /* anchor stack depth */
+ int bn; /* brace number */
+ int brace;
+ int tdirty; /* kernel dirty */
+#define PFCTL_ANCHOR_STACK_DEPTH 64
+ struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH];
+ struct pfioc_pooladdr paddr;
+ struct pfioc_altq *paltq;
+ struct pfioc_queue *pqueue;
+ struct pfr_buffer *trans;
+ struct pf_anchor *anchor, *alast;
+ const char *ruleset;
+
+ /* 'set foo' options */
+ u_int32_t timeout[PFTM_MAX];
+ u_int32_t limit[PF_LIMIT_MAX];
+ u_int32_t debug;
+ u_int32_t hostid;
+ char *ifname;
+
+ u_int8_t timeout_set[PFTM_MAX];
+ u_int8_t limit_set[PF_LIMIT_MAX];
+ u_int8_t debug_set;
+ u_int8_t hostid_set;
+ u_int8_t ifname_set;
+};
+
+struct node_if {
+ char ifname[IFNAMSIZ];
+ u_int8_t not;
+ u_int8_t dynamic; /* antispoof */
+ u_int ifa_flags;
+ struct node_if *next;
+ struct node_if *tail;
+};
+
+struct node_host {
+ struct pf_addr_wrap addr;
+ struct pf_addr bcast;
+ struct pf_addr peer;
+ sa_family_t af;
+ u_int8_t not;
+ u_int32_t ifindex; /* link-local IPv6 addrs */
+ char *ifname;
+ u_int ifa_flags;
+ struct node_host *next;
+ struct node_host *tail;
+};
+
+struct node_os {
+ char *os;
+ pf_osfp_t fingerprint;
+ struct node_os *next;
+ struct node_os *tail;
+};
+
+struct node_queue_bw {
+ u_int32_t bw_absolute;
+ u_int16_t bw_percent;
+};
+
+struct node_hfsc_sc {
+ struct node_queue_bw m1; /* slope of 1st segment; bps */
+ u_int d; /* x-projection of m1; msec */
+ struct node_queue_bw m2; /* slope of 2nd segment; bps */
+ u_int8_t used;
+};
+
+struct node_hfsc_opts {
+ struct node_hfsc_sc realtime;
+ struct node_hfsc_sc linkshare;
+ struct node_hfsc_sc upperlimit;
+ int flags;
+};
+
+struct node_fairq_sc {
+ struct node_queue_bw m1; /* slope of 1st segment; bps */
+ u_int d; /* x-projection of m1; msec */
+ struct node_queue_bw m2; /* slope of 2nd segment; bps */
+ u_int8_t used;
+};
+
+struct node_fairq_opts {
+ struct node_fairq_sc linkshare;
+ struct node_queue_bw hogs_bw;
+ u_int nbuckets;
+ int flags;
+};
+
+struct node_queue_opt {
+ int qtype;
+ union {
+ struct cbq_opts cbq_opts;
+ struct codel_opts codel_opts;
+ struct priq_opts priq_opts;
+ struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ } data;
+};
+
+#ifdef __FreeBSD__
+/*
+ * XXX
+ * Absolutely this is not correct location to define this.
+ * Should we use an another sperate header file?
+ */
+#define SIMPLEQ_HEAD STAILQ_HEAD
+#define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER
+#define SIMPLEQ_ENTRY STAILQ_ENTRY
+#define SIMPLEQ_FIRST STAILQ_FIRST
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY STAILQ_EMPTY
+#define SIMPLEQ_NEXT STAILQ_NEXT
+/*#define SIMPLEQ_FOREACH STAILQ_FOREACH*/
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+#define SIMPLEQ_INIT STAILQ_INIT
+#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD
+#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL
+#define SIMPLEQ_INSERT_AFTER STAILQ_INSERT_AFTER
+#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD
+#endif
+SIMPLEQ_HEAD(node_tinithead, node_tinit);
+struct node_tinit { /* table initializer */
+ SIMPLEQ_ENTRY(node_tinit) entries;
+ struct node_host *host;
+ char *file;
+};
+
+
+/* optimizer created tables */
+struct pf_opt_tbl {
+ char pt_name[PF_TABLE_NAME_SIZE];
+ int pt_rulecount;
+ int pt_generated;
+ struct node_tinithead pt_nodes;
+ struct pfr_buffer *pt_buf;
+};
+#define PF_OPT_TABLE_PREFIX "__automatic_"
+
+/* optimizer pf_rule container */
+struct pf_opt_rule {
+ struct pf_rule por_rule;
+ struct pf_opt_tbl *por_src_tbl;
+ struct pf_opt_tbl *por_dst_tbl;
+ u_int64_t por_profile_count;
+ TAILQ_ENTRY(pf_opt_rule) por_entry;
+ TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT];
+};
+
+TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
+
+int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *);
+int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *);
+
+int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *);
+int pfctl_add_altq(struct pfctl *, struct pf_altq *);
+int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t);
+void pfctl_move_pool(struct pf_pool *, struct pf_pool *);
+void pfctl_clear_pool(struct pf_pool *);
+
+int pfctl_set_timeout(struct pfctl *, const char *, int, int);
+int pfctl_set_optimization(struct pfctl *, const char *);
+int pfctl_set_limit(struct pfctl *, const char *, unsigned int);
+int pfctl_set_logif(struct pfctl *, char *);
+int pfctl_set_hostid(struct pfctl *, u_int32_t);
+int pfctl_set_debug(struct pfctl *, char *);
+int pfctl_set_interface_flags(struct pfctl *, char *, int, int);
+
+int parse_config(char *, struct pfctl *);
+int parse_flags(char *);
+int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
+
+void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int);
+void print_src_node(struct pf_src_node *, int);
+void print_rule(struct pf_rule *, const char *, int, int);
+void print_tabledef(const char *, int, int, struct node_tinithead *);
+void print_status(struct pf_status *, int);
+
+int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
+ struct node_queue_opt *);
+int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
+ struct node_queue_opt *);
+
+void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *,
+ struct node_queue_opt *);
+void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *,
+ int, struct node_queue_opt *);
+
+int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *,
+ u_int32_t);
+
+void pfctl_clear_fingerprints(int, int);
+int pfctl_file_fingerprints(int, int, const char *);
+pf_osfp_t pfctl_get_fingerprint(const char *);
+int pfctl_load_fingerprints(int, int);
+char *pfctl_lookup_fingerprint(pf_osfp_t, char *, size_t);
+void pfctl_show_fingerprints(int);
+
+
+struct icmptypeent {
+ const char *name;
+ u_int8_t type;
+};
+
+struct icmpcodeent {
+ const char *name;
+ u_int8_t type;
+ u_int8_t code;
+};
+
+const struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t);
+const struct icmptypeent *geticmptypebyname(char *, u_int8_t);
+const struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t);
+const struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t);
+
+struct pf_timeout {
+ const char *name;
+ int timeout;
+};
+
+#define PFCTL_FLAG_FILTER 0x02
+#define PFCTL_FLAG_NAT 0x04
+#define PFCTL_FLAG_OPTION 0x08
+#define PFCTL_FLAG_ALTQ 0x10
+#define PFCTL_FLAG_TABLE 0x20
+
+extern const struct pf_timeout pf_timeouts[];
+
+void set_ipmask(struct node_host *, u_int8_t);
+int check_netmask(struct node_host *, sa_family_t);
+int unmask(struct pf_addr *, sa_family_t);
+void ifa_load(void);
+int get_socket_domain(void);
+struct node_host *ifa_exists(const char *);
+struct node_host *ifa_lookup(const char *, int);
+struct node_host *host(const char *);
+
+int append_addr(struct pfr_buffer *, char *, int);
+int append_addr_host(struct pfr_buffer *,
+ struct node_host *, int, int);
+
+#endif /* _PFCTL_PARSER_H_ */
diff --git a/freebsd/sbin/pfctl/pfctl_qstats.c b/freebsd/sbin/pfctl/pfctl_qstats.c
new file mode 100644
index 00000000..dda3a494
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_qstats.c
@@ -0,0 +1,528 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
+
+/*
+ * Copyright (c) Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include "pfctl.h"
+#include "pfctl_parser.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_qstats-data.h"
+#endif /* __rtems__ */
+
+union class_stats {
+ class_stats_t cbq_stats;
+ struct priq_classstats priq_stats;
+ struct hfsc_classstats hfsc_stats;
+ struct fairq_classstats fairq_stats;
+ struct codel_ifstats codel_stats;
+};
+
+#define AVGN_MAX 8
+#define STAT_INTERVAL 5
+
+struct queue_stats {
+ union class_stats data;
+ int avgn;
+ double avg_bytes;
+ double avg_packets;
+ u_int64_t prev_bytes;
+ u_int64_t prev_packets;
+};
+
+struct pf_altq_node {
+ struct pf_altq altq;
+ struct pf_altq_node *next;
+ struct pf_altq_node *children;
+ struct queue_stats qstats;
+};
+
+int pfctl_update_qstats(int, struct pf_altq_node **);
+void pfctl_insert_altq_node(struct pf_altq_node **,
+ const struct pf_altq, const struct queue_stats);
+struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
+ const char *, const char *);
+void pfctl_print_altq_node(int, const struct pf_altq_node *,
+ unsigned, int);
+void print_cbqstats(struct queue_stats);
+void print_codelstats(struct queue_stats);
+void print_priqstats(struct queue_stats);
+void print_hfscstats(struct queue_stats);
+void print_fairqstats(struct queue_stats);
+void pfctl_free_altq_node(struct pf_altq_node *);
+void pfctl_print_altq_nodestat(int,
+ const struct pf_altq_node *);
+
+void update_avg(struct pf_altq_node *);
+
+int
+pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
+{
+ struct pf_altq_node *root = NULL, *node;
+ int nodes, dotitle = (opts & PF_OPT_SHOWALL);
+
+#ifdef __FreeBSD__
+ if (!altqsupport)
+ return (-1);
+#endif
+
+ if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
+ return (-1);
+
+ if (nodes == 0)
+ printf("No queue in use\n");
+ for (node = root; node != NULL; node = node->next) {
+ if (iface != NULL && strcmp(node->altq.ifname, iface))
+ continue;
+ if (dotitle) {
+ pfctl_print_title("ALTQ:");
+ dotitle = 0;
+ }
+ pfctl_print_altq_node(dev, node, 0, opts);
+ }
+
+ while (verbose2 && nodes > 0) {
+ printf("\n");
+ fflush(stdout);
+ sleep(STAT_INTERVAL);
+ if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
+ return (-1);
+ for (node = root; node != NULL; node = node->next) {
+ if (iface != NULL && strcmp(node->altq.ifname, iface))
+ continue;
+#ifdef __FreeBSD__
+ if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
+ continue;
+#endif
+ pfctl_print_altq_node(dev, node, 0, opts);
+ }
+ }
+ pfctl_free_altq_node(root);
+ return (0);
+}
+
+#ifdef __rtems__
+static u_int32_t last_ticket;
+#endif /* __rtems__ */
+int
+pfctl_update_qstats(int dev, struct pf_altq_node **root)
+{
+ struct pf_altq_node *node;
+ struct pfioc_altq pa;
+ struct pfioc_qstats pq;
+ u_int32_t mnr, nr;
+ struct queue_stats qstats;
+#ifndef __rtems__
+ static u_int32_t last_ticket;
+#endif /* __rtems__ */
+
+ memset(&pa, 0, sizeof(pa));
+ memset(&pq, 0, sizeof(pq));
+ memset(&qstats, 0, sizeof(qstats));
+ if (ioctl(dev, DIOCGETALTQS, &pa)) {
+ warn("DIOCGETALTQS");
+ return (-1);
+ }
+
+ /* if a new set is found, start over */
+ if (pa.ticket != last_ticket && *root != NULL) {
+ pfctl_free_altq_node(*root);
+ *root = NULL;
+ }
+ last_ticket = pa.ticket;
+
+ mnr = pa.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pa.nr = nr;
+ if (ioctl(dev, DIOCGETALTQ, &pa)) {
+ warn("DIOCGETALTQ");
+ return (-1);
+ }
+#ifdef __FreeBSD__
+ if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
+ !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
+#else
+ if (pa.altq.qid > 0) {
+#endif
+ pq.nr = nr;
+ pq.ticket = pa.ticket;
+ pq.buf = &qstats.data;
+ pq.nbytes = sizeof(qstats.data);
+ if (ioctl(dev, DIOCGETQSTATS, &pq)) {
+ warn("DIOCGETQSTATS");
+ return (-1);
+ }
+ if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
+ pa.altq.ifname)) != NULL) {
+ memcpy(&node->qstats.data, &qstats.data,
+ sizeof(qstats.data));
+ update_avg(node);
+ } else {
+ pfctl_insert_altq_node(root, pa.altq, qstats);
+ }
+ }
+#ifdef __FreeBSD__
+ else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
+ memset(&qstats.data, 0, sizeof(qstats.data));
+ if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
+ pa.altq.ifname)) != NULL) {
+ memcpy(&node->qstats.data, &qstats.data,
+ sizeof(qstats.data));
+ update_avg(node);
+ } else {
+ pfctl_insert_altq_node(root, pa.altq, qstats);
+ }
+ }
+#endif
+ }
+ return (mnr);
+}
+
+void
+pfctl_insert_altq_node(struct pf_altq_node **root,
+ const struct pf_altq altq, const struct queue_stats qstats)
+{
+ struct pf_altq_node *node;
+
+ node = calloc(1, sizeof(struct pf_altq_node));
+ if (node == NULL)
+ err(1, "pfctl_insert_altq_node: calloc");
+ memcpy(&node->altq, &altq, sizeof(struct pf_altq));
+ memcpy(&node->qstats, &qstats, sizeof(qstats));
+ node->next = node->children = NULL;
+
+ if (*root == NULL)
+ *root = node;
+ else if (!altq.parent[0]) {
+ struct pf_altq_node *prev = *root;
+
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = node;
+ } else {
+ struct pf_altq_node *parent;
+
+ parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found", altq.parent);
+ if (parent->children == NULL)
+ parent->children = node;
+ else {
+ struct pf_altq_node *prev = parent->children;
+
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = node;
+ }
+ }
+ update_avg(node);
+}
+
+struct pf_altq_node *
+pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
+ const char *ifname)
+{
+ struct pf_altq_node *node, *child;
+
+ for (node = root; node != NULL; node = node->next) {
+ if (!strcmp(node->altq.qname, qname)
+ && !(strcmp(node->altq.ifname, ifname)))
+ return (node);
+ if (node->children != NULL) {
+ child = pfctl_find_altq_node(node->children, qname,
+ ifname);
+ if (child != NULL)
+ return (child);
+ }
+ }
+ return (NULL);
+}
+
+void
+pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
+ unsigned int level, int opts)
+{
+ const struct pf_altq_node *child;
+
+ if (node == NULL)
+ return;
+
+ print_altq(&node->altq, level, NULL, NULL);
+
+ if (node->children != NULL) {
+ printf("{");
+ for (child = node->children; child != NULL;
+ child = child->next) {
+ printf("%s", child->altq.qname);
+ if (child->next != NULL)
+ printf(", ");
+ }
+ printf("}");
+ }
+ printf("\n");
+
+ if (opts & PF_OPT_VERBOSE)
+ pfctl_print_altq_nodestat(dev, node);
+
+ if (opts & PF_OPT_DEBUG)
+ printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
+ node->altq.qid, node->altq.ifname,
+ rate2str((double)(node->altq.ifbandwidth)));
+
+ for (child = node->children; child != NULL;
+ child = child->next)
+ pfctl_print_altq_node(dev, child, level + 1, opts);
+}
+
+void
+pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
+{
+ if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
+ return;
+
+#ifdef __FreeBSD__
+ if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
+ return;
+#endif
+ switch (a->altq.scheduler) {
+ case ALTQT_CBQ:
+ print_cbqstats(a->qstats);
+ break;
+ case ALTQT_PRIQ:
+ print_priqstats(a->qstats);
+ break;
+ case ALTQT_HFSC:
+ print_hfscstats(a->qstats);
+ break;
+ case ALTQT_FAIRQ:
+ print_fairqstats(a->qstats);
+ break;
+ case ALTQT_CODEL:
+ print_codelstats(a->qstats);
+ break;
+ }
+}
+
+void
+print_cbqstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
+ (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
+ (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
+ (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
+ cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
+ cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_codelstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
+ (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
+ (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
+ cur.data.codel_stats.stats.drop_cnt.packets,
+ (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
+ cur.data.codel_stats.stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_priqstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
+ (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
+ (unsigned long long)cur.data.priq_stats.dropcnt.packets,
+ (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_hfscstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
+ (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
+ (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
+ (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_fairqstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
+ (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
+ (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
+ (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+pfctl_free_altq_node(struct pf_altq_node *node)
+{
+ while (node != NULL) {
+ struct pf_altq_node *prev;
+
+ if (node->children != NULL)
+ pfctl_free_altq_node(node->children);
+ prev = node;
+ node = node->next;
+ free(prev);
+ }
+}
+
+void
+update_avg(struct pf_altq_node *a)
+{
+ struct queue_stats *qs;
+ u_int64_t b, p;
+ int n;
+
+ if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
+ return;
+
+ qs = &a->qstats;
+ n = qs->avgn;
+
+ switch (a->altq.scheduler) {
+ case ALTQT_CBQ:
+ b = qs->data.cbq_stats.xmit_cnt.bytes;
+ p = qs->data.cbq_stats.xmit_cnt.packets;
+ break;
+ case ALTQT_PRIQ:
+ b = qs->data.priq_stats.xmitcnt.bytes;
+ p = qs->data.priq_stats.xmitcnt.packets;
+ break;
+ case ALTQT_HFSC:
+ b = qs->data.hfsc_stats.xmit_cnt.bytes;
+ p = qs->data.hfsc_stats.xmit_cnt.packets;
+ break;
+ case ALTQT_FAIRQ:
+ b = qs->data.fairq_stats.xmit_cnt.bytes;
+ p = qs->data.fairq_stats.xmit_cnt.packets;
+ break;
+ case ALTQT_CODEL:
+ b = qs->data.codel_stats.cl_xmitcnt.bytes;
+ p = qs->data.codel_stats.cl_xmitcnt.packets;
+ break;
+ default:
+ b = 0;
+ p = 0;
+ break;
+ }
+
+ if (n == 0) {
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ qs->avgn++;
+ return;
+ }
+
+ if (b >= qs->prev_bytes)
+ qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
+ (b - qs->prev_bytes)) / n;
+
+ if (p >= qs->prev_packets)
+ qs->avg_packets = ((qs->avg_packets * (n - 1)) +
+ (p - qs->prev_packets)) / n;
+
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ if (n < AVGN_MAX)
+ qs->avgn++;
+}
diff --git a/freebsd/sbin/pfctl/pfctl_radix.c b/freebsd/sbin/pfctl/pfctl_radix.c
new file mode 100644
index 00000000..c151f878
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_radix.c
@@ -0,0 +1,597 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <err.h>
+
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_radix-data.h"
+#endif /* __rtems__ */
+
+#define BUF_SIZE 256
+
+extern int dev;
+
+static int pfr_next_token(char buf[], FILE *);
+
+
+int
+pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (filter != NULL)
+ io.pfrio_table = *filter;
+ if (ioctl(dev, DIOCRCLRTABLES, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRADDTABLES, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ return (0);
+}
+
+int
+pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRDELTABLES, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (filter != NULL)
+ io.pfrio_table = *filter;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETTABLES, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (filter != NULL)
+ io.pfrio_table = *filter;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETTSTATS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ if (ioctl(dev, DIOCRCLRADDRS, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nadd, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRADDADDRS, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ return (0);
+}
+
+int
+pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRDELADDRS, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *size2, int *nadd, int *ndel, int *nchange, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
+ if (ioctl(dev, DIOCRSETADDRS, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ if (nchange != NULL)
+ *nchange = io.pfrio_nchange;
+ if (size2 != NULL)
+ *size2 = io.pfrio_size2;
+ return (0);
+}
+
+int
+pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size == NULL || *size < 0 ||
+ (*size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETADDRS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size == NULL || *size < 0 ||
+ (*size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETASTATS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && !tbl)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRCLRTSTATS, &io))
+ return (-1);
+ if (nzero)
+ *nzero = io.pfrio_nzero;
+ return (0);
+}
+
+int
+pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nmatch, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRTSTADDRS, &io))
+ return (-1);
+ if (nmatch)
+ *nmatch = io.pfrio_nmatch;
+ return (0);
+}
+
+int
+pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nadd, int *naddr, int ticket, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ io.pfrio_ticket = ticket;
+ if (ioctl(dev, DIOCRINADEFINE, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ if (naddr != NULL)
+ *naddr = io.pfrio_naddr;
+ return (0);
+}
+
+/* interface management code */
+
+int
+pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
+{
+ struct pfioc_iface io;
+
+ if (size == NULL || *size < 0 || (*size && buf == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ if (filter != NULL)
+ if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
+ sizeof(io.pfiio_name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ io.pfiio_buffer = buf;
+ io.pfiio_esize = sizeof(*buf);
+ io.pfiio_size = *size;
+ if (ioctl(dev, DIOCIGETIFACES, &io))
+ return (-1);
+ *size = io.pfiio_size;
+ return (0);
+}
+
+/* buffer management code */
+
+const size_t buf_esize[PFRB_MAX] = { 0,
+ sizeof(struct pfr_table), sizeof(struct pfr_tstats),
+ sizeof(struct pfr_addr), sizeof(struct pfr_astats),
+ sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
+};
+
+/*
+ * add one element to the buffer
+ */
+int
+pfr_buf_add(struct pfr_buffer *b, const void *e)
+{
+ size_t bs;
+
+ if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
+ e == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bs = buf_esize[b->pfrb_type];
+ if (b->pfrb_size == b->pfrb_msize)
+ if (pfr_buf_grow(b, 0))
+ return (-1);
+ memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
+ b->pfrb_size++;
+ return (0);
+}
+
+/*
+ * return next element of the buffer (or first one if prev is NULL)
+ * see PFRB_FOREACH macro
+ */
+void *
+pfr_buf_next(struct pfr_buffer *b, const void *prev)
+{
+ size_t bs;
+
+ if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
+ return (NULL);
+ if (b->pfrb_size == 0)
+ return (NULL);
+ if (prev == NULL)
+ return (b->pfrb_caddr);
+ bs = buf_esize[b->pfrb_type];
+ if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
+ return (NULL);
+ return (((caddr_t)prev) + bs);
+}
+
+/*
+ * minsize:
+ * 0: make the buffer somewhat bigger
+ * n: make room for "n" entries in the buffer
+ */
+int
+pfr_buf_grow(struct pfr_buffer *b, int minsize)
+{
+ caddr_t p;
+ size_t bs;
+
+ if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (minsize != 0 && minsize <= b->pfrb_msize)
+ return (0);
+ bs = buf_esize[b->pfrb_type];
+ if (!b->pfrb_msize) {
+ if (minsize < 64)
+ minsize = 64;
+ b->pfrb_caddr = calloc(bs, minsize);
+ if (b->pfrb_caddr == NULL)
+ return (-1);
+ b->pfrb_msize = minsize;
+ } else {
+ if (minsize == 0)
+ minsize = b->pfrb_msize * 2;
+ if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
+ /* msize overflow */
+ errno = ENOMEM;
+ return (-1);
+ }
+ p = realloc(b->pfrb_caddr, minsize * bs);
+ if (p == NULL)
+ return (-1);
+ bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
+ b->pfrb_caddr = p;
+ b->pfrb_msize = minsize;
+ }
+ return (0);
+}
+
+/*
+ * reset buffer and free memory.
+ */
+void
+pfr_buf_clear(struct pfr_buffer *b)
+{
+ if (b == NULL)
+ return;
+ if (b->pfrb_caddr != NULL)
+ free(b->pfrb_caddr);
+ b->pfrb_caddr = NULL;
+ b->pfrb_size = b->pfrb_msize = 0;
+}
+
+int
+pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
+ int (*append_addr)(struct pfr_buffer *, char *, int))
+{
+ FILE *fp;
+ char buf[BUF_SIZE];
+ int rv;
+
+ if (file == NULL)
+ return (0);
+ if (!strcmp(file, "-"))
+ fp = stdin;
+ else {
+ fp = pfctl_fopen(file, "r");
+ if (fp == NULL)
+ return (-1);
+ }
+ while ((rv = pfr_next_token(buf, fp)) == 1)
+ if (append_addr(b, buf, nonetwork)) {
+ rv = -1;
+ break;
+ }
+ if (fp != stdin)
+ fclose(fp);
+ return (rv);
+}
+
+int
+pfr_next_token(char buf[BUF_SIZE], FILE *fp)
+{
+ static char next_ch = ' ';
+ int i = 0;
+
+ for (;;) {
+ /* skip spaces */
+ while (isspace(next_ch) && !feof(fp))
+ next_ch = fgetc(fp);
+ /* remove from '#' until end of line */
+ if (next_ch == '#')
+ while (!feof(fp)) {
+ next_ch = fgetc(fp);
+ if (next_ch == '\n')
+ break;
+ }
+ else
+ break;
+ }
+ if (feof(fp)) {
+ next_ch = ' ';
+ return (0);
+ }
+ do {
+ if (i < BUF_SIZE)
+ buf[i++] = next_ch;
+ next_ch = fgetc(fp);
+ } while (!feof(fp) && !isspace(next_ch));
+ if (i >= BUF_SIZE) {
+ errno = EINVAL;
+ return (-1);
+ }
+ buf[i] = '\0';
+ return (1);
+}
+
+char *
+pfr_strerror(int errnum)
+{
+ switch (errnum) {
+ case ESRCH:
+ return "Table does not exist";
+ case ENOENT:
+ return "Anchor or Ruleset does not exist";
+ default:
+ return strerror(errnum);
+ }
+}
diff --git a/freebsd/sbin/pfctl/pfctl_table.c b/freebsd/sbin/pfctl/pfctl_table.c
new file mode 100644
index 00000000..4dfb0689
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_table.c
@@ -0,0 +1,650 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_table-data.h"
+#endif /* __rtems__ */
+
+extern void usage(void);
+static int pfctl_table(int, char *[], char *, const char *, char *,
+ const char *, int);
+static void print_table(struct pfr_table *, int, int);
+static void print_tstats(struct pfr_tstats *, int);
+static int load_addr(struct pfr_buffer *, int, char *[], char *, int);
+static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
+static void print_astats(struct pfr_astats *, int);
+static void radix_perror(void);
+static void xprintf(int, const char *, ...);
+static void print_iface(struct pfi_kif *, int);
+
+static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
+ { "In/Block:", "In/Pass:", "In/XPass:" },
+ { "Out/Block:", "Out/Pass:", "Out/XPass:" }
+};
+
+static const char *istats_text[2][2][2] = {
+ { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } },
+ { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } }
+};
+
+#define RVTEST(fct) do { \
+ if ((!(opts & PF_OPT_NOACTION) || \
+ (opts & PF_OPT_DUMMYACTION)) && \
+ (fct)) { \
+ radix_perror(); \
+ goto _error; \
+ } \
+ } while (0)
+
+#define CREATE_TABLE do { \
+ table.pfrt_flags |= PFR_TFLAG_PERSIST; \
+ if ((!(opts & PF_OPT_NOACTION) || \
+ (opts & PF_OPT_DUMMYACTION)) && \
+ (pfr_add_tables(&table, 1, &nadd, flags)) && \
+ (errno != EPERM)) { \
+ radix_perror(); \
+ goto _error; \
+ } \
+ if (nadd) { \
+ warn_namespace_collision(table.pfrt_name); \
+ xprintf(opts, "%d table created", nadd); \
+ if (opts & PF_OPT_NOACTION) \
+ return (0); \
+ } \
+ table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \
+ } while(0)
+
+int
+pfctl_clear_tables(const char *anchor, int opts)
+{
+ return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts);
+}
+
+int
+pfctl_show_tables(const char *anchor, int opts)
+{
+ return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, opts);
+}
+
+int
+pfctl_command_tables(int argc, char *argv[], char *tname,
+ const char *command, char *file, const char *anchor, int opts)
+{
+ if (tname == NULL || command == NULL)
+ usage();
+ return pfctl_table(argc, argv, tname, command, file, anchor, opts);
+}
+
+int
+pfctl_table(int argc, char *argv[], char *tname, const char *command,
+ char *file, const char *anchor, int opts)
+{
+ struct pfr_table table;
+ struct pfr_buffer b, b2;
+ struct pfr_addr *a, *a2;
+ int nadd = 0, ndel = 0, nchange = 0, nzero = 0;
+ int rv = 0, flags = 0, nmatch = 0;
+ void *p;
+
+ if (command == NULL)
+ usage();
+ if (opts & PF_OPT_NOACTION)
+ flags |= PFR_FLAG_DUMMY;
+
+ bzero(&b, sizeof(b));
+ bzero(&b2, sizeof(b2));
+ bzero(&table, sizeof(table));
+ if (tname != NULL) {
+ if (strlen(tname) >= PF_TABLE_NAME_SIZE)
+ usage();
+ if (strlcpy(table.pfrt_name, tname,
+ sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
+ errx(1, "pfctl_table: strlcpy");
+ }
+ if (strlcpy(table.pfrt_anchor, anchor,
+ sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor))
+ errx(1, "pfctl_table: strlcpy");
+
+ if (!strcmp(command, "-F")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_clr_tables(&table, &ndel, flags));
+ xprintf(opts, "%d tables deleted", ndel);
+ } else if (!strcmp(command, "-s")) {
+ b.pfrb_type = (opts & PF_OPT_VERBOSE2) ?
+ PFRB_TSTATS : PFRB_TABLES;
+ if (argc || file != NULL)
+ usage();
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (opts & PF_OPT_VERBOSE2)
+ RVTEST(pfr_get_tstats(&table,
+ b.pfrb_caddr, &b.pfrb_size, flags));
+ else
+ RVTEST(pfr_get_tables(&table,
+ b.pfrb_caddr, &b.pfrb_size, flags));
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+
+ if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0)
+ pfctl_print_title("TABLES:");
+
+ PFRB_FOREACH(p, &b)
+ if (opts & PF_OPT_VERBOSE2)
+ print_tstats(p, opts & PF_OPT_DEBUG);
+ else
+ print_table(p, opts & PF_OPT_VERBOSE,
+ opts & PF_OPT_DEBUG);
+ } else if (!strcmp(command, "kill")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_del_tables(&table, 1, &ndel, flags));
+ xprintf(opts, "%d table deleted", ndel);
+ } else if (!strcmp(command, "flush")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_clr_addrs(&table, &ndel, flags));
+ xprintf(opts, "%d addresses deleted", ndel);
+ } else if (!strcmp(command, "add")) {
+ b.pfrb_type = PFRB_ADDRS;
+ if (load_addr(&b, argc, argv, file, 0))
+ goto _error;
+ CREATE_TABLE;
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &nadd, flags));
+ xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size);
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "delete")) {
+ b.pfrb_type = PFRB_ADDRS;
+ if (load_addr(&b, argc, argv, file, 0))
+ goto _error;
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &ndel, flags));
+ xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size);
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "replace")) {
+ b.pfrb_type = PFRB_ADDRS;
+ if (load_addr(&b, argc, argv, file, 0))
+ goto _error;
+ CREATE_TABLE;
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ for (;;) {
+ int sz2 = b.pfrb_msize;
+
+ RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &sz2, &nadd, &ndel, &nchange, flags));
+ if (sz2 <= b.pfrb_msize) {
+ b.pfrb_size = sz2;
+ break;
+ } else
+ pfr_buf_grow(&b, sz2);
+ }
+ if (nadd)
+ xprintf(opts, "%d addresses added", nadd);
+ if (ndel)
+ xprintf(opts, "%d addresses deleted", ndel);
+ if (nchange)
+ xprintf(opts, "%d addresses changed", nchange);
+ if (!nadd && !ndel && !nchange)
+ xprintf(opts, "no changes");
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "expire")) {
+ const char *errstr;
+ u_int lifetime;
+
+ b.pfrb_type = PFRB_ASTATS;
+ b2.pfrb_type = PFRB_ADDRS;
+ if (argc != 1 || file != NULL)
+ usage();
+ lifetime = strtonum(*argv, 0, UINT_MAX, &errstr);
+ if (errstr)
+ errx(1, "expiry time: %s", errstr);
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
+ &b.pfrb_size, flags));
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+ PFRB_FOREACH(p, &b) {
+ ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0;
+ if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero >
+ lifetime)
+ if (pfr_buf_add(&b2,
+ &((struct pfr_astats *)p)->pfras_a))
+ err(1, "duplicate buffer");
+ }
+
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size,
+ &ndel, flags));
+ xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size);
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b2)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "show")) {
+ b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
+ PFRB_ASTATS : PFRB_ADDRS;
+ if (argc || file != NULL)
+ usage();
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (opts & PF_OPT_VERBOSE)
+ RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
+ &b.pfrb_size, flags));
+ else
+ RVTEST(pfr_get_addrs(&table, b.pfrb_caddr,
+ &b.pfrb_size, flags));
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+ PFRB_FOREACH(p, &b)
+ if (opts & PF_OPT_VERBOSE)
+ print_astats(p, opts & PF_OPT_USEDNS);
+ else
+ print_addrx(p, NULL, opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "test")) {
+ b.pfrb_type = PFRB_ADDRS;
+ b2.pfrb_type = PFRB_ADDRS;
+
+ if (load_addr(&b, argc, argv, file, 1))
+ goto _error;
+ if (opts & PF_OPT_VERBOSE2) {
+ flags |= PFR_FLAG_REPLACE;
+ PFRB_FOREACH(a, &b)
+ if (pfr_buf_add(&b2, a))
+ err(1, "duplicate buffer");
+ }
+ RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &nmatch, flags));
+ xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size);
+ if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2))
+ PFRB_FOREACH(a, &b)
+ if (a->pfra_fback == PFR_FB_MATCH)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ if (opts & PF_OPT_VERBOSE2) {
+ a2 = NULL;
+ PFRB_FOREACH(a, &b) {
+ a2 = pfr_buf_next(&b2, a2);
+ print_addrx(a2, a, opts & PF_OPT_USEDNS);
+ }
+ }
+ if (nmatch < b.pfrb_size)
+ rv = 2;
+ } else if (!strcmp(command, "zero")) {
+ if (argc || file != NULL)
+ usage();
+ flags |= PFR_FLAG_ADDRSTOO;
+ RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
+ xprintf(opts, "%d table/stats cleared", nzero);
+ } else
+ warnx("pfctl_table: unknown command '%s'", command);
+ goto _cleanup;
+
+_error:
+ rv = -1;
+_cleanup:
+ pfr_buf_clear(&b);
+ pfr_buf_clear(&b2);
+ return (rv);
+}
+
+void
+print_table(struct pfr_table *ta, int verbose, int debug)
+{
+ if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE))
+ return;
+ if (verbose) {
+ printf("%c%c%c%c%c%c%c\t%s",
+ (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-',
+ ta->pfrt_name);
+ if (ta->pfrt_anchor[0])
+ printf("\t%s", ta->pfrt_anchor);
+ puts("");
+ } else
+ puts(ta->pfrt_name);
+}
+
+void
+print_tstats(struct pfr_tstats *ts, int debug)
+{
+ time_t time = ts->pfrts_tzero;
+ int dir, op;
+
+ if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
+ return;
+ print_table(&ts->pfrts_t, 1, debug);
+ printf("\tAddresses: %d\n", ts->pfrts_cnt);
+ printf("\tCleared: %s", ctime(&time));
+ printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n",
+ ts->pfrts_refcnt[PFR_REFCNT_ANCHOR],
+ ts->pfrts_refcnt[PFR_REFCNT_RULE]);
+ printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n",
+ (unsigned long long)ts->pfrts_nomatch,
+ (unsigned long long)ts->pfrts_match);
+ for (dir = 0; dir < PFR_DIR_MAX; dir++)
+ for (op = 0; op < PFR_OP_TABLE_MAX; op++)
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ stats_text[dir][op],
+ (unsigned long long)ts->pfrts_packets[dir][op],
+ (unsigned long long)ts->pfrts_bytes[dir][op]);
+}
+
+int
+load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file,
+ int nonetwork)
+{
+ while (argc--)
+ if (append_addr(b, *argv++, nonetwork)) {
+ if (errno)
+ warn("cannot decode %s", argv[-1]);
+ return (-1);
+ }
+ if (pfr_buf_load(b, file, nonetwork, append_addr)) {
+ warn("cannot load %s", file);
+ return (-1);
+ }
+ return (0);
+}
+
+void
+print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
+{
+ char ch, buf[256] = "{error}";
+ char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' };
+ unsigned int fback, hostnet;
+
+ fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback;
+ ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?';
+ hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32;
+ inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf));
+ printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf);
+ if (ad->pfra_net < hostnet)
+ printf("/%d", ad->pfra_net);
+ if (rad != NULL && fback != PFR_FB_NONE) {
+ if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf))
+ errx(1, "print_addrx: strlcpy");
+ inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf));
+ printf("\t%c%s", (rad->pfra_not?'!':' '), buf);
+ if (rad->pfra_net < hostnet)
+ printf("/%d", rad->pfra_net);
+ }
+ if (rad != NULL && fback == PFR_FB_NONE)
+ printf("\t nomatch");
+ if (dns && ad->pfra_net == hostnet) {
+ char host[NI_MAXHOST];
+ union sockaddr_union sa;
+
+ strlcpy(host, "?", sizeof(host));
+ bzero(&sa, sizeof(sa));
+ sa.sa.sa_family = ad->pfra_af;
+ if (sa.sa.sa_family == AF_INET) {
+ sa.sa.sa_len = sizeof(sa.sin);
+ sa.sin.sin_addr = ad->pfra_ip4addr;
+ } else {
+ sa.sa.sa_len = sizeof(sa.sin6);
+ sa.sin6.sin6_addr = ad->pfra_ip6addr;
+ }
+ if (getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host),
+ NULL, 0, NI_NAMEREQD) == 0)
+ printf("\t(%s)", host);
+ }
+ printf("\n");
+}
+
+void
+print_astats(struct pfr_astats *as, int dns)
+{
+ time_t time = as->pfras_tzero;
+ int dir, op;
+
+ print_addrx(&as->pfras_a, NULL, dns);
+ printf("\tCleared: %s", ctime(&time));
+ if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT)
+ return;
+ for (dir = 0; dir < PFR_DIR_MAX; dir++)
+ for (op = 0; op < PFR_OP_ADDR_MAX; op++)
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ stats_text[dir][op],
+ (unsigned long long)as->pfras_packets[dir][op],
+ (unsigned long long)as->pfras_bytes[dir][op]);
+}
+
+void
+radix_perror(void)
+{
+#ifndef __rtems__
+ extern char *__progname;
+#else /* __rtems__ */
+#define __progname "pfctl"
+#endif /* __rtems__ */
+ fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno));
+}
+
+int
+pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
+ struct pfr_buffer *ab, u_int32_t ticket)
+{
+ struct pfr_table tbl;
+
+ bzero(&tbl, sizeof(tbl));
+ if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >=
+ sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor,
+ sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor))
+ errx(1, "pfctl_define_table: strlcpy");
+ tbl.pfrt_flags = flags;
+
+ return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL,
+ NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0);
+}
+
+void
+warn_namespace_collision(const char *filter)
+{
+ struct pfr_buffer b;
+ struct pfr_table *t;
+ const char *name = NULL, *lastcoll;
+ int coll = 0;
+
+ bzero(&b, sizeof(b));
+ b.pfrb_type = PFRB_TABLES;
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (pfr_get_tables(NULL, b.pfrb_caddr,
+ &b.pfrb_size, PFR_FLAG_ALLRSETS))
+ err(1, "pfr_get_tables");
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+ PFRB_FOREACH(t, &b) {
+ if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE))
+ continue;
+ if (filter != NULL && strcmp(filter, t->pfrt_name))
+ continue;
+ if (!t->pfrt_anchor[0])
+ name = t->pfrt_name;
+ else if (name != NULL && !strcmp(name, t->pfrt_name)) {
+ coll++;
+ lastcoll = name;
+ name = NULL;
+ }
+ }
+ if (coll == 1)
+ warnx("warning: namespace collision with <%s> global table.",
+ lastcoll);
+ else if (coll > 1)
+ warnx("warning: namespace collisions with %d global tables.",
+ coll);
+ pfr_buf_clear(&b);
+}
+
+void
+xprintf(int opts, const char *fmt, ...)
+{
+ va_list args;
+
+ if (opts & PF_OPT_QUIET)
+ return;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ if (opts & PF_OPT_DUMMYACTION)
+ fprintf(stderr, " (dummy).\n");
+ else if (opts & PF_OPT_NOACTION)
+ fprintf(stderr, " (syntax only).\n");
+ else
+ fprintf(stderr, ".\n");
+}
+
+
+/* interface stuff */
+
+int
+pfctl_show_ifaces(const char *filter, int opts)
+{
+ struct pfr_buffer b;
+ struct pfi_kif *p;
+ int i = 0;
+
+ bzero(&b, sizeof(b));
+ b.pfrb_type = PFRB_IFACES;
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) {
+ radix_perror();
+ return (1);
+ }
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ i++;
+ }
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("INTERFACES:");
+ PFRB_FOREACH(p, &b)
+ print_iface(p, opts);
+ return (0);
+}
+
+void
+print_iface(struct pfi_kif *p, int opts)
+{
+ time_t tzero = p->pfik_tzero;
+ int i, af, dir, act;
+
+ printf("%s", p->pfik_name);
+ if (opts & PF_OPT_VERBOSE) {
+ if (p->pfik_flags & PFI_IFLAG_SKIP)
+ printf(" (skip)");
+ }
+ printf("\n");
+
+ if (!(opts & PF_OPT_VERBOSE2))
+ return;
+ printf("\tCleared: %s", ctime(&tzero));
+ printf("\tReferences: %-18d\n", p->pfik_rulerefs);
+ for (i = 0; i < 8; i++) {
+ af = (i>>2) & 1;
+ dir = (i>>1) &1;
+ act = i & 1;
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ istats_text[af][dir][act],
+ (unsigned long long)p->pfik_packets[af][dir][act],
+ (unsigned long long)p->pfik_bytes[af][dir][act]);
+ }
+}
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h
new file mode 100644
index 00000000..3984522e
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h
@@ -0,0 +1,25 @@
+/* generated by userspace-header-gen.py */
+/*
+ * NOTE: MANUALLY CHANGED.
+ * YACC needs a special treatment for some variables. They are commented here.
+ */
+#include <rtems/linkersets.h>
+/* parse.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlydebug);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlynerrs);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlyerrflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlychar);
+/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval); */
+/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval); */
+/* pfctl_altq.c */
+/* pfctl.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int loadopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int altqsupport);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int dev);
+/* pfctl_optimize.c */
+/* pfctl_osfp.c */
+/* pfctl_parser.c */
+/* pfctl_qstats.c */
+/* pfctl_radix.c */
+/* pfctl_table.c */
+/* pf_print_state.c */
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h
new file mode 100644
index 00000000..4e815fee
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h
@@ -0,0 +1,262 @@
+/* generated by userspace-header-gen.py */
+/* parse.c */
+#define pfctlydebug _bsd_pfctl_pfctlydebug
+#define pfctlynerrs _bsd_pfctl_pfctlynerrs
+#define pfctlyerrflag _bsd_pfctl_pfctlyerrflag
+#define pfctlychar _bsd_pfctl_pfctlychar
+#define pfctlyval _bsd_pfctl_pfctlyval
+#define pfctlylval _bsd_pfctl_pfctlylval
+#define pfctlyparse _bsd_pfctl_pfctlyparse
+#define rt_tableid_max _bsd_pfctl_rt_tableid_max
+#define pfctl_load_anchors _bsd_pfctl_pfctl_load_anchors
+#define parseport _bsd_pfctl_parseport
+#define parseicmpspec _bsd_pfctl_parseicmpspec
+#define rule_label _bsd_pfctl_rule_label
+#define getservice _bsd_pfctl_getservice
+#define atoul _bsd_pfctl_atoul
+#define invalid_redirect _bsd_pfctl_invalid_redirect
+#define remove_invalid_hosts _bsd_pfctl_remove_invalid_hosts
+#define decide_address_family _bsd_pfctl_decide_address_family
+#define mv_rules _bsd_pfctl_mv_rules
+#define symget _bsd_pfctl_symget
+#define pfctl_cmdline_symset _bsd_pfctl_pfctl_cmdline_symset
+#define symset _bsd_pfctl_symset
+#define parse_config _bsd_pfctl_parse_config
+#define popfile _bsd_pfctl_popfile
+#define pushfile _bsd_pfctl_pushfile
+#define check_file_secrecy _bsd_pfctl_check_file_secrecy
+#define pfctlylex _bsd_pfctl_pfctlylex
+#define findeol _bsd_pfctl_findeol
+#define lungetc _bsd_pfctl_lungetc
+#define lgetc _bsd_pfctl_lgetc
+#define lookup _bsd_pfctl_lookup
+#define kw_cmp _bsd_pfctl_kw_cmp
+#define check_rulestate _bsd_pfctl_check_rulestate
+#define expand_skip_interface _bsd_pfctl_expand_skip_interface
+#define expand_rule _bsd_pfctl_expand_rule
+#define expand_queue _bsd_pfctl_expand_queue
+#define expand_altq _bsd_pfctl_expand_altq
+#define expand_label _bsd_pfctl_expand_label
+#define expand_label_nr _bsd_pfctl_expand_label_nr
+#define expand_label_proto _bsd_pfctl_expand_label_proto
+#define expand_label_port _bsd_pfctl_expand_label_port
+#define expand_label_addr _bsd_pfctl_expand_label_addr
+#define expand_label_if _bsd_pfctl_expand_label_if
+#define expand_label_str _bsd_pfctl_expand_label_str
+#define process_tabledef _bsd_pfctl_process_tabledef
+#define rdr_consistent _bsd_pfctl_rdr_consistent
+#define nat_consistent _bsd_pfctl_nat_consistent
+#define filter_consistent _bsd_pfctl_filter_consistent
+#define rule_consistent _bsd_pfctl_rule_consistent
+#define disallow_alias _bsd_pfctl_disallow_alias
+#define disallow_urpf_failed _bsd_pfctl_disallow_urpf_failed
+#define disallow_table _bsd_pfctl_disallow_table
+#define pfctlyerror _bsd_pfctl_pfctlyerror
+/* pfctl_altq.c */
+#define print_fairq_sc _bsd_pfctl_print_fairq_sc
+#define print_hfsc_sc _bsd_pfctl_print_hfsc_sc
+#define eval_bwspec _bsd_pfctl_eval_bwspec
+#define eval_queue_opts _bsd_pfctl_eval_queue_opts
+#define getifmtu _bsd_pfctl_getifmtu
+#define getifspeed _bsd_pfctl_getifspeed
+#define rate2str _bsd_pfctl_rate2str
+#define eval_pfqueue _bsd_pfctl_eval_pfqueue
+#define check_commit_altq _bsd_pfctl_check_commit_altq
+#define eval_pfaltq _bsd_pfctl_eval_pfaltq
+#define print_queue _bsd_pfctl_print_queue
+#define print_altq _bsd_pfctl_print_altq
+#define qname_to_qid _bsd_pfctl_qname_to_qid
+#define qname_to_pfaltq _bsd_pfctl_qname_to_pfaltq
+#define pfaltq_lookup _bsd_pfctl_pfaltq_lookup
+#define pfaltq_store _bsd_pfctl_pfaltq_store
+/* pfctl.c */
+#define loadopt _bsd_pfctl_loadopt
+#define altqsupport _bsd_pfctl_altqsupport
+#define dev _bsd_pfctl_dev
+#define pfctl_lookup_option _bsd_pfctl_pfctl_lookup_option
+#define pfctl_show_anchors _bsd_pfctl_pfctl_show_anchors
+#define pfctl_test_altqsupport _bsd_pfctl_pfctl_test_altqsupport
+#define pfctl_debug _bsd_pfctl_pfctl_debug
+#define pfctl_set_interface_flags _bsd_pfctl_pfctl_set_interface_flags
+#define pfctl_load_debug _bsd_pfctl_pfctl_load_debug
+#define pfctl_set_debug _bsd_pfctl_pfctl_set_debug
+#define pfctl_load_hostid _bsd_pfctl_pfctl_load_hostid
+#define pfctl_set_hostid _bsd_pfctl_pfctl_set_hostid
+#define pfctl_load_logif _bsd_pfctl_pfctl_load_logif
+#define pfctl_set_logif _bsd_pfctl_pfctl_set_logif
+#define pfctl_set_optimization _bsd_pfctl_pfctl_set_optimization
+#define pfctl_load_timeout _bsd_pfctl_pfctl_load_timeout
+#define pfctl_set_timeout _bsd_pfctl_pfctl_set_timeout
+#define pfctl_load_limit _bsd_pfctl_pfctl_load_limit
+#define pfctl_set_limit _bsd_pfctl_pfctl_set_limit
+#define pfctl_load_options _bsd_pfctl_pfctl_load_options
+#define pfctl_init_options _bsd_pfctl_pfctl_init_options
+#define pfctl_fopen _bsd_pfctl_pfctl_fopen
+#define pfctl_rules _bsd_pfctl_pfctl_rules
+#define pfctl_add_altq _bsd_pfctl_pfctl_add_altq
+#define pfctl_load_rule _bsd_pfctl_pfctl_load_rule
+#define pfctl_load_ruleset _bsd_pfctl_pfctl_load_ruleset
+#define pfctl_ruleset_trans _bsd_pfctl_pfctl_ruleset_trans
+#define pfctl_add_rule _bsd_pfctl_pfctl_add_rule
+#define pfctl_add_pool _bsd_pfctl_pfctl_add_pool
+#define pfctl_show_limits _bsd_pfctl_pfctl_show_limits
+#define pfctl_show_timeouts _bsd_pfctl_pfctl_show_timeouts
+#define pfctl_show_status _bsd_pfctl_pfctl_show_status
+#define pfctl_show_states _bsd_pfctl_pfctl_show_states
+#define pfctl_show_src_nodes _bsd_pfctl_pfctl_show_src_nodes
+#define pfctl_show_nat _bsd_pfctl_pfctl_show_nat
+#define pfctl_show_rules _bsd_pfctl_pfctl_show_rules
+#define pfctl_print_title _bsd_pfctl_pfctl_print_title
+#define pfctl_print_rule_counters _bsd_pfctl_pfctl_print_rule_counters
+#define pfctl_clear_pool _bsd_pfctl_pfctl_clear_pool
+#define pfctl_move_pool _bsd_pfctl_pfctl_move_pool
+#define pfctl_get_pool _bsd_pfctl_pfctl_get_pool
+#define pfctl_id_kill_states _bsd_pfctl_pfctl_id_kill_states
+#define pfctl_label_kill_states _bsd_pfctl_pfctl_label_kill_states
+#define pfctl_net_kill_states _bsd_pfctl_pfctl_net_kill_states
+#define pfctl_kill_src_nodes _bsd_pfctl_pfctl_kill_src_nodes
+#define pfctl_addrprefix _bsd_pfctl_pfctl_addrprefix
+#define pfctl_clear_states _bsd_pfctl_pfctl_clear_states
+#define pfctl_clear_src_nodes _bsd_pfctl_pfctl_clear_src_nodes
+#define pfctl_clear_altq _bsd_pfctl_pfctl_clear_altq
+#define pfctl_clear_nat _bsd_pfctl_pfctl_clear_nat
+#define pfctl_clear_rules _bsd_pfctl_pfctl_clear_rules
+#define pfctl_clear_interface_flags _bsd_pfctl_pfctl_clear_interface_flags
+#define pfctl_clear_stats _bsd_pfctl_pfctl_clear_stats
+#define pfctl_disable _bsd_pfctl_pfctl_disable
+#define pfctl_enable _bsd_pfctl_pfctl_enable
+#define usage _bsd_pfctl_usage
+/* pfctl_optimize.c */
+#define superblock_free _bsd_pfctl_superblock_free
+#define exclude_supersets _bsd_pfctl_exclude_supersets
+#define comparable_rule _bsd_pfctl_comparable_rule
+#define interface_group _bsd_pfctl_interface_group
+#define superblock_inclusive _bsd_pfctl_superblock_inclusive
+#define rules_combineable _bsd_pfctl_rules_combineable
+#define addrs_combineable _bsd_pfctl_addrs_combineable
+#define addrs_equal _bsd_pfctl_addrs_equal
+#define construct_superblocks _bsd_pfctl_construct_superblocks
+#define pf_opt_create_table _bsd_pfctl_pf_opt_create_table
+#define add_opt_table _bsd_pfctl_add_opt_table
+#define skip_init _bsd_pfctl_skip_init
+#define skip_cmp_src_port _bsd_pfctl_skip_cmp_src_port
+#define skip_cmp_src_addr _bsd_pfctl_skip_cmp_src_addr
+#define skip_cmp_proto _bsd_pfctl_skip_cmp_proto
+#define skip_cmp_ifp _bsd_pfctl_skip_cmp_ifp
+#define skip_cmp_dst_port _bsd_pfctl_skip_cmp_dst_port
+#define skip_cmp_dst_addr _bsd_pfctl_skip_cmp_dst_addr
+#define skip_cmp_dir _bsd_pfctl_skip_cmp_dir
+#define skip_cmp_af _bsd_pfctl_skip_cmp_af
+#define remove_from_skipsteps _bsd_pfctl_remove_from_skipsteps
+#define skip_append _bsd_pfctl_skip_append
+#define skip_compare _bsd_pfctl_skip_compare
+#define load_feedback_profile _bsd_pfctl_load_feedback_profile
+#define block_feedback _bsd_pfctl_block_feedback
+#define reorder_rules _bsd_pfctl_reorder_rules
+#define combine_rules _bsd_pfctl_combine_rules
+#define remove_identical_rules _bsd_pfctl_remove_identical_rules
+#define optimize_superblock _bsd_pfctl_optimize_superblock
+#define pfctl_optimize_ruleset _bsd_pfctl_pfctl_optimize_ruleset
+/* pfctl_osfp.c */
+#define print_ioctl _bsd_pfctl_print_ioctl
+#define get_field _bsd_pfctl_get_field
+#define get_tcpopts _bsd_pfctl_get_tcpopts
+#define get_str _bsd_pfctl_get_str
+#define get_int _bsd_pfctl_get_int
+#define sort_name_list _bsd_pfctl_sort_name_list
+#define print_name_list _bsd_pfctl_print_name_list
+#define fingerprint_name_entry _bsd_pfctl_fingerprint_name_entry
+#define import_fingerprint _bsd_pfctl_import_fingerprint
+#define add_fingerprint _bsd_pfctl_add_fingerprint
+#define lookup_name_list _bsd_pfctl_lookup_name_list
+#define pfctl_lookup_fingerprint _bsd_pfctl_pfctl_lookup_fingerprint
+#define pfctl_get_fingerprint _bsd_pfctl_pfctl_get_fingerprint
+#define pfctl_show_fingerprints _bsd_pfctl_pfctl_show_fingerprints
+#define pfctl_load_fingerprints _bsd_pfctl_pfctl_load_fingerprints
+#define pfctl_flush_my_fingerprints _bsd_pfctl_pfctl_flush_my_fingerprints
+#define pfctl_clear_fingerprints _bsd_pfctl_pfctl_clear_fingerprints
+#define pfctl_file_fingerprints _bsd_pfctl_pfctl_file_fingerprints
+/* pfctl_parser.c */
+#define pfctl_trans _bsd_pfctl_pfctl_trans
+#define pfctl_get_ticket _bsd_pfctl_pfctl_get_ticket
+#define pfctl_add_trans _bsd_pfctl_pfctl_add_trans
+#define append_addr_host _bsd_pfctl_append_addr_host
+#define append_addr _bsd_pfctl_append_addr
+#define host_dns _bsd_pfctl_host_dns
+#define host_v6 _bsd_pfctl_host_v6
+#define host_v4 _bsd_pfctl_host_v4
+#define host_if _bsd_pfctl_host_if
+#define host _bsd_pfctl_host
+#define ifa_skip_if _bsd_pfctl_ifa_skip_if
+#define ifa_lookup _bsd_pfctl_ifa_lookup
+#define ifa_grouplookup _bsd_pfctl_ifa_grouplookup
+#define ifa_exists _bsd_pfctl_ifa_exists
+#define get_socket_domain _bsd_pfctl_get_socket_domain
+#define ifa_load _bsd_pfctl_ifa_load
+#define check_netmask _bsd_pfctl_check_netmask
+#define set_ipmask _bsd_pfctl_set_ipmask
+#define parse_flags _bsd_pfctl_parse_flags
+#define print_tabledef _bsd_pfctl_print_tabledef
+#define print_rule _bsd_pfctl_print_rule
+#define print_src_node _bsd_pfctl_print_src_node
+#define print_status _bsd_pfctl_print_status
+#define print_pool _bsd_pfctl_print_pool
+#define print_fromto _bsd_pfctl_print_fromto
+#define print_flags _bsd_pfctl_print_flags
+#define print_ugid _bsd_pfctl_print_ugid
+#define print_port _bsd_pfctl_print_port
+#define print_op _bsd_pfctl_print_op
+#define geticmpcodebyname _bsd_pfctl_geticmpcodebyname
+#define geticmpcodebynumber _bsd_pfctl_geticmpcodebynumber
+#define geticmptypebyname _bsd_pfctl_geticmptypebyname
+#define geticmptypebynumber _bsd_pfctl_geticmptypebynumber
+/* pfctl_qstats.c */
+#define update_avg _bsd_pfctl_update_avg
+#define pfctl_free_altq_node _bsd_pfctl_pfctl_free_altq_node
+#define print_fairqstats _bsd_pfctl_print_fairqstats
+#define print_hfscstats _bsd_pfctl_print_hfscstats
+#define print_priqstats _bsd_pfctl_print_priqstats
+#define print_codelstats _bsd_pfctl_print_codelstats
+#define print_cbqstats _bsd_pfctl_print_cbqstats
+#define pfctl_print_altq_nodestat _bsd_pfctl_pfctl_print_altq_nodestat
+#define pfctl_print_altq_node _bsd_pfctl_pfctl_print_altq_node
+#define pfctl_find_altq_node _bsd_pfctl_pfctl_find_altq_node
+#define pfctl_insert_altq_node _bsd_pfctl_pfctl_insert_altq_node
+#define pfctl_update_qstats _bsd_pfctl_pfctl_update_qstats
+#define pfctl_show_altq _bsd_pfctl_pfctl_show_altq
+/* pfctl_radix.c */
+#define pfr_strerror _bsd_pfctl_pfr_strerror
+#define pfr_buf_load _bsd_pfctl_pfr_buf_load
+#define pfr_buf_clear _bsd_pfctl_pfr_buf_clear
+#define pfr_buf_grow _bsd_pfctl_pfr_buf_grow
+#define pfr_buf_next _bsd_pfctl_pfr_buf_next
+#define pfr_buf_add _bsd_pfctl_pfr_buf_add
+#define pfi_get_ifaces _bsd_pfctl_pfi_get_ifaces
+#define pfr_ina_define _bsd_pfctl_pfr_ina_define
+#define pfr_tst_addrs _bsd_pfctl_pfr_tst_addrs
+#define pfr_clr_tstats _bsd_pfctl_pfr_clr_tstats
+#define pfr_get_astats _bsd_pfctl_pfr_get_astats
+#define pfr_get_addrs _bsd_pfctl_pfr_get_addrs
+#define pfr_set_addrs _bsd_pfctl_pfr_set_addrs
+#define pfr_del_addrs _bsd_pfctl_pfr_del_addrs
+#define pfr_add_addrs _bsd_pfctl_pfr_add_addrs
+#define pfr_clr_addrs _bsd_pfctl_pfr_clr_addrs
+#define pfr_get_tstats _bsd_pfctl_pfr_get_tstats
+#define pfr_get_tables _bsd_pfctl_pfr_get_tables
+#define pfr_del_tables _bsd_pfctl_pfr_del_tables
+#define pfr_add_tables _bsd_pfctl_pfr_add_tables
+#define pfr_clr_tables _bsd_pfctl_pfr_clr_tables
+/* pfctl_table.c */
+#define pfctl_show_ifaces _bsd_pfctl_pfctl_show_ifaces
+#define warn_namespace_collision _bsd_pfctl_warn_namespace_collision
+#define pfctl_define_table _bsd_pfctl_pfctl_define_table
+#define pfctl_command_tables _bsd_pfctl_pfctl_command_tables
+#define pfctl_show_tables _bsd_pfctl_pfctl_show_tables
+#define pfctl_clear_tables _bsd_pfctl_pfctl_clear_tables
+/* pf_print_state.c */
+#define unmask _bsd_pfctl_unmask
+#define print_state _bsd_pfctl_print_state
+#define print_seq _bsd_pfctl_print_seq
+#define print_host _bsd_pfctl_print_host
+#define print_name _bsd_pfctl_print_name
+#define print_addr _bsd_pfctl_print_addr
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h
new file mode 100644
index 00000000..ed13a43a
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h
@@ -0,0 +1,36 @@
+/* generated by userspace-header-gen.py */
+/*
+ * NOTE: MANUALLY CHANGED.
+ * YACC needs a special treatment for some variables. They are commented here.
+ */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* parse.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pfctl *pf);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int debug);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int rulestate);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmpdefault);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmp6default);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int blockpolicy);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int require_order);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int default_statelock);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct files files);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct file *file);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct symhead symhead);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_queue *queues);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct filter_opts filter_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct antispoof_opts antispoof_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct scrub_opts scrub_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct queue_opts queue_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct table_opts table_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pool_opts pool_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct codel_opts codel_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_hfsc_opts hfsc_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_fairq_opts fairq_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_state_opt *keep_state_defaults);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct loadanchorshead loadanchorshead);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *parsebuf);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int parseindex);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pushback_index);
+/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack); */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char pushback_buffer[]);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h
new file mode 100644
index 00000000..33366e0d
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h
@@ -0,0 +1,4 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pf_print_state.c */
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h
new file mode 100644
index 00000000..65956d58
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h
@@ -0,0 +1,22 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_anchor_global pf_anchors);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_anchor pf_main_anchor);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *clearopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *rulesopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *showopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *debugopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *anchoropt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *optiopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *pf_device);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *ifaceopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *tableopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *tblcmdopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int src_node_killers);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int state_killers);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int first_title);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int labels);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *src_node_kill[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *state_kill[]);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h
new file mode 100644
index 00000000..6a032132
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h
@@ -0,0 +1,9 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_altq.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct altqs altqs);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc rtsc);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc lssc);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char r2sbuf[8][16]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int idx);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h
new file mode 100644
index 00000000..09598a79
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h
@@ -0,0 +1,11 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_optimize.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_rule_field pf_rule_desc[70]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int (*skip_comparitors[8])(struct pf_rule *, struct pf_rule *));
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *skip_comparitors_names[8]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pfr_buffer table_buffer);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int table_identifier);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int add_opt_tablenum);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pf_opt_create_tablenum);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h
new file mode 100644
index 00000000..53bf09c4
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h
@@ -0,0 +1,7 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_osfp.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct name_list classes);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int class_count);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int fingerprint_count);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h
new file mode 100644
index 00000000..bb8832ac
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h
@@ -0,0 +1,5 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_parser.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_host *iftab);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h
new file mode 100644
index 00000000..0ee02a9e
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h
@@ -0,0 +1,5 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_qstats.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int32_t last_ticket);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h
new file mode 100644
index 00000000..b2a7340e
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h
@@ -0,0 +1,4 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_radix.c */
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h
new file mode 100644
index 00000000..db4e915b
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h
@@ -0,0 +1,6 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_table.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *stats_text[2][3]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *istats_text[2][2][2]);