parse.y revision 1.380
1/*	$OpenBSD: parse.y,v 1.380 2003/05/14 22:46:01 henning Exp $	*/
2
3/*
4 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
5 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27%{
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <net/if.h>
31#include <netinet/in.h>
32#include <netinet/in_systm.h>
33#include <netinet/ip.h>
34#include <netinet/ip_icmp.h>
35#include <netinet/icmp6.h>
36#include <net/pfvar.h>
37#include <arpa/inet.h>
38#include <altq/altq.h>
39#include <altq/altq_cbq.h>
40#include <altq/altq_priq.h>
41#include <altq/altq_hfsc.h>
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <netdb.h>
46#include <stdarg.h>
47#include <errno.h>
48#include <string.h>
49#include <ctype.h>
50#include <err.h>
51#include <pwd.h>
52#include <grp.h>
53#include <md5.h>
54
55#include "pfctl_parser.h"
56#include "pfctl.h"
57
58static struct pfctl	*pf = NULL;
59static FILE		*fin = NULL;
60static int		 debug = 0;
61static int		 lineno = 1;
62static int		 errors = 0;
63static int		 rulestate = 0;
64static u_int16_t	 returnicmpdefault =
65			    (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
66static u_int16_t	 returnicmp6default =
67			    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
68static int		 blockpolicy = PFRULE_DROP;
69static int		 require_order = 1;
70
71enum {
72	PFCTL_STATE_NONE,
73	PFCTL_STATE_OPTION,
74	PFCTL_STATE_SCRUB,
75	PFCTL_STATE_QUEUE,
76	PFCTL_STATE_NAT,
77	PFCTL_STATE_FILTER
78};
79
80struct node_proto {
81	u_int8_t		 proto;
82	struct node_proto	*next;
83	struct node_proto	*tail;
84};
85
86struct node_port {
87	u_int16_t		 port[2];
88	u_int8_t		 op;
89	struct node_port	*next;
90	struct node_port	*tail;
91};
92
93struct node_uid {
94	uid_t			 uid[2];
95	u_int8_t		 op;
96	struct node_uid		*next;
97	struct node_uid		*tail;
98};
99
100struct node_gid {
101	gid_t			 gid[2];
102	u_int8_t		 op;
103	struct node_gid		*next;
104	struct node_gid		*tail;
105};
106
107struct node_icmp {
108	u_int8_t		 code;
109	u_int8_t		 type;
110	u_int8_t		 proto;
111	struct node_icmp	*next;
112	struct node_icmp	*tail;
113};
114
115enum	{ PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 };
116struct node_state_opt {
117	int			 type;
118	union {
119		u_int32_t	 max_states;
120		struct {
121			int		number;
122			u_int32_t	seconds;
123		}		 timeout;
124	}			 data;
125	struct node_state_opt	*next;
126	struct node_state_opt	*tail;
127};
128
129struct peer {
130	struct node_host	*host;
131	struct node_port	*port;
132};
133
134struct node_queue {
135	char			 queue[PF_QNAME_SIZE];
136	char			 parent[PF_QNAME_SIZE];
137	char			 ifname[IFNAMSIZ];
138	int			 scheduler;
139	struct node_queue	*next;
140	struct node_queue	*tail;
141}	*queues = NULL;
142
143struct node_qassign {
144	char		*qname;
145	char		*pqname;
146};
147
148struct filter_opts {
149	int			 marker;
150#define FOM_FLAGS	0x01
151#define FOM_ICMP	0x02
152#define FOM_TOS		0x04
153#define FOM_KEEP	0x08
154	struct node_uid		*uid;
155	struct node_gid		*gid;
156	struct {
157		u_int8_t	 b1;
158		u_int8_t	 b2;
159		u_int16_t	 w;
160		u_int16_t	 w2;
161	} flags;
162	struct node_icmp	*icmpspec;
163	u_int32_t		 tos;
164	struct {
165		int			 action;
166		struct node_state_opt	*options;
167	} keep;
168	int			 fragment;
169	int			 allowopts;
170	char			*label;
171	struct node_qassign	 queues;
172	char			*tag;
173	char			*match_tag;
174} filter_opts;
175
176struct antispoof_opts {
177	char			*label;
178} antispoof_opts;
179
180struct scrub_opts {
181	int			marker;
182#define SOM_MINTTL	0x01
183#define SOM_MAXMSS	0x02
184#define SOM_FRAGCACHE	0x04
185	int			nodf;
186	int			minttl;
187	int			maxmss;
188	int			fragcache;
189	int			randomid;
190} scrub_opts;
191
192struct queue_opts {
193	int			marker;
194#define QOM_BWSPEC	0x01
195#define QOM_SCHEDULER	0x02
196#define QOM_PRIORITY	0x04
197#define QOM_TBRSIZE	0x08
198#define QOM_QLIMIT	0x10
199	struct node_queue_bw	queue_bwspec;
200	struct node_queue_opt	scheduler;
201	int			priority;
202	int			tbrsize;
203	int			qlimit;
204} queue_opts;
205
206struct table_opts {
207	int			flags;
208	int			init_addr;
209} table_opts;
210
211struct node_hfsc_opts	hfsc_opts;
212
213int	yyerror(const char *, ...);
214int	disallow_table(struct node_host *, const char *);
215int	rule_consistent(struct pf_rule *);
216int	filter_consistent(struct pf_rule *);
217int	nat_consistent(struct pf_rule *);
218int	rdr_consistent(struct pf_rule *);
219int	yyparse(void);
220void	expand_label_str(char *, const char *, const char *);
221void	expand_label_if(const char *, char *, const char *);
222void	expand_label_addr(const char *, char *, u_int8_t, struct node_host *);
223void	expand_label_port(const char *, char *, struct node_port *);
224void	expand_label_proto(const char *, char *, u_int8_t);
225void	expand_label_nr(const char *, char *);
226void	expand_label(char *, const char *, u_int8_t, struct node_host *,
227	    struct node_port *, struct node_host *, struct node_port *,
228	    u_int8_t);
229void	expand_rule(struct pf_rule *, struct node_if *, struct node_host *,
230	    struct node_proto *, struct node_host *, struct node_port *,
231	    struct node_host *, struct node_port *, struct node_uid *,
232	    struct node_gid *, struct node_icmp *);
233int	expand_altq(struct pf_altq *, struct node_if *, struct node_queue *,
234	    struct node_queue_bw bwspec, struct node_queue_opt *);
235int	expand_queue(struct pf_altq *, struct node_if *, struct node_queue *,
236	    struct node_queue_bw, struct node_queue_opt *);
237
238int	 check_rulestate(int);
239int	 kw_cmp(const void *, const void *);
240int	 lookup(char *);
241int	 lgetc(FILE *);
242int	 lungetc(int);
243int	 findeol(void);
244int	 yylex(void);
245int	 atoul(char *, u_long *);
246int	 getservice(char *);
247int	 rule_label(struct pf_rule *, char *);
248
249TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
250struct sym {
251	TAILQ_ENTRY(sym)	 entries;
252	int			 used;
253	int			 persist;
254	char			*nam;
255	char			*val;
256};
257
258
259int	 symset(const char *, const char *, int);
260char	*symget(const char *);
261
262void	 decide_address_family(struct node_host *, sa_family_t *);
263void	 remove_invalid_hosts(struct node_host **, sa_family_t *);
264int	 invalid_redirect(struct node_host *, sa_family_t);
265u_int16_t parseicmpspec(char *, sa_family_t);
266
267TAILQ_HEAD(loadanchorshead, loadanchors)	 loadanchorshead =
268   TAILQ_HEAD_INITIALIZER(loadanchorshead);
269struct loadanchors {
270	TAILQ_ENTRY(loadanchors)	 entries;
271	char				*anchorname;
272	char				*rulesetname;
273	char				*filename;
274};
275
276typedef struct {
277	union {
278		u_int32_t		 number;
279		int			 i;
280		char			*string;
281		struct {
282			u_int8_t	 b1;
283			u_int8_t	 b2;
284			u_int16_t	 w;
285			u_int16_t	 w2;
286		}			 b;
287		struct range {
288			int		 a;
289			int		 b;
290			int		 t;
291		}			 range;
292		struct node_if		*interface;
293		struct node_proto	*proto;
294		struct node_icmp	*icmp;
295		struct node_host	*host;
296		struct node_port	*port;
297		struct node_uid		*uid;
298		struct node_gid		*gid;
299		struct node_state_opt	*state_opt;
300		struct peer		 peer;
301		struct {
302			struct peer	 src, dst;
303		}			 fromto;
304		struct pf_poolhashkey	*hashkey;
305		struct {
306			struct node_host	*host;
307			u_int8_t		 rt;
308			u_int8_t		 pool_opts;
309			sa_family_t		 af;
310			struct pf_poolhashkey	*key;
311		}			 route;
312		struct redirection {
313			struct node_host	*host;
314			struct range		 rport;
315		}			*redirection;
316		struct {
317			int			 type;
318			struct pf_poolhashkey	*key;
319		}			 pooltype;
320		struct {
321			int			 action;
322			struct node_state_opt	*options;
323		}			 keep_state;
324		struct {
325			u_int8_t	 log;
326			u_int8_t	 quick;
327		}			 logquick;
328		struct node_queue	*queue;
329		struct node_queue_opt	 queue_options;
330		struct node_queue_bw	 queue_bwspec;
331		struct node_qassign	 qassign;
332		struct filter_opts	 filter_opts;
333		struct antispoof_opts	 antispoof_opts;
334		struct queue_opts	 queue_opts;
335		struct scrub_opts	 scrub_opts;
336		struct table_opts	 table_opts;
337		struct node_hfsc_opts	 hfsc_opts;
338	} v;
339	int lineno;
340} YYSTYPE;
341
342#define PREPARE_ANCHOR_RULE(r, a)				\
343	do {							\
344		memset(&(r), 0, sizeof(r));			\
345		if (strlcpy(r.anchorname, (a),			\
346		    sizeof(r.anchorname)) >=			\
347		    sizeof(r.anchorname)) {			\
348			yyerror("anchor name '%s' too long",	\
349			    (a));				\
350			YYERROR;				\
351		}						\
352	} while (0)
353
354%}
355
356%token	PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS
357%token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
358%token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
359%token	MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
360%token	NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
361%token	FRAGNORM FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
362%token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
363%token	REQUIREORDER
364%token	ANTISPOOF FOR
365%token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT
366%token	ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
367%token	QUEUE PRIORITY QLIMIT
368%token	LOAD
369%token	TAGGED TAG
370%token	<v.string>		STRING
371%token	<v.i>			PORTBINARY
372%type	<v.interface>		interface if_list if_item_not if_item
373%type	<v.number>		number icmptype icmp6type uid gid
374%type	<v.number>		tos not yesno
375%type	<v.i>			no dir log af fragcache
376%type	<v.i>			staticport unaryop
377%type	<v.b>			action nataction flags flag blockspec
378%type	<v.range>		port rport
379%type	<v.hashkey>		hashkey
380%type	<v.pooltype>		pooltype
381%type	<v.proto>		proto proto_list proto_item
382%type	<v.icmp>		icmpspec
383%type	<v.icmp>		icmp_list icmp_item
384%type	<v.icmp>		icmp6_list icmp6_item
385%type	<v.fromto>		fromto
386%type	<v.peer>		ipportspec from to
387%type	<v.host>		ipspec xhost host dynaddr host_list
388%type	<v.host>		redir_host_list redirspec
389%type	<v.host>		route_host route_host_list routespec
390%type	<v.port>		portspec port_list port_item
391%type	<v.uid>			uids uid_list uid_item
392%type	<v.gid>			gids gid_list gid_item
393%type	<v.route>		route
394%type	<v.redirection>		redirection redirpool
395%type	<v.string>		label string tag
396%type	<v.keep_state>		keep
397%type	<v.state_opt>		state_opt_spec state_opt_list state_opt_item
398%type	<v.logquick>		logquick
399%type	<v.interface>		antispoof_ifspc antispoof_iflst
400%type	<v.qassign>		qname
401%type	<v.queue>		qassign qassign_list qassign_item
402%type	<v.queue_options>	scheduler
403%type	<v.number>		cbqflags_list cbqflags_item
404%type	<v.number>		priqflags_list priqflags_item
405%type	<v.hfsc_opts>		hfscopts_list hfscopts_item hfsc_opts
406%type	<v.queue_bwspec>	bandwidth
407%type	<v.filter_opts>		filter_opts filter_opt filter_opts_l
408%type	<v.antispoof_opts>	antispoof_opts antispoof_opt antispoof_opts_l
409%type	<v.queue_opts>		queue_opts queue_opt queue_opts_l
410%type	<v.scrub_opts>		scrub_opts scrub_opt scrub_opts_l
411%type	<v.table_opts>		table_opts table_opt table_opts_l
412%%
413
414ruleset		: /* empty */
415		| ruleset '\n'
416		| ruleset option '\n'
417		| ruleset scrubrule '\n'
418		| ruleset natrule '\n'
419		| ruleset binatrule '\n'
420		| ruleset pfrule '\n'
421		| ruleset anchorrule '\n'
422		| ruleset loadrule '\n'
423		| ruleset altqif '\n'
424		| ruleset queuespec '\n'
425		| ruleset varset '\n'
426		| ruleset antispoof '\n'
427		| ruleset tabledef '\n'
428		| ruleset error '\n'		{ errors++; }
429		;
430
431option		: SET OPTIMIZATION STRING		{
432			if (check_rulestate(PFCTL_STATE_OPTION))
433				YYERROR;
434			if (pfctl_set_optimization(pf, $3) != 0) {
435				yyerror("unknown optimization %s", $3);
436				YYERROR;
437			}
438		}
439		| SET TIMEOUT timeout_spec
440		| SET TIMEOUT '{' timeout_list '}'
441		| SET LIMIT limit_spec
442		| SET LIMIT '{' limit_list '}'
443		| SET LOGINTERFACE STRING		{
444			if (check_rulestate(PFCTL_STATE_OPTION))
445				YYERROR;
446			if ((ifa_exists($3) == NULL) && strcmp($3, "none")) {
447				yyerror("interface %s doesn't exist", $3);
448				YYERROR;
449			}
450			if (pfctl_set_logif(pf, $3) != 0) {
451				yyerror("error setting loginterface %s", $3);
452				YYERROR;
453			}
454		}
455		| SET BLOCKPOLICY DROP	{
456			if (pf->opts & PF_OPT_VERBOSE)
457				printf("set block-policy drop\n");
458			if (check_rulestate(PFCTL_STATE_OPTION))
459				YYERROR;
460			blockpolicy = PFRULE_DROP;
461		}
462		| SET BLOCKPOLICY RETURN {
463			if (pf->opts & PF_OPT_VERBOSE)
464				printf("set block-policy return\n");
465			if (check_rulestate(PFCTL_STATE_OPTION))
466				YYERROR;
467			blockpolicy = PFRULE_RETURN;
468		}
469		| SET REQUIREORDER yesno {
470			if (pf->opts & PF_OPT_VERBOSE)
471				printf("set require-order %s\n",
472				    $3 == 1 ? "yes" : "no");
473			require_order = $3;
474		}
475		;
476
477string		: string STRING				{
478			if (asprintf(&$$, "%s %s", $1, $2) == -1)
479				err(1, "string: asprintf");
480			free($1);
481			free($2);
482		}
483		| STRING
484		;
485
486varset		: STRING '=' string		{
487			if (pf->opts & PF_OPT_VERBOSE)
488				printf("%s = \"%s\"\n", $1, $3);
489			if (symset($1, $3, 0) == -1)
490				err(1, "cannot store variable %s", $1);
491		}
492		;
493
494anchorrule	: ANCHOR string	dir interface af proto fromto {
495			struct pf_rule	r;
496
497			if (check_rulestate(PFCTL_STATE_FILTER))
498				YYERROR;
499
500			PREPARE_ANCHOR_RULE(r, $2);
501			r.direction = $3;
502			r.af = $5;
503
504			decide_address_family($7.src.host, &r.af);
505			decide_address_family($7.dst.host, &r.af);
506
507			expand_rule(&r, $4, NULL, $6,
508			    $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
509			    0, 0, 0);
510		}
511		| NATANCHOR string interface af proto fromto {
512			struct pf_rule	r;
513
514			if (check_rulestate(PFCTL_STATE_NAT))
515				YYERROR;
516
517			PREPARE_ANCHOR_RULE(r, $2);
518			r.action = PF_NAT;
519			r.af = $4;
520
521			decide_address_family($6.src.host, &r.af);
522			decide_address_family($6.dst.host, &r.af);
523
524			expand_rule(&r, $3, NULL, $5,
525			    $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
526			    0, 0, 0);
527		}
528		| RDRANCHOR string interface af proto fromto {
529			struct pf_rule	r;
530
531			if (check_rulestate(PFCTL_STATE_NAT))
532				YYERROR;
533
534			PREPARE_ANCHOR_RULE(r, $2);
535			r.action = PF_RDR;
536			r.af = $4;
537
538			decide_address_family($6.src.host, &r.af);
539			decide_address_family($6.dst.host, &r.af);
540
541			if ($6.src.port != NULL) {
542				yyerror("source port parameter not supported"
543				    " in rdr-anchor");
544				YYERROR;
545			}
546			if ($6.dst.port != NULL) {
547				if ($6.dst.port->next != NULL) {
548					yyerror("destination port list "
549					    "expansion not supported in "
550					    "rdr-anchor");
551					YYERROR;
552				} else if ($6.dst.port->op != PF_OP_EQ) {
553					yyerror("destination port operators"
554					    " not supported in rdr-anchor");
555					YYERROR;
556				}
557				r.dst.port[0] = $6.dst.port->port[0];
558				r.dst.port[1] = $6.dst.port->port[1];
559				r.dst.port_op = $6.dst.port->op;
560			}
561
562			expand_rule(&r, $3, NULL, $5,
563			    $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
564			    0, 0, 0);
565		}
566		| BINATANCHOR string interface af proto fromto {
567			struct pf_rule	r;
568
569			if (check_rulestate(PFCTL_STATE_NAT))
570				YYERROR;
571
572			PREPARE_ANCHOR_RULE(r, $2);
573			r.action = PF_BINAT;
574			r.af = $4;
575			if ($5 != NULL) {
576				if ($5->next != NULL) {
577					yyerror("proto list expansion"
578					    " not supported in binat-anchor");
579					YYERROR;
580				}
581				r.proto = $5->proto;
582				free($5);
583			}
584
585			if ($6.src.host != NULL || $6.src.port != NULL ||
586			    $6.dst.host != NULL || $6.dst.port != NULL) {
587				yyerror("fromto parameter not supported"
588				    " in binat-anchor");
589				YYERROR;
590			}
591
592			decide_address_family($6.src.host, &r.af);
593			decide_address_family($6.dst.host, &r.af);
594
595			pfctl_add_rule(pf, &r);
596		}
597		;
598
599loadrule	: LOAD ANCHOR string FROM string	{
600			char			*t;
601			struct loadanchors	*loadanchor;
602
603			t = strsep(&$3, ":");
604			if (*t == '\0' || *$3 == '\0') {
605				yyerror("anchor '%s' invalid\n", $3);
606				YYERROR;
607			}
608			if (strlen(t) >= PF_ANCHOR_NAME_SIZE) {
609				yyerror("anchorname %s too long, max %u\n",
610				    t, PF_ANCHOR_NAME_SIZE - 1);
611				YYERROR;
612			}
613			if (strlen($3) >= PF_RULESET_NAME_SIZE) {
614				yyerror("rulesetname %s too long, max %u\n",
615				    $3, PF_RULESET_NAME_SIZE - 1);
616				YYERROR;
617			}
618
619			loadanchor = calloc(1, sizeof(struct loadanchors));
620			if (loadanchor == NULL)
621				err(1, "loadrule: calloc");
622			if ((loadanchor->anchorname = strdup(t)) == NULL)
623				err(1, "loadrule: strdup");
624			if ((loadanchor->rulesetname = strdup($3)) == NULL)
625				err(1, "loadrule: strdup");
626			if ((loadanchor->filename = strdup($5)) == NULL)
627				err(1, "loadrule: strdup");
628
629			TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
630			    entries);
631
632			free(t); /* not $3 */
633			free($5);
634		};
635
636scrubrule	: SCRUB dir logquick interface af proto fromto scrub_opts
637		{
638			struct pf_rule	r;
639
640			if (check_rulestate(PFCTL_STATE_SCRUB))
641				YYERROR;
642
643			memset(&r, 0, sizeof(r));
644
645			r.action = PF_SCRUB;
646			r.direction = $2;
647
648			r.log = $3.log;
649			if ($3.quick) {
650				yyerror("scrub rules do not support 'quick'");
651				YYERROR;
652			}
653
654			if ($4) {
655				if ($4->not) {
656					yyerror("scrub rules do not support "
657					    "'! <if>'");
658					YYERROR;
659				}
660			}
661			r.af = $5;
662			if ($8.nodf)
663				r.rule_flag |= PFRULE_NODF;
664			if ($8.randomid)
665				r.rule_flag |= PFRULE_RANDOMID;
666			if ($8.minttl)
667				r.min_ttl = $8.minttl;
668			if ($8.maxmss)
669				r.max_mss = $8.maxmss;
670			if ($8.fragcache)
671				r.rule_flag |= $8.fragcache;
672
673			expand_rule(&r, $4, NULL, $6,
674			    $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
675			    NULL, NULL, NULL);
676		}
677		;
678
679scrub_opts	:	{
680			bzero(&scrub_opts, sizeof scrub_opts);
681		}
682		  scrub_opts_l
683			{ $$ = scrub_opts; }
684		| /* empty */ {
685			bzero(&scrub_opts, sizeof scrub_opts);
686			$$ = scrub_opts;
687		}
688		;
689
690scrub_opts_l	: scrub_opts_l scrub_opt
691		| scrub_opt
692		;
693
694scrub_opt	: NODF	{
695			if (scrub_opts.nodf) {
696				yyerror("no-df cannot be respecified");
697				YYERROR;
698			}
699			scrub_opts.nodf = 1;
700		}
701		| MINTTL number {
702			if (scrub_opts.marker & SOM_MINTTL) {
703				yyerror("min-ttl cannot be respecified");
704				YYERROR;
705			}
706			if ($2 > 255) {
707				yyerror("illegal min-ttl value %d", $2);
708				YYERROR;
709			}
710			scrub_opts.marker |= SOM_MINTTL;
711			scrub_opts.minttl = $2;
712		}
713		| MAXMSS number {
714			if (scrub_opts.marker & SOM_MAXMSS) {
715				yyerror("max-mss cannot be respecified");
716				YYERROR;
717			}
718			scrub_opts.marker |= SOM_MAXMSS;
719			scrub_opts.maxmss = $2;
720		}
721		| fragcache {
722			if (scrub_opts.marker & SOM_FRAGCACHE) {
723				yyerror("fragcache cannot be respecified");
724				YYERROR;
725			}
726			scrub_opts.marker |= SOM_FRAGCACHE;
727			scrub_opts.fragcache = $1;
728		}
729		| RANDOMID {
730			if (scrub_opts.randomid) {
731				yyerror("random-id cannot be respecified");
732				YYERROR;
733			}
734			scrub_opts.randomid = 1;
735		}
736		;
737
738fragcache	: FRAGMENT FRAGNORM	{ $$ = 0; /* default */ }
739		| FRAGMENT FRAGCROP	{ $$ = PFRULE_FRAGCROP; }
740		| FRAGMENT FRAGDROP	{ $$ = PFRULE_FRAGDROP; }
741		;
742
743antispoof	: ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
744			struct pf_rule		 r;
745			struct node_host	*h = NULL;
746			struct node_if		*i, *j;
747
748			if (check_rulestate(PFCTL_STATE_FILTER))
749				YYERROR;
750
751			for (i = $3; i; i = i->next) {
752				bzero(&r, sizeof(r));
753
754				r.action = PF_DROP;
755				r.direction = PF_IN;
756				r.log = $2.log;
757				r.quick = $2.quick;
758				r.af = $4;
759				if (rule_label(&r, $5.label))
760					YYERROR;
761				j = calloc(1, sizeof(struct node_if));
762				if (j == NULL)
763					err(1, "antispoof: calloc");
764				if (strlcpy(j->ifname, i->ifname,
765				    sizeof(j->ifname)) >= sizeof(j->ifname)) {
766					free(j);
767					yyerror("interface name too long");
768					YYERROR;
769				}
770				j->not = 1;
771				h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET);
772
773				expand_rule(&r, j, NULL, NULL, h, NULL, NULL,
774				    NULL, NULL, NULL, NULL);
775
776				if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
777					bzero(&r, sizeof(r));
778
779					r.action = PF_DROP;
780					r.direction = PF_IN;
781					r.log = $2.log;
782					r.quick = $2.quick;
783					r.af = $4;
784					if (rule_label(&r, $5.label))
785						YYERROR;
786					h = ifa_lookup(i->ifname,
787					    PFCTL_IFLOOKUP_HOST);
788					expand_rule(&r, NULL, NULL, NULL, h,
789					    NULL, NULL, NULL, NULL, NULL, NULL);
790				}
791			}
792			free($5.label);
793		}
794		;
795
796antispoof_ifspc	: FOR if_item			{ $$ = $2; }
797		| FOR '{' antispoof_iflst '}'	{ $$ = $3; }
798		;
799
800antispoof_iflst	: if_item			{ $$ = $1; }
801		| antispoof_iflst comma if_item	{
802			$1->tail->next = $3;
803			$1->tail = $3;
804			$$ = $1;
805		}
806		;
807
808antispoof_opts	:	{ bzero(&antispoof_opts, sizeof antispoof_opts); }
809		  antispoof_opts_l
810			{ $$ = antispoof_opts; }
811		| /* empty */	{
812			bzero(&antispoof_opts, sizeof antispoof_opts);
813			$$ = antispoof_opts;
814		}
815		;
816
817antispoof_opts_l	: antispoof_opts_l antispoof_opt
818			| antispoof_opt
819			;
820
821antispoof_opt	: label	{
822			if (antispoof_opts.label) {
823				yyerror("label cannot be redefined");
824				YYERROR;
825			}
826			antispoof_opts.label = $1;
827		}
828		;
829
830not		: '!'		{ $$ = 1; }
831		| /* empty */	{ $$ = 0; }
832
833tabledef	: TABLE '<' STRING '>' table_opts {
834			if (strlen($3) >= PF_TABLE_NAME_SIZE) {
835				yyerror("table name too long, max %d chars",
836				    PF_TABLE_NAME_SIZE - 1);
837				YYERROR;
838			}
839			pfctl_define_table($3, $5.flags, $5.init_addr,
840			    (pf->opts & PF_OPT_NOACTION) || !(pf->loadopt &
841				(PFCTL_FLAG_TABLE | PFCTL_FLAG_ALL)),
842				pf->anchor, pf->ruleset);
843		}
844		;
845
846table_opts	:	{
847			bzero(&table_opts, sizeof table_opts);
848		}
849		   table_opts_l
850			{ $$ = table_opts; }
851		| /* empty */
852			{
853			bzero(&table_opts, sizeof table_opts);
854			$$ = table_opts;
855		}
856		;
857
858table_opts_l	: table_opts_l table_opt
859		| table_opt
860		;
861
862table_opt	: STRING
863			{
864			if (!strcmp($1, "const"))
865				table_opts.flags |= PFR_TFLAG_CONST;
866			else if (!strcmp($1, "persist"))
867				table_opts.flags |= PFR_TFLAG_PERSIST;
868			else
869				YYERROR;
870		}
871		| '{' tableaddrs '}'	{ table_opts.init_addr = 1; }
872		| FILENAME STRING	{
873			pfctl_append_file($2);
874			table_opts.init_addr = 1;
875		}
876		;
877
878tableaddrs	: /* empty */
879		| tableaddrs tableaddr comma
880
881tableaddr	: not STRING {
882			pfctl_append_addr($2, -1, $1);
883		}
884		| not STRING '/' number {
885			pfctl_append_addr($2, $4, $1);
886		}
887		;
888
889altqif		: ALTQ interface queue_opts QUEUE qassign {
890			struct pf_altq	a;
891
892			if (check_rulestate(PFCTL_STATE_QUEUE))
893				YYERROR;
894
895			memset(&a, 0, sizeof(a));
896			if ($3.scheduler.qtype == ALTQT_NONE) {
897				yyerror("no scheduler specified!");
898				YYERROR;
899			}
900			a.scheduler = $3.scheduler.qtype;
901			a.qlimit = $3.qlimit;
902			a.tbrsize = $3.tbrsize;
903			if ($5 == NULL) {
904				yyerror("no child queues specified");
905				YYERROR;
906			}
907			if (expand_altq(&a, $2, $5, $3.queue_bwspec,
908			    &$3.scheduler))
909				YYERROR;
910		}
911		;
912
913queuespec	: QUEUE STRING interface queue_opts qassign {
914			struct pf_altq	a;
915
916			if (check_rulestate(PFCTL_STATE_QUEUE))
917				YYERROR;
918
919			memset(&a, 0, sizeof(a));
920
921			if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
922			    sizeof(a.qname)) {
923				yyerror("queue name too long (max "
924				    "%d chars)", PF_QNAME_SIZE-1);
925				YYERROR;
926			}
927			if ($4.tbrsize) {
928				yyerror("cannot specify tbrsize for queue");
929				YYERROR;
930			}
931			if ($4.priority > 255) {
932				yyerror("priority out of range: max 255");
933				YYERROR;
934			}
935			a.priority = $4.priority;
936			a.qlimit = $4.qlimit;
937			a.scheduler = $4.scheduler.qtype;
938			if (expand_queue(&a, $3, $5, $4.queue_bwspec,
939			    &$4.scheduler))
940				YYERROR;
941		}
942		;
943
944queue_opts	:	{
945			bzero(&queue_opts, sizeof queue_opts);
946			queue_opts.priority = DEFAULT_PRIORITY;
947			queue_opts.qlimit = DEFAULT_QLIMIT;
948			queue_opts.scheduler.qtype = ALTQT_NONE;
949			queue_opts.queue_bwspec.bw_percent = 100;
950		}
951		  queue_opts_l
952			{ $$ = queue_opts; }
953		| /* empty */ {
954			bzero(&queue_opts, sizeof queue_opts);
955			queue_opts.priority = DEFAULT_PRIORITY;
956			queue_opts.qlimit = DEFAULT_QLIMIT;
957			queue_opts.scheduler.qtype = ALTQT_NONE;
958			queue_opts.queue_bwspec.bw_percent = 100;
959			$$ = queue_opts;
960		}
961		;
962
963queue_opts_l	: queue_opts_l queue_opt
964		| queue_opt
965		;
966
967queue_opt	: BANDWIDTH bandwidth	{
968			if (queue_opts.marker & QOM_BWSPEC) {
969				yyerror("bandwidth cannot be respecified");
970				YYERROR;
971			}
972			queue_opts.marker |= QOM_BWSPEC;
973			queue_opts.queue_bwspec = $2;
974		}
975		| PRIORITY number	{
976			if (queue_opts.marker & QOM_PRIORITY) {
977				yyerror("priority cannot be respecified");
978				YYERROR;
979			}
980			if ($2 > 255) {
981				yyerror("priority out of range: max 255");
982				YYERROR;
983			}
984			queue_opts.marker |= QOM_PRIORITY;
985			queue_opts.priority = $2;
986		}
987		| QLIMIT number	{
988			if (queue_opts.marker & QOM_QLIMIT) {
989				yyerror("qlimit cannot be respecified");
990				YYERROR;
991			}
992			if ($2 > 65535) {
993				yyerror("qlimit out of range: max 65535");
994				YYERROR;
995			}
996			queue_opts.marker |= QOM_QLIMIT;
997			queue_opts.qlimit = $2;
998		}
999		| scheduler	{
1000			if (queue_opts.marker & QOM_SCHEDULER) {
1001				yyerror("scheduler cannot be respecified");
1002				YYERROR;
1003			}
1004			queue_opts.marker |= QOM_SCHEDULER;
1005			queue_opts.scheduler = $1;
1006		}
1007		| TBRSIZE number	{
1008			if (queue_opts.marker & QOM_TBRSIZE) {
1009				yyerror("tbrsize cannot be respecified");
1010				YYERROR;
1011			}
1012			if ($2 > 65535) {
1013				yyerror("tbrsize too big: max 65535");
1014				YYERROR;
1015			}
1016			queue_opts.marker |= QOM_TBRSIZE;
1017			queue_opts.tbrsize = $2;
1018		}
1019		;
1020
1021bandwidth	: STRING {
1022			double	 bps;
1023			char	*cp;
1024
1025			$$.bw_percent = 0;
1026
1027			bps = strtod($1, &cp);
1028			if (cp != NULL) {
1029				if (!strcmp(cp, "b"))
1030					; /* nothing */
1031				else if (!strcmp(cp, "Kb"))
1032					bps *= 1000;
1033				else if (!strcmp(cp, "Mb"))
1034					bps *= 1000 * 1000;
1035				else if (!strcmp(cp, "Gb"))
1036					bps *= 1000 * 1000 * 1000;
1037				else if (!strcmp(cp, "%")) {
1038					if (bps < 0 || bps > 100) {
1039						yyerror("bandwidth spec "
1040						    "out of range");
1041						YYERROR;
1042					}
1043					$$.bw_percent = bps;
1044					bps = 0;
1045				} else {
1046					yyerror("unknown unit %s", cp);
1047					YYERROR;
1048				}
1049			}
1050			$$.bw_absolute = (u_int32_t)bps;
1051		}
1052
1053scheduler	: CBQ				{
1054			$$.qtype = ALTQT_CBQ;
1055			$$.data.cbq_opts.flags = 0;
1056		}
1057		| CBQ '(' cbqflags_list ')'	{
1058			$$.qtype = ALTQT_CBQ;
1059			$$.data.cbq_opts.flags = $3;
1060		}
1061		| PRIQ				{
1062			$$.qtype = ALTQT_PRIQ;
1063			$$.data.priq_opts.flags = 0;
1064		}
1065		| PRIQ '(' priqflags_list ')'	{
1066			$$.qtype = ALTQT_PRIQ;
1067			$$.data.priq_opts.flags = $3;
1068		}
1069		| HFSC				{
1070			$$.qtype = ALTQT_HFSC;
1071			bzero(&$$.data.hfsc_opts,
1072			    sizeof(struct node_hfsc_opts));
1073		}
1074		| HFSC '(' hfsc_opts ')'	{
1075			$$.qtype = ALTQT_HFSC;
1076			$$.data.hfsc_opts = $3;
1077		}
1078		;
1079
1080cbqflags_list	: cbqflags_item				{ $$ |= $1; }
1081		| cbqflags_list comma cbqflags_item	{ $$ |= $3; }
1082		;
1083
1084cbqflags_item	: STRING	{
1085			if (!strcmp($1, "default"))
1086				$$ = CBQCLF_DEFCLASS;
1087			else if (!strcmp($1, "borrow"))
1088				$$ = CBQCLF_BORROW;
1089			else if (!strcmp($1, "red"))
1090				$$ = CBQCLF_RED;
1091			else if (!strcmp($1, "ecn"))
1092				$$ = CBQCLF_RED|CBQCLF_ECN;
1093			else if (!strcmp($1, "rio"))
1094				$$ = CBQCLF_RIO;
1095			else {
1096				yyerror("unknown cbq flag \"%s\"", $1);
1097				YYERROR;
1098			}
1099		}
1100		;
1101
1102priqflags_list	: priqflags_item			{ $$ |= $1; }
1103		| priqflags_list comma priqflags_item	{ $$ |= $3; }
1104		;
1105
1106priqflags_item	: STRING	{
1107			if (!strcmp($1, "default"))
1108				$$ = PRCF_DEFAULTCLASS;
1109			else if (!strcmp($1, "red"))
1110				$$ = PRCF_RED;
1111			else if (!strcmp($1, "ecn"))
1112				$$ = PRCF_RED|PRCF_ECN;
1113			else if (!strcmp($1, "rio"))
1114				$$ = PRCF_RIO;
1115			else {
1116				yyerror("unknown priq flag \"%s\"", $1);
1117				YYERROR;
1118			}
1119		}
1120		;
1121
1122hfsc_opts	:	{
1123				bzero(&hfsc_opts,
1124				    sizeof(struct node_hfsc_opts));
1125			}
1126		  hfscopts_list				{
1127			$$ = hfsc_opts;
1128		}
1129		;
1130
1131hfscopts_list	: hfscopts_item
1132		| hfscopts_list comma hfscopts_item
1133		;
1134
1135hfscopts_item	: LINKSHARE bandwidth				{
1136			if (hfsc_opts.linkshare.used) {
1137				yyerror("linkshare already specified");
1138				YYERROR;
1139			}
1140			hfsc_opts.linkshare.m2 = $2;
1141			hfsc_opts.linkshare.used = 1;
1142		}
1143		| LINKSHARE '(' bandwidth number bandwidth ')'	{
1144			if (hfsc_opts.linkshare.used) {
1145				yyerror("linkshare already specified");
1146				YYERROR;
1147			}
1148			hfsc_opts.linkshare.m1 = $3;
1149			hfsc_opts.linkshare.d = $4;
1150			hfsc_opts.linkshare.m2 = $5;
1151			hfsc_opts.linkshare.used = 1;
1152		}
1153		| REALTIME bandwidth				{
1154			if (hfsc_opts.realtime.used) {
1155				yyerror("realtime already specified");
1156				YYERROR;
1157			}
1158			hfsc_opts.realtime.m2 = $2;
1159			hfsc_opts.realtime.used = 1;
1160		}
1161		| REALTIME '(' bandwidth number bandwidth ')'	{
1162			if (hfsc_opts.realtime.used) {
1163				yyerror("realtime already specified");
1164				YYERROR;
1165			}
1166			hfsc_opts.realtime.m1 = $3;
1167			hfsc_opts.realtime.d = $4;
1168			hfsc_opts.realtime.m2 = $5;
1169			hfsc_opts.realtime.used = 1;
1170		}
1171		| UPPERLIMIT bandwidth				{
1172			if (hfsc_opts.upperlimit.used) {
1173				yyerror("upperlimit already specified");
1174				YYERROR;
1175			}
1176			hfsc_opts.upperlimit.m2 = $2;
1177			hfsc_opts.upperlimit.used = 1;
1178		}
1179		| UPPERLIMIT '(' bandwidth number bandwidth ')'	{
1180			if (hfsc_opts.upperlimit.used) {
1181				yyerror("upperlimit already specified");
1182				YYERROR;
1183			}
1184			hfsc_opts.upperlimit.m1 = $3;
1185			hfsc_opts.upperlimit.d = $4;
1186			hfsc_opts.upperlimit.m2 = $5;
1187			hfsc_opts.upperlimit.used = 1;
1188		}
1189		| STRING	{
1190			if (!strcmp($1, "default"))
1191				hfsc_opts.flags |= HFCF_DEFAULTCLASS;
1192			else if (!strcmp($1, "red"))
1193				hfsc_opts.flags |= HFCF_RED;
1194			else if (!strcmp($1, "ecn"))
1195				hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
1196			else if (!strcmp($1, "rio"))
1197				hfsc_opts.flags |= HFCF_RIO;
1198			else {
1199				yyerror("unknown hfsc flag \"%s\"", $1);
1200				YYERROR;
1201			}
1202		}
1203		;
1204
1205qassign		: /* empty */		{ $$ = NULL; }
1206		| qassign_item		{ $$ = $1; }
1207		| '{' qassign_list '}'	{ $$ = $2; }
1208		;
1209
1210qassign_list	: qassign_item			{ $$ = $1; }
1211		| qassign_list comma qassign_item	{
1212			$1->tail->next = $3;
1213			$1->tail = $3;
1214			$$ = $1;
1215		}
1216		;
1217
1218qassign_item	: STRING			{
1219			$$ = calloc(1, sizeof(struct node_queue));
1220			if ($$ == NULL)
1221				err(1, "qassign_item: calloc");
1222			if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
1223			    sizeof($$->queue)) {
1224				free($$);
1225				yyerror("queue name '%s' too long (max "
1226				    "%d chars)", $1, sizeof($$->queue)-1);
1227				YYERROR;
1228			}
1229			$$->next = NULL;
1230			$$->tail = $$;
1231		}
1232		;
1233
1234pfrule		: action dir logquick interface route af proto fromto
1235		  filter_opts
1236		{
1237			struct pf_rule		 r;
1238			struct node_state_opt	*o;
1239			struct node_proto	*proto;
1240
1241			if (check_rulestate(PFCTL_STATE_FILTER))
1242				YYERROR;
1243
1244			memset(&r, 0, sizeof(r));
1245
1246			r.action = $1.b1;
1247			switch ($1.b2) {
1248			case PFRULE_RETURNRST:
1249				r.rule_flag |= PFRULE_RETURNRST;
1250				r.return_ttl = $1.w;
1251				break;
1252			case PFRULE_RETURNICMP:
1253				r.rule_flag |= PFRULE_RETURNICMP;
1254				r.return_icmp = $1.w;
1255				r.return_icmp6 = $1.w2;
1256				break;
1257			case PFRULE_RETURN:
1258				r.rule_flag |= PFRULE_RETURN;
1259				r.return_icmp = $1.w;
1260				r.return_icmp6 = $1.w2;
1261				break;
1262			}
1263			r.direction = $2;
1264			r.log = $3.log;
1265			r.quick = $3.quick;
1266
1267			r.af = $6;
1268			if ($9.tag)
1269				strlcpy(r.tagname, $9.tag, PF_TAG_NAME_SIZE);
1270			if ($9.match_tag)
1271				strlcpy(r.match_tagname, $9.match_tag,
1272				    PF_TAG_NAME_SIZE);
1273			r.flags = $9.flags.b1;
1274			r.flagset = $9.flags.b2;
1275			if (rule_label(&r, $9.label))
1276				YYERROR;
1277			free($9.label);
1278			if ($9.flags.b1 || $9.flags.b2) {
1279				for (proto = $7; proto != NULL &&
1280				    proto->proto != IPPROTO_TCP;
1281				    proto = proto->next)
1282					;	/* nothing */
1283				if (proto == NULL && $7 != NULL) {
1284					yyerror("flags only apply to tcp");
1285					YYERROR;
1286				}
1287			}
1288
1289			r.tos = $9.tos;
1290			r.keep_state = $9.keep.action;
1291			o = $9.keep.options;
1292			while (o) {
1293				struct node_state_opt	*p = o;
1294
1295				switch (o->type) {
1296				case PF_STATE_OPT_MAX:
1297					if (r.max_states) {
1298						yyerror("state option 'max' "
1299						    "multiple definitions");
1300						YYERROR;
1301					}
1302					r.max_states = o->data.max_states;
1303					break;
1304				case PF_STATE_OPT_TIMEOUT:
1305					if (r.timeout[o->data.timeout.number]) {
1306						yyerror("state timeout %s "
1307						    "multiple definitions",
1308						    pf_timeouts[o->data.
1309						    timeout.number].name);
1310						YYERROR;
1311					}
1312					r.timeout[o->data.timeout.number] =
1313					    o->data.timeout.seconds;
1314				}
1315				o = o->next;
1316				free(p);
1317			}
1318
1319			if ($9.fragment)
1320				r.rule_flag |= PFRULE_FRAGMENT;
1321			r.allow_opts = $9.allowopts;
1322
1323			decide_address_family($8.src.host, &r.af);
1324			decide_address_family($8.dst.host, &r.af);
1325
1326			if ($5.rt) {
1327				if (!r.direction) {
1328					yyerror("direction must be explicit "
1329					    "with rules that specify routing");
1330					YYERROR;
1331				}
1332				r.rt = $5.rt;
1333				r.rpool.opts = $5.pool_opts;
1334				if ($5.key != NULL)
1335					memcpy(&r.rpool.key, $5.key,
1336					    sizeof(struct pf_poolhashkey));
1337			}
1338			if (r.rt && r.rt != PF_FASTROUTE) {
1339				decide_address_family($5.host, &r.af);
1340				remove_invalid_hosts(&$5.host, &r.af);
1341				if ($5.host == NULL) {
1342					yyerror("no routing address with "
1343					    "matching address family found.");
1344					YYERROR;
1345				}
1346				if ($5.host->next != NULL) {
1347					if (r.rpool.opts == PF_POOL_NONE)
1348						r.rpool.opts =
1349						    PF_POOL_ROUNDROBIN;
1350					if (r.rpool.opts !=
1351					    PF_POOL_ROUNDROBIN) {
1352						yyerror("r.rpool.opts must "
1353						    "be PF_POOL_ROUNDROBIN");
1354						YYERROR;
1355					}
1356				}
1357			}
1358			if ($9.queues.qname != NULL) {
1359				if (strlcpy(r.qname, $9.queues.qname,
1360				    sizeof(r.qname)) >= sizeof(r.qname)) {
1361					yyerror("rule qname too long (max "
1362					    "%d chars)", sizeof(r.qname)-1);
1363					YYERROR;
1364				}
1365				free($9.queues.qname);
1366			}
1367			if ($9.queues.pqname != NULL) {
1368				if (strlcpy(r.pqname, $9.queues.pqname,
1369				    sizeof(r.pqname)) >= sizeof(r.pqname)) {
1370					yyerror("rule pqname too long (max "
1371					    "%d chars)", sizeof(r.pqname)-1);
1372					YYERROR;
1373				}
1374				free($9.queues.pqname);
1375			}
1376
1377			expand_rule(&r, $4, $5.host, $7,
1378			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
1379			    $9.uid, $9.gid, $9.icmpspec);
1380		}
1381		;
1382
1383filter_opts	:	{ bzero(&filter_opts, sizeof filter_opts); }
1384		  filter_opts_l
1385			{ $$ = filter_opts; }
1386		| /* empty */	{
1387			bzero(&filter_opts, sizeof filter_opts);
1388			$$ = filter_opts;
1389		}
1390		;
1391
1392filter_opts_l	: filter_opts_l filter_opt
1393		| filter_opt
1394		;
1395
1396filter_opt	: USER uids {
1397			if (filter_opts.uid)
1398				$2->tail->next = filter_opts.uid;
1399			filter_opts.uid = $2;
1400		}
1401		| GROUP gids {
1402			if (filter_opts.gid)
1403				$2->tail->next = filter_opts.gid;
1404			filter_opts.gid = $2;
1405		}
1406		| flags {
1407			if (filter_opts.marker & FOM_FLAGS) {
1408				yyerror("flags cannot be redefined");
1409				YYERROR;
1410			}
1411			filter_opts.marker |= FOM_FLAGS;
1412			filter_opts.flags.b1 |= $1.b1;
1413			filter_opts.flags.b2 |= $1.b2;
1414			filter_opts.flags.w |= $1.w;
1415			filter_opts.flags.w2 |= $1.w2;
1416		}
1417		| icmpspec {
1418			if (filter_opts.marker & FOM_ICMP) {
1419				yyerror("icmp-type cannot be redefined");
1420				YYERROR;
1421			}
1422			filter_opts.marker |= FOM_ICMP;
1423			filter_opts.icmpspec = $1;
1424		}
1425		| tos {
1426			if (filter_opts.marker & FOM_TOS) {
1427				yyerror("tos cannot be redefined");
1428				YYERROR;
1429			}
1430			filter_opts.marker |= FOM_TOS;
1431			filter_opts.tos = $1;
1432		}
1433		| keep {
1434			if (filter_opts.marker & FOM_KEEP) {
1435				yyerror("modulate or keep cannot be redefined");
1436				YYERROR;
1437			}
1438			filter_opts.marker |= FOM_KEEP;
1439			filter_opts.keep.action = $1.action;
1440			filter_opts.keep.options = $1.options;
1441		}
1442		| FRAGMENT {
1443			filter_opts.fragment = 1;
1444		}
1445		| ALLOWOPTS {
1446			filter_opts.allowopts = 1;
1447		}
1448		| label	{
1449			if (filter_opts.label) {
1450				yyerror("label cannot be redefined");
1451				YYERROR;
1452			}
1453			filter_opts.label = $1;
1454		}
1455		| qname	{
1456			if (filter_opts.queues.qname) {
1457				yyerror("queue cannot be redefined");
1458				YYERROR;
1459			}
1460			filter_opts.queues = $1;
1461		}
1462		| TAG string				{
1463			filter_opts.tag = $2;
1464		}
1465		| TAGGED string			{
1466			filter_opts.match_tag = $2;
1467		}
1468		;
1469
1470action		: PASS			{ $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
1471		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
1472		;
1473
1474blockspec	: /* empty */		{
1475			$$.b2 = blockpolicy;
1476			$$.w = returnicmpdefault;
1477			$$.w2 = returnicmp6default;
1478		}
1479		| DROP			{
1480			$$.b2 = PFRULE_DROP;
1481			$$.w = 0;
1482			$$.w2 = 0;
1483		}
1484		| RETURNRST		{
1485			$$.b2 = PFRULE_RETURNRST;
1486			$$.w = 0;
1487			$$.w2 = 0;
1488		}
1489		| RETURNRST '(' TTL number ')'	{
1490			$$.b2 = PFRULE_RETURNRST;
1491			$$.w = $4;
1492			$$.w2 = 0;
1493		}
1494		| RETURNICMP		{
1495			$$.b2 = PFRULE_RETURNICMP;
1496			$$.w = returnicmpdefault;
1497			$$.w2 = returnicmp6default;
1498		}
1499		| RETURNICMP6		{
1500			$$.b2 = PFRULE_RETURNICMP;
1501			$$.w = returnicmpdefault;
1502			$$.w2 = returnicmp6default;
1503		}
1504		| RETURNICMP '(' STRING ')'	{
1505			$$.b2 = PFRULE_RETURNICMP;
1506			if (!($$.w = parseicmpspec($3, AF_INET)))
1507				YYERROR;
1508			$$.w2 = returnicmp6default;
1509		}
1510		| RETURNICMP6 '(' STRING ')'	{
1511			$$.b2 = PFRULE_RETURNICMP;
1512			$$.w = returnicmpdefault;
1513			if (!($$.w2 = parseicmpspec($3, AF_INET6)))
1514				YYERROR;
1515		}
1516		| RETURNICMP '(' STRING comma STRING ')' {
1517			$$.b2 = PFRULE_RETURNICMP;
1518			if (!($$.w = parseicmpspec($3, AF_INET)))
1519				YYERROR;
1520			if (!($$.w2 = parseicmpspec($5, AF_INET6)))
1521				YYERROR;
1522		}
1523		| RETURN {
1524			$$.b2 = PFRULE_RETURN;
1525			$$.w = returnicmpdefault;
1526			$$.w2 = returnicmp6default;
1527		}
1528		;
1529
1530dir		: /* empty */			{ $$ = 0; }
1531		| IN				{ $$ = PF_IN; }
1532		| OUT				{ $$ = PF_OUT; }
1533		;
1534
1535logquick	: /* empty */			{ $$.log = 0; $$.quick = 0; }
1536		| log				{ $$.log = $1; $$.quick = 0; }
1537		| QUICK				{ $$.log = 0; $$.quick = 1; }
1538		| log QUICK			{ $$.log = $1; $$.quick = 1; }
1539		| QUICK log			{ $$.log = $2; $$.quick = 1; }
1540		;
1541
1542log		: LOG				{ $$ = 1; }
1543		| LOGALL			{ $$ = 2; }
1544		;
1545
1546interface	: /* empty */			{ $$ = NULL; }
1547		| ON if_item_not		{ $$ = $2; }
1548		| ON '{' if_list '}'		{ $$ = $3; }
1549		;
1550
1551if_list		: if_item_not			{ $$ = $1; }
1552		| if_list comma if_item_not	{
1553			$1->tail->next = $3;
1554			$1->tail = $3;
1555			$$ = $1;
1556		}
1557		;
1558
1559if_item_not	: not if_item			{ $$ = $2; $$->not = $1; }
1560		;
1561
1562if_item		: STRING			{
1563			struct node_host	*n;
1564
1565			if ((n = ifa_exists($1)) == NULL) {
1566				yyerror("unknown interface %s", $1);
1567				YYERROR;
1568			}
1569			$$ = calloc(1, sizeof(struct node_if));
1570			if ($$ == NULL)
1571				err(1, "if_item: calloc");
1572			if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
1573			    sizeof($$->ifname)) {
1574				free($$);
1575				yyerror("interface name too long");
1576				YYERROR;
1577			}
1578			$$->ifa_flags = n->ifa_flags;
1579			$$->not = 0;
1580			$$->next = NULL;
1581			$$->tail = $$;
1582		}
1583		;
1584
1585af		: /* empty */			{ $$ = 0; }
1586		| INET				{ $$ = AF_INET; }
1587		| INET6				{ $$ = AF_INET6; }
1588
1589proto		: /* empty */			{ $$ = NULL; }
1590		| PROTO proto_item		{ $$ = $2; }
1591		| PROTO '{' proto_list '}'	{ $$ = $3; }
1592		;
1593
1594proto_list	: proto_item			{ $$ = $1; }
1595		| proto_list comma proto_item	{
1596			$1->tail->next = $3;
1597			$1->tail = $3;
1598			$$ = $1;
1599		}
1600		;
1601
1602proto_item	: STRING			{
1603			u_int8_t	pr;
1604			u_long		ulval;
1605
1606			if (atoul($1, &ulval) == 0) {
1607				if (ulval > 255) {
1608					yyerror("protocol outside range");
1609					YYERROR;
1610				}
1611				pr = (u_int8_t)ulval;
1612			} else {
1613				struct protoent	*p;
1614
1615				p = getprotobyname($1);
1616				if (p == NULL) {
1617					yyerror("unknown protocol %s", $1);
1618					YYERROR;
1619				}
1620				pr = p->p_proto;
1621			}
1622			if (pr == 0) {
1623				yyerror("proto 0 cannot be used");
1624				YYERROR;
1625			}
1626			$$ = calloc(1, sizeof(struct node_proto));
1627			if ($$ == NULL)
1628				err(1, "proto_item: calloc");
1629			$$->proto = pr;
1630			$$->next = NULL;
1631			$$->tail = $$;
1632		}
1633		;
1634
1635fromto		: ALL				{
1636			$$.src.host = NULL;
1637			$$.src.port = NULL;
1638			$$.dst.host = NULL;
1639			$$.dst.port = NULL;
1640		}
1641		| from to			{
1642			$$.src = $1;
1643			$$.dst = $2;
1644		}
1645		;
1646
1647from		: /* empty */			{
1648			$$.host = NULL;
1649			$$.port = NULL;
1650		}
1651		| FROM ipportspec		{
1652			$$ = $2;
1653		}
1654		;
1655
1656to		: /* empty */			{
1657			$$.host = NULL;
1658			$$.port = NULL;
1659		}
1660		| TO ipportspec		{
1661			$$ = $2;
1662		}
1663		;
1664
1665ipportspec	: ipspec			{
1666			$$.host = $1;
1667			$$.port = NULL;
1668		}
1669		| ipspec PORT portspec		{
1670			$$.host = $1;
1671			$$.port = $3;
1672		}
1673		| PORT portspec			{
1674			$$.host = NULL;
1675			$$.port = $2;
1676		}
1677		;
1678
1679ipspec		: ANY				{ $$ = NULL; }
1680		| xhost				{ $$ = $1; }
1681		| '{' host_list '}'		{ $$ = $2; }
1682		;
1683
1684host_list	: xhost				{ $$ = $1; }
1685		| host_list comma xhost		{
1686			/* $3 may be a list, so use its tail pointer */
1687			if ($3 == NULL)
1688				$$ = $1;
1689			else if ($1 == NULL)
1690				$$ = $3;
1691			else {
1692				$1->tail->next = $3->tail;
1693				$1->tail = $3->tail;
1694				$$ = $1;
1695			}
1696		}
1697		;
1698
1699xhost		: not host			{
1700			struct node_host	*n;
1701
1702			for (n = $2; n != NULL; n = n->next)
1703				n->not = $1;
1704			$$ = $2;
1705		}
1706		| NOROUTE			{
1707			$$ = calloc(1, sizeof(struct node_host));
1708			if ($$ == NULL)
1709				err(1, "xhost: calloc");
1710			$$->addr.type = PF_ADDR_NOROUTE;
1711			$$->next = NULL;
1712			$$->tail = $$;
1713		}
1714		;
1715
1716host		: STRING			{ $$ = host($1); }
1717		| STRING '/' number		{
1718			char	*buf;
1719
1720			if (asprintf(&buf, "%s/%u", $1, $3) == -1)
1721				err(1, "host: asprintf");
1722			$$ = host(buf);
1723			free(buf);
1724		}
1725		| dynaddr
1726		| dynaddr '/' number		{
1727			struct node_host	*n;
1728
1729			$$ = $1;
1730			for (n = $1; n != NULL; n = n->next)
1731				set_ipmask(n, $3);
1732		}
1733		| '<' STRING '>'	{
1734			if (strlen($2) >= PF_TABLE_NAME_SIZE) {
1735				yyerror("table name '%s' too long");
1736				YYERROR;
1737			}
1738			$$ = calloc(1, sizeof(struct node_host));
1739			if ($$ == NULL)
1740				err(1, "host: calloc");
1741			$$->addr.type = PF_ADDR_TABLE;
1742			if (strlcpy($$->addr.v.tblname, $2,
1743			    sizeof($$->addr.v.tblname)) >=
1744			    sizeof($$->addr.v.tblname))
1745				errx(1, "host: strlcpy");
1746			$$->next = NULL;
1747			$$->tail = $$;
1748		}
1749		;
1750
1751number		: STRING			{
1752			u_long	ulval;
1753
1754			if (atoul($1, &ulval) == -1) {
1755				yyerror("%s is not a number", $1);
1756				YYERROR;
1757			} else
1758				$$ = ulval;
1759		}
1760		;
1761
1762dynaddr		: '(' STRING ')'		{
1763			if (ifa_exists($2) == NULL) {
1764				yyerror("interface %s does not exist", $2);
1765				YYERROR;
1766			}
1767			$$ = calloc(1, sizeof(struct node_host));
1768			if ($$ == NULL)
1769				err(1, "address: calloc");
1770			$$->af = 0;
1771			set_ipmask($$, 128);
1772			$$->addr.type = PF_ADDR_DYNIFTL;
1773			if (strlcpy($$->addr.v.ifname, $2,
1774			    sizeof($$->addr.v.ifname)) >=
1775			    sizeof($$->addr.v.ifname)) {
1776				free($$);
1777				yyerror("interface name too long");
1778				YYERROR;
1779			}
1780			$$->next = NULL;
1781			$$->tail = $$;
1782		}
1783		;
1784
1785portspec	: port_item			{ $$ = $1; }
1786		| '{' port_list '}'		{ $$ = $2; }
1787		;
1788
1789port_list	: port_item			{ $$ = $1; }
1790		| port_list comma port_item	{
1791			$1->tail->next = $3;
1792			$1->tail = $3;
1793			$$ = $1;
1794		}
1795		;
1796
1797port_item	: port				{
1798			$$ = calloc(1, sizeof(struct node_port));
1799			if ($$ == NULL)
1800				err(1, "port_item: calloc");
1801			$$->port[0] = $1.a;
1802			$$->port[1] = $1.b;
1803			if ($1.t)
1804				$$->op = PF_OP_RRG;
1805			else
1806				$$->op = PF_OP_EQ;
1807			$$->next = NULL;
1808			$$->tail = $$;
1809		}
1810		| unaryop port		{
1811			if ($2.t) {
1812				yyerror("':' cannot be used with an other "
1813				    "port operator");
1814				YYERROR;
1815			}
1816			$$ = calloc(1, sizeof(struct node_port));
1817			if ($$ == NULL)
1818				err(1, "port_item: calloc");
1819			$$->port[0] = $2.a;
1820			$$->port[1] = $2.b;
1821			$$->op = $1;
1822			$$->next = NULL;
1823			$$->tail = $$;
1824		}
1825		| port PORTBINARY port		{
1826			if ($1.t || $3.t) {
1827				yyerror("':' cannot be used with an other "
1828				    "port operator");
1829				YYERROR;
1830			}
1831			$$ = calloc(1, sizeof(struct node_port));
1832			if ($$ == NULL)
1833				err(1, "port_item: calloc");
1834			$$->port[0] = $1.a;
1835			$$->port[1] = $3.a;
1836			$$->op = $2;
1837			$$->next = NULL;
1838			$$->tail = $$;
1839		}
1840		;
1841
1842port		: STRING			{
1843			char	*p = strchr($1, ':');
1844			struct servent	*s = NULL;
1845			u_long		 ulval;
1846
1847			if (p == NULL) {
1848				if (atoul($1, &ulval) == 0) {
1849					if (ulval > 65535) {
1850						yyerror("illegal port value %d",
1851						    ulval);
1852						YYERROR;
1853					}
1854					$$.a = htons(ulval);
1855				} else {
1856					s = getservbyname($1, "tcp");
1857					if (s == NULL)
1858						s = getservbyname($1, "udp");
1859					if (s == NULL) {
1860						yyerror("unknown port %s", $1);
1861						YYERROR;
1862					}
1863					$$.a = s->s_port;
1864				}
1865				$$.b = 0;
1866				$$.t = 0;
1867			} else {
1868				int port[2];
1869
1870				*p++ = 0;
1871				if ((port[0] = getservice($1)) == -1 ||
1872				    (port[1] = getservice(p)) == -1)
1873					YYERROR;
1874				$$.a = port[0];
1875				$$.b = port[1];
1876				$$.t = PF_OP_RRG;
1877			}
1878		}
1879		;
1880
1881uids		: uid_item			{ $$ = $1; }
1882		| '{' uid_list '}'		{ $$ = $2; }
1883		;
1884
1885uid_list	: uid_item			{ $$ = $1; }
1886		| uid_list comma uid_item	{
1887			$1->tail->next = $3;
1888			$1->tail = $3;
1889			$$ = $1;
1890		}
1891		;
1892
1893uid_item	: uid				{
1894			$$ = calloc(1, sizeof(struct node_uid));
1895			if ($$ == NULL)
1896				err(1, "uid_item: calloc");
1897			$$->uid[0] = $1;
1898			$$->uid[1] = $1;
1899			$$->op = PF_OP_EQ;
1900			$$->next = NULL;
1901			$$->tail = $$;
1902		}
1903		| unaryop uid			{
1904			if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
1905				yyerror("user unknown requires operator = or "
1906				    "!=");
1907				YYERROR;
1908			}
1909			$$ = calloc(1, sizeof(struct node_uid));
1910			if ($$ == NULL)
1911				err(1, "uid_item: calloc");
1912			$$->uid[0] = $2;
1913			$$->uid[1] = $2;
1914			$$->op = $1;
1915			$$->next = NULL;
1916			$$->tail = $$;
1917		}
1918		| uid PORTBINARY uid		{
1919			if ($1 == UID_MAX || $3 == UID_MAX) {
1920				yyerror("user unknown requires operator = or "
1921				    "!=");
1922				YYERROR;
1923			}
1924			$$ = calloc(1, sizeof(struct node_uid));
1925			if ($$ == NULL)
1926				err(1, "uid_item: calloc");
1927			$$->uid[0] = $1;
1928			$$->uid[1] = $3;
1929			$$->op = $2;
1930			$$->next = NULL;
1931			$$->tail = $$;
1932		}
1933		;
1934
1935uid		: STRING			{
1936			u_long	ulval;
1937
1938			if (atoul($1, &ulval) == -1) {
1939				if (!strcmp($1, "unknown"))
1940					$$ = UID_MAX;
1941				else {
1942					struct passwd	*pw;
1943
1944					if ((pw = getpwnam($1)) == NULL) {
1945						yyerror("unknown user %s", $1);
1946						YYERROR;
1947					}
1948					$$ = pw->pw_uid;
1949				}
1950			} else {
1951				if (ulval >= UID_MAX) {
1952					yyerror("illegal uid value %lu", ulval);
1953					YYERROR;
1954				}
1955				$$ = ulval;
1956			}
1957		}
1958		;
1959
1960gids		: gid_item			{ $$ = $1; }
1961		| '{' gid_list '}'		{ $$ = $2; }
1962		;
1963
1964gid_list	: gid_item			{ $$ = $1; }
1965		| gid_list comma gid_item	{
1966			$1->tail->next = $3;
1967			$1->tail = $3;
1968			$$ = $1;
1969		}
1970		;
1971
1972gid_item	: gid				{
1973			$$ = calloc(1, sizeof(struct node_gid));
1974			if ($$ == NULL)
1975				err(1, "gid_item: calloc");
1976			$$->gid[0] = $1;
1977			$$->gid[1] = $1;
1978			$$->op = PF_OP_EQ;
1979			$$->next = NULL;
1980			$$->tail = $$;
1981		}
1982		| unaryop gid			{
1983			if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
1984				yyerror("group unknown requires operator = or "
1985				    "!=");
1986				YYERROR;
1987			}
1988			$$ = calloc(1, sizeof(struct node_gid));
1989			if ($$ == NULL)
1990				err(1, "gid_item: calloc");
1991			$$->gid[0] = $2;
1992			$$->gid[1] = $2;
1993			$$->op = $1;
1994			$$->next = NULL;
1995			$$->tail = $$;
1996		}
1997		| gid PORTBINARY gid		{
1998			if ($1 == GID_MAX || $3 == GID_MAX) {
1999				yyerror("group unknown requires operator = or "
2000				    "!=");
2001				YYERROR;
2002			}
2003			$$ = calloc(1, sizeof(struct node_gid));
2004			if ($$ == NULL)
2005				err(1, "gid_item: calloc");
2006			$$->gid[0] = $1;
2007			$$->gid[1] = $3;
2008			$$->op = $2;
2009			$$->next = NULL;
2010			$$->tail = $$;
2011		}
2012		;
2013
2014gid		: STRING			{
2015			u_long	ulval;
2016
2017			if (atoul($1, &ulval) == -1) {
2018				if (!strcmp($1, "unknown"))
2019					$$ = GID_MAX;
2020				else {
2021					struct group	*grp;
2022
2023					if ((grp = getgrnam($1)) == NULL) {
2024						yyerror("unknown group %s", $1);
2025						YYERROR;
2026					}
2027					$$ = grp->gr_gid;
2028				}
2029			} else {
2030				if (ulval >= GID_MAX) {
2031					yyerror("illegal gid value %lu", ulval);
2032					YYERROR;
2033				}
2034				$$ = ulval;
2035			}
2036		}
2037		;
2038
2039flag		: STRING			{
2040			int	f;
2041
2042			if ((f = parse_flags($1)) < 0) {
2043				yyerror("bad flags %s", $1);
2044				YYERROR;
2045			}
2046			$$.b1 = f;
2047		}
2048		;
2049
2050flags		: FLAGS flag '/' flag	{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
2051		| FLAGS '/' flag	{ $$.b1 = 0; $$.b2 = $3.b1; }
2052		;
2053
2054icmpspec	: ICMPTYPE icmp_item		{ $$ = $2; }
2055		| ICMPTYPE '{' icmp_list '}'	{ $$ = $3; }
2056		| ICMP6TYPE icmp6_item		{ $$ = $2; }
2057		| ICMP6TYPE '{' icmp6_list '}'	{ $$ = $3; }
2058		;
2059
2060icmp_list	: icmp_item			{ $$ = $1; }
2061		| icmp_list comma icmp_item	{
2062			$1->tail->next = $3;
2063			$1->tail = $3;
2064			$$ = $1;
2065		}
2066		;
2067
2068icmp6_list	: icmp6_item			{ $$ = $1; }
2069		| icmp6_list comma icmp6_item	{
2070			$1->tail->next = $3;
2071			$1->tail = $3;
2072			$$ = $1;
2073		}
2074		;
2075
2076icmp_item	: icmptype		{
2077			$$ = calloc(1, sizeof(struct node_icmp));
2078			if ($$ == NULL)
2079				err(1, "icmp_item: calloc");
2080			$$->type = $1;
2081			$$->code = 0;
2082			$$->proto = IPPROTO_ICMP;
2083			$$->next = NULL;
2084			$$->tail = $$;
2085		}
2086		| icmptype CODE STRING	{
2087			const struct icmpcodeent	*p;
2088			u_long				 ulval;
2089
2090			if (atoul($3, &ulval) == 0) {
2091				if (ulval > 255) {
2092					yyerror("illegal icmp-code %d", ulval);
2093					YYERROR;
2094				}
2095			} else {
2096				if ((p = geticmpcodebyname($1-1, $3,
2097				    AF_INET)) == NULL) {
2098					yyerror("unknown icmp-code %s", $3);
2099					YYERROR;
2100				}
2101				ulval = p->code;
2102			}
2103			$$ = calloc(1, sizeof(struct node_icmp));
2104			if ($$ == NULL)
2105				err(1, "icmp_item: calloc");
2106			$$->type = $1;
2107			$$->code = ulval + 1;
2108			$$->proto = IPPROTO_ICMP;
2109			$$->next = NULL;
2110			$$->tail = $$;
2111		}
2112		;
2113
2114icmp6_item	: icmp6type		{
2115			$$ = calloc(1, sizeof(struct node_icmp));
2116			if ($$ == NULL)
2117				err(1, "icmp_item: calloc");
2118			$$->type = $1;
2119			$$->code = 0;
2120			$$->proto = IPPROTO_ICMPV6;
2121			$$->next = NULL;
2122			$$->tail = $$;
2123		}
2124		| icmp6type CODE STRING	{
2125			const struct icmpcodeent	*p;
2126			u_long				 ulval;
2127
2128			if (atoul($3, &ulval) == 0) {
2129				if (ulval > 255) {
2130					yyerror("illegal icmp6-code %ld",
2131					    ulval);
2132					YYERROR;
2133				}
2134			} else {
2135				if ((p = geticmpcodebyname($1-1, $3,
2136				    AF_INET6)) == NULL) {
2137					yyerror("unknown icmp6-code %s", $3);
2138					YYERROR;
2139				}
2140				ulval = p->code;
2141			}
2142			$$ = calloc(1, sizeof(struct node_icmp));
2143			if ($$ == NULL)
2144				err(1, "icmp_item: calloc");
2145			$$->type = $1;
2146			$$->code = ulval + 1;
2147			$$->proto = IPPROTO_ICMPV6;
2148			$$->next = NULL;
2149			$$->tail = $$;
2150		}
2151		;
2152
2153icmptype	: STRING			{
2154			const struct icmptypeent	*p;
2155			u_long				 ulval;
2156
2157			if (atoul($1, &ulval) == 0) {
2158				if (ulval > 255) {
2159					yyerror("illegal icmp-type %d", ulval);
2160					YYERROR;
2161				}
2162				$$ = ulval + 1;
2163			} else {
2164				if ((p = geticmptypebyname($1, AF_INET)) ==
2165				    NULL) {
2166					yyerror("unknown icmp-type %s", $1);
2167					YYERROR;
2168				}
2169				$$ = p->type + 1;
2170			}
2171		}
2172		;
2173
2174icmp6type	: STRING			{
2175			const struct icmptypeent	*p;
2176			u_long				 ulval;
2177
2178			if (atoul($1, &ulval) == 0) {
2179				if (ulval > 255) {
2180					yyerror("illegal icmp6-type %d", ulval);
2181					YYERROR;
2182				}
2183				$$ = ulval + 1;
2184			} else {
2185				if ((p = geticmptypebyname($1, AF_INET6)) ==
2186				    NULL) {
2187					yyerror("unknown icmp6-type %s", $1);
2188					YYERROR;
2189				}
2190				$$ = p->type + 1;
2191			}
2192		}
2193		;
2194
2195tos		: TOS STRING			{
2196			if (!strcmp($2, "lowdelay"))
2197				$$ = IPTOS_LOWDELAY;
2198			else if (!strcmp($2, "throughput"))
2199				$$ = IPTOS_THROUGHPUT;
2200			else if (!strcmp($2, "reliability"))
2201				$$ = IPTOS_RELIABILITY;
2202			else if ($2[0] == '0' && $2[1] == 'x')
2203				$$ = strtoul($2, NULL, 16);
2204			else
2205				$$ = strtoul($2, NULL, 10);
2206			if (!$$ || $$ > 255) {
2207				yyerror("illegal tos value %s", $2);
2208				YYERROR;
2209			}
2210		}
2211		;
2212
2213keep		: KEEP STATE state_opt_spec	{
2214			$$.action = PF_STATE_NORMAL;
2215			$$.options = $3;
2216		}
2217		| MODULATE STATE state_opt_spec	{
2218			$$.action = PF_STATE_MODULATE;
2219			$$.options = $3;
2220		}
2221		;
2222
2223state_opt_spec	: '(' state_opt_list ')'	{ $$ = $2; }
2224		| /* empty */			{ $$ = NULL; }
2225		;
2226
2227state_opt_list	: state_opt_item		{ $$ = $1; }
2228		| state_opt_list comma state_opt_item {
2229			$1->tail->next = $3;
2230			$1->tail = $3;
2231			$$ = $1;
2232		}
2233		;
2234
2235state_opt_item	: MAXIMUM number		{
2236			$$ = calloc(1, sizeof(struct node_state_opt));
2237			if ($$ == NULL)
2238				err(1, "state_opt_item: calloc");
2239			$$->type = PF_STATE_OPT_MAX;
2240			$$->data.max_states = $2;
2241			$$->next = NULL;
2242			$$->tail = $$;
2243		}
2244		| STRING number			{
2245			int	i;
2246
2247			for (i = 0; pf_timeouts[i].name &&
2248			    strcmp(pf_timeouts[i].name, $1); ++i)
2249				;	/* nothing */
2250			if (!pf_timeouts[i].name) {
2251				yyerror("illegal timeout name %s", $1);
2252				YYERROR;
2253			}
2254			if (strchr(pf_timeouts[i].name, '.') == NULL) {
2255				yyerror("illegal state timeout %s", $1);
2256				YYERROR;
2257			}
2258			$$ = calloc(1, sizeof(struct node_state_opt));
2259			if ($$ == NULL)
2260				err(1, "state_opt_item: calloc");
2261			$$->type = PF_STATE_OPT_TIMEOUT;
2262			$$->data.timeout.number = pf_timeouts[i].timeout;
2263			$$->data.timeout.seconds = $2;
2264			$$->next = NULL;
2265			$$->tail = $$;
2266		}
2267		;
2268
2269label		: LABEL STRING			{
2270			if (($$ = strdup($2)) == NULL)
2271				err(1, "rule label strdup() failed");
2272		}
2273		;
2274
2275qname		: QUEUE STRING				{
2276			if (($$.qname = strdup($2)) == NULL)
2277				err(1, "qname strdup() failed");
2278		}
2279		| QUEUE '(' STRING ')'			{
2280			if (($$.qname = strdup($3)) == NULL)
2281				err(1, "qname strdup() failed");
2282		}
2283		| QUEUE '(' STRING comma STRING ')'	{
2284			if (($$.qname = strdup($3)) == NULL ||
2285			    ($$.pqname = strdup($5)) == NULL)
2286				err(1, "qname strdup() failed");
2287		}
2288		;
2289
2290no		: /* empty */			{ $$ = 0; }
2291		| NO				{ $$ = 1; }
2292		;
2293
2294rport		: STRING			{
2295			char	*p = strchr($1, ':');
2296
2297			if (p == NULL) {
2298				if (($$.a = getservice($1)) == -1)
2299					YYERROR;
2300				$$.b = $$.t = 0;
2301			} else if (!strcmp(p+1, "*")) {
2302				*p = 0;
2303				if (($$.a = getservice($1)) == -1)
2304					YYERROR;
2305				$$.b = 0;
2306				$$.t = 1;
2307			} else {
2308				*p++ = 0;
2309				if (($$.a = getservice($1)) == -1 ||
2310				    ($$.b = getservice(p)) == -1)
2311					YYERROR;
2312				if ($$.a == $$.b)
2313					$$.b = 0;
2314				$$.t = 0;
2315			}
2316		}
2317		;
2318
2319redirspec	: host				{ $$ = $1; }
2320		| '{' redir_host_list '}'	{ $$ = $2; }
2321		;
2322
2323redir_host_list	: host				{ $$ = $1; }
2324		| redir_host_list comma host	{
2325			/* $3 may be a list, so use its tail pointer */
2326			$1->tail->next = $3->tail;
2327			$1->tail = $3->tail;
2328			$$ = $1;
2329		}
2330		;
2331
2332redirpool	: /* empty */			{ $$ = NULL; }
2333		| ARROW redirspec		{
2334			$$ = calloc(1, sizeof(struct redirection));
2335			if ($$ == NULL)
2336				err(1, "redirection: calloc");
2337			$$->host = $2;
2338			$$->rport.a = $$->rport.b = $$->rport.t = 0;
2339		}
2340		| ARROW redirspec PORT rport	{
2341			$$ = calloc(1, sizeof(struct redirection));
2342			if ($$ == NULL)
2343				err(1, "redirection: calloc");
2344			$$->host = $2;
2345			$$->rport = $4;
2346		}
2347		;
2348
2349hashkey		: /* empty */
2350		{
2351			$$ = calloc(1, sizeof(struct pf_poolhashkey));
2352			if ($$ == NULL)
2353				err(1, "hashkey: calloc");
2354			$$->key32[0] = arc4random();
2355			$$->key32[1] = arc4random();
2356			$$->key32[2] = arc4random();
2357			$$->key32[3] = arc4random();
2358		}
2359		| string
2360		{
2361			if (!strncmp($1, "0x", 2)) {
2362				if (strlen($1) != 34) {
2363					yyerror("hex key must be 128 bits "
2364						"(32 hex digits) long");
2365					YYERROR;
2366				}
2367				$$ = calloc(1, sizeof(struct pf_poolhashkey));
2368				if ($$ == NULL)
2369					err(1, "hashkey: calloc");
2370
2371				if (sscanf($1, "0x%8x%8x%8x%8x",
2372				    &$$->key32[0], &$$->key32[1],
2373				    &$$->key32[2], &$$->key32[3]) != 4) {
2374					free($$);
2375					yyerror("invalid hex key");
2376					YYERROR;
2377				}
2378			} else {
2379				MD5_CTX	context;
2380
2381				$$ = calloc(1, sizeof(struct pf_poolhashkey));
2382				if ($$ == NULL)
2383					err(1, "hashkey: calloc");
2384				MD5Init(&context);
2385				MD5Update(&context, (unsigned char *)$1,
2386				    strlen($1));
2387				MD5Final((unsigned char *)$$, &context);
2388				HTONL($$->key32[0]);
2389				HTONL($$->key32[1]);
2390				HTONL($$->key32[2]);
2391				HTONL($$->key32[3]);
2392			}
2393		}
2394		;
2395
2396pooltype	: /* empty */
2397		{
2398			$$.type = PF_POOL_NONE;
2399			$$.key = NULL;
2400		}
2401		| BITMASK
2402		{
2403			$$.type = PF_POOL_BITMASK;
2404			$$.key = NULL;
2405		}
2406		| RANDOM
2407		{
2408			$$.type = PF_POOL_RANDOM;
2409			$$.key = NULL;
2410		}
2411		| SOURCEHASH hashkey
2412		{
2413			$$.type = PF_POOL_SRCHASH;
2414			$$.key = $2;
2415		}
2416		| ROUNDROBIN
2417		{
2418			$$.type = PF_POOL_ROUNDROBIN;
2419			$$.key = NULL;
2420		}
2421		;
2422
2423staticport	: /* empty */			{ $$ = 0; }
2424		| STATICPORT			{ $$ = PF_POOL_STATICPORT; }
2425		;
2426
2427redirection	: /* empty */			{ $$ = NULL; }
2428		| ARROW host			{
2429			$$ = calloc(1, sizeof(struct redirection));
2430			if ($$ == NULL)
2431				err(1, "redirection: calloc");
2432			$$->host = $2;
2433			$$->rport.a = $$->rport.b = $$->rport.t = 0;
2434		}
2435		| ARROW host PORT rport	{
2436			$$ = calloc(1, sizeof(struct redirection));
2437			if ($$ == NULL)
2438				err(1, "redirection: calloc");
2439			$$->host = $2;
2440			$$->rport = $4;
2441		}
2442		;
2443
2444nataction	: no NAT {
2445			$$.b2 = $$.w = 0;
2446			if ($1)
2447				$$.b1 = PF_NONAT;
2448			else
2449				$$.b1 = PF_NAT;
2450		}
2451		| no RDR {
2452			$$.b2 = $$.w = 0;
2453			if ($1)
2454				$$.b1 = PF_NORDR;
2455			else
2456				$$.b1 = PF_RDR;
2457		}
2458		;
2459
2460natrule		: nataction interface af proto fromto tag redirpool pooltype
2461		  staticport
2462		{
2463			struct pf_rule	r;
2464
2465			if (check_rulestate(PFCTL_STATE_NAT))
2466				YYERROR;
2467
2468			memset(&r, 0, sizeof(r));
2469
2470			r.action = $1.b1;
2471			r.af = $3;
2472
2473			if (!r.af) {
2474				if ($5.src.host && $5.src.host->af &&
2475				    !$5.src.host->ifindex)
2476					r.af = $5.src.host->af;
2477				else if ($5.dst.host && $5.dst.host->af &&
2478				    !$5.dst.host->ifindex)
2479					r.af = $5.dst.host->af;
2480			}
2481
2482			if ($6 != NULL)
2483				strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE);
2484
2485			if (r.action == PF_NONAT || r.action == PF_NORDR) {
2486				if ($7 != NULL) {
2487					yyerror("translation rule with 'no' "
2488					    "does not need '->'");
2489					YYERROR;
2490				}
2491			} else {
2492				if ($7 == NULL || $7->host == NULL) {
2493					yyerror("translation rule requires '-> "
2494					    "address'");
2495					YYERROR;
2496				}
2497				if (disallow_table($7->host, "invalid use of "
2498				    "table <%s> as the redirection address "
2499				    "of a translation rule"))
2500					YYERROR;
2501				if (!r.af && ! $7->host->ifindex)
2502					r.af = $7->host->af;
2503
2504				remove_invalid_hosts(&$7->host, &r.af);
2505				if (invalid_redirect($7->host, r.af))
2506					YYERROR;
2507
2508				r.rpool.proxy_port[0] = ntohs($7->rport.a);
2509
2510				switch (r.action) {
2511				case PF_RDR:
2512					if (!$7->rport.b && $7->rport.t &&
2513					    $5.dst.port != NULL) {
2514						r.rpool.proxy_port[1] =
2515						    ntohs($7->rport.a) +
2516						    (ntohs($5.dst.port->port[1]) -
2517						    ntohs($5.dst.port->port[0]));
2518					} else
2519						r.rpool.proxy_port[1] =
2520						    ntohs($7->rport.b);
2521					break;
2522				case PF_NAT:
2523					r.rpool.proxy_port[1] = ntohs($7->rport.b);
2524					if (!r.rpool.proxy_port[0] &&
2525					    !r.rpool.proxy_port[1]) {
2526						r.rpool.proxy_port[0] =
2527						    PF_NAT_PROXY_PORT_LOW;
2528						r.rpool.proxy_port[1] =
2529						    PF_NAT_PROXY_PORT_HIGH;
2530					} else if (!r.rpool.proxy_port[1])
2531						r.rpool.proxy_port[1] =
2532						    r.rpool.proxy_port[0];
2533					break;
2534				default:
2535					break;
2536				}
2537
2538				if ($7->host->next) {
2539					r.rpool.opts = $8.type;
2540					if (r.rpool.opts == PF_POOL_NONE)
2541						r.rpool.opts =
2542						    PF_POOL_ROUNDROBIN;
2543					if (r.rpool.opts !=
2544					    PF_POOL_ROUNDROBIN) {
2545						yyerror("only round-robin "
2546						    "valid for multiple "
2547						    "redirection addresses");
2548						YYERROR;
2549					}
2550				} else {
2551					if ((r.af == AF_INET &&
2552					    unmask(&$7->host->addr.v.a.mask,
2553					    r.af) == 32) ||
2554					    (r.af == AF_INET6 &&
2555					    unmask(&$7->host->addr.v.a.mask,
2556					    r.af) == 128)) {
2557						r.rpool.opts = PF_POOL_NONE;
2558					} else {
2559						if ($8.type == PF_POOL_NONE)
2560							r.rpool.opts =
2561							    PF_POOL_ROUNDROBIN;
2562						else
2563							r.rpool.opts =
2564							    $8.type;
2565					}
2566				}
2567			}
2568
2569			if ($8.key != NULL)
2570				memcpy(&r.rpool.key, $8.key,
2571				    sizeof(struct pf_poolhashkey));
2572
2573			if ($9 != NULL) {
2574				if (r.action == PF_NAT)
2575					r.rpool.opts |= PF_POOL_STATICPORT;
2576				else {
2577					yyerror("the 'static-port' option is "
2578					    "only valid with nat rules");
2579					YYERROR;
2580				}
2581			}
2582
2583			expand_rule(&r, $2, $7 == NULL ? NULL : $7->host, $4,
2584			    $5.src.host, $5.src.port, $5.dst.host, $5.dst.port,
2585			    0, 0, 0);
2586			free($7);
2587		}
2588		;
2589
2590binatrule	: no BINAT interface af proto FROM host TO ipspec redirection
2591		{
2592			struct pf_rule		binat;
2593			struct pf_pooladdr	*pa;
2594
2595			if (check_rulestate(PFCTL_STATE_NAT))
2596				YYERROR;
2597
2598			memset(&binat, 0, sizeof(binat));
2599
2600			if ($1)
2601				binat.action = PF_NOBINAT;
2602			else
2603				binat.action = PF_BINAT;
2604			binat.af = $4;
2605			if (!binat.af && $7 != NULL && $7->af)
2606				binat.af = $7->af;
2607			if (!binat.af && $9 != NULL && $9->af)
2608				binat.af = $9->af;
2609			if (!binat.af && $10 != NULL && $10->host)
2610				binat.af = $10->host->af;
2611			if (!binat.af) {
2612				yyerror("address family (inet/inet6) "
2613				    "undefined");
2614				YYERROR;
2615			}
2616
2617			if ($3 != NULL) {
2618				memcpy(binat.ifname, $3->ifname,
2619				    sizeof(binat.ifname));
2620				free($3);
2621			}
2622			if ($5 != NULL) {
2623				binat.proto = $5->proto;
2624				free($5);
2625			}
2626
2627			if ($7 != NULL && disallow_table($7, "invalid use of "
2628			    "table <%s> as the source address of a binat rule"))
2629				YYERROR;
2630			if ($10 != NULL && $10->host != NULL && disallow_table(
2631			    $10->host, "invalid use of table <%s> as the "
2632			    "redirect address of a binat rule"))
2633				YYERROR;
2634
2635			if ($7 != NULL) {
2636				if ($7->next) {
2637					yyerror("multiple binat ip addresses");
2638					YYERROR;
2639				}
2640				if ($7->addr.type == PF_ADDR_DYNIFTL)
2641					$7->af = binat.af;
2642				if ($7->af != binat.af) {
2643					yyerror("binat ip versions must match");
2644					YYERROR;
2645				}
2646				memcpy(&binat.src.addr, &$7->addr,
2647				    sizeof(binat.src.addr));
2648				free($7);
2649			}
2650			if ($9 != NULL) {
2651				if ($9->next) {
2652					yyerror("multiple binat ip addresses");
2653					YYERROR;
2654				}
2655				if ($9->af != binat.af && $9->af) {
2656					yyerror("binat ip versions must match");
2657					YYERROR;
2658				}
2659				memcpy(&binat.dst.addr, &$9->addr,
2660				    sizeof(binat.dst.addr));
2661				binat.dst.not = $9->not;
2662				free($9);
2663			}
2664
2665			if (binat.action == PF_NOBINAT) {
2666				if ($10 != NULL) {
2667					yyerror("'no binat' rule does not need"
2668					    " '->'");
2669					YYERROR;
2670				}
2671			} else {
2672				if ($10 == NULL || $10->host == NULL) {
2673					yyerror("'binat' rule requires"
2674					    " '-> address'");
2675					YYERROR;
2676				}
2677
2678				remove_invalid_hosts(&$10->host, &binat.af);
2679				if (invalid_redirect($10->host, binat.af))
2680					YYERROR;
2681				if ($10->host->next != NULL) {
2682					yyerror("binat rule must redirect to "
2683					    "a single address");
2684					YYERROR;
2685				}
2686
2687				if (!PF_AZERO(&binat.src.addr.v.a.mask,
2688				    binat.af) &&
2689				    !PF_AEQ(&binat.src.addr.v.a.mask,
2690				    &$10->host->addr.v.a.mask, binat.af)) {
2691					yyerror("'binat' source mask and "
2692					    "redirect mask must be the same");
2693					YYERROR;
2694				}
2695
2696				TAILQ_INIT(&binat.rpool.list);
2697				pa = calloc(1, sizeof(struct pf_pooladdr));
2698				if (pa == NULL)
2699					err(1, "binat: calloc");
2700				pa->addr.addr = $10->host->addr;
2701				pa->ifname[0] = 0;
2702				TAILQ_INSERT_TAIL(&binat.rpool.list,
2703				    pa, entries);
2704
2705				free($10);
2706			}
2707
2708			pfctl_add_rule(pf, &binat);
2709		}
2710		;
2711
2712tag		: /* empty */		{ $$ = NULL; }
2713		| TAG STRING		{ $$ = $2; }
2714
2715route_host	: STRING			{
2716			struct node_host	*n;
2717
2718			$$ = calloc(1, sizeof(struct node_host));
2719			if ($$ == NULL)
2720				err(1, "route_host: calloc");
2721			if (($$->ifname = strdup($1)) == NULL)
2722				err(1, "routeto: strdup");
2723			if ((n = ifa_exists($$->ifname)) == NULL) {
2724				yyerror("routeto: unknown interface %s",
2725				    $$->ifname);
2726				YYERROR;
2727			}
2728			set_ipmask($$, 128);
2729			$$->next = NULL;
2730			$$->tail = $$;
2731		}
2732		| '(' STRING host ')'		{
2733			struct node_host	*n;
2734
2735			$$ = $3;
2736			if (($$->ifname = strdup($2)) == NULL)
2737				err(1, "routeto: strdup");
2738			if ((n = ifa_exists($$->ifname)) == NULL) {
2739				yyerror("routeto: unknown interface %s",
2740				    $$->ifname);
2741				YYERROR;
2742			}
2743			if (disallow_table($3, "invalid use of table <%s> in "
2744			    "a route expression"))
2745				YYERROR;
2746		}
2747		;
2748
2749route_host_list	: route_host				{ $$ = $1; }
2750		| route_host_list comma route_host	{
2751			if ($1->af == 0)
2752				$1->af = $3->af;
2753			if ($1->af != $3->af) {
2754				yyerror("all pool addresses must be in the "
2755				    "same address family");
2756				YYERROR;
2757			}
2758			/* $3 may be a list, so use its tail pointer */
2759			$1->tail->next = $3->tail;
2760			$1->tail = $3->tail;
2761			$$ = $1;
2762		}
2763		;
2764
2765routespec	: route_host			{ $$ = $1; }
2766		| '{' route_host_list '}'	{ $$ = $2; }
2767		;
2768
2769route		: /* empty */			{
2770			$$.host = NULL;
2771			$$.rt = 0;
2772			$$.pool_opts = 0;
2773		}
2774		| FASTROUTE {
2775			$$.host = NULL;
2776			$$.rt = PF_FASTROUTE;
2777			$$.pool_opts = 0;
2778		}
2779		| ROUTETO routespec pooltype {
2780			$$.host = $2;
2781			$$.rt = PF_ROUTETO;
2782			$$.pool_opts = $3.type;
2783			if ($3.key != NULL)
2784				$$.key = $3.key;
2785		}
2786		| REPLYTO routespec pooltype {
2787			$$.host = $2;
2788			$$.rt = PF_REPLYTO;
2789			$$.pool_opts = $3.type;
2790			if ($3.key != NULL)
2791				$$.key = $3.key;
2792		}
2793		| DUPTO routespec pooltype {
2794			$$.host = $2;
2795			$$.rt = PF_DUPTO;
2796			$$.pool_opts = $3.type;
2797			if ($3.key != NULL)
2798				$$.key = $3.key;
2799		}
2800		;
2801
2802timeout_spec	: STRING number
2803		{
2804			if (check_rulestate(PFCTL_STATE_OPTION))
2805				YYERROR;
2806			if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
2807				yyerror("unknown timeout %s", $1);
2808				YYERROR;
2809			}
2810		}
2811		;
2812
2813timeout_list	: timeout_list comma timeout_spec
2814		| timeout_spec
2815		;
2816
2817limit_spec	: STRING number
2818		{
2819			if (check_rulestate(PFCTL_STATE_OPTION))
2820				YYERROR;
2821			if (pfctl_set_limit(pf, $1, $2) != 0) {
2822				yyerror("unable to set limit %s %u", $1, $2);
2823				YYERROR;
2824			}
2825		}
2826
2827limit_list	: limit_list comma limit_spec
2828		| limit_spec
2829		;
2830
2831comma		: ','
2832		| /* empty */
2833		;
2834
2835yesno		: NO			{ $$ = 0; }
2836		| STRING		{
2837			if (!strcmp($1, "yes"))
2838				$$ = 1;
2839			else
2840				YYERROR;
2841		}
2842
2843unaryop		: '='		{ $$ = PF_OP_EQ; }
2844		| '!' '='	{ $$ = PF_OP_NE; }
2845		| '<' '='	{ $$ = PF_OP_LE; }
2846		| '<'		{ $$ = PF_OP_LT; }
2847		| '>' '='	{ $$ = PF_OP_GE; }
2848		| '>'		{ $$ = PF_OP_GT; }
2849		;
2850
2851%%
2852
2853int
2854yyerror(const char *fmt, ...)
2855{
2856	va_list		 ap;
2857	extern char	*infile;
2858
2859	errors = 1;
2860	va_start(ap, fmt);
2861	fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
2862	vfprintf(stderr, fmt, ap);
2863	fprintf(stderr, "\n");
2864	va_end(ap);
2865	return (0);
2866}
2867
2868int
2869disallow_table(struct node_host *h, const char *fmt)
2870{
2871	for (; h != NULL; h = h->next)
2872		if (h->addr.type == PF_ADDR_TABLE) {
2873			yyerror(fmt, h->addr.v.tblname);
2874			return (1);
2875		}
2876	return (0);
2877}
2878
2879int
2880rule_consistent(struct pf_rule *r)
2881{
2882	int	problems = 0;
2883	switch (r->action) {
2884	case PF_PASS:
2885	case PF_DROP:
2886	case PF_SCRUB:
2887		problems = filter_consistent(r);
2888		break;
2889	case PF_NAT:
2890	case PF_NONAT:
2891		problems = nat_consistent(r);
2892		break;
2893	case PF_RDR:
2894	case PF_NORDR:
2895		problems = rdr_consistent(r);
2896		break;
2897	case PF_BINAT:
2898	case PF_NOBINAT:
2899	default:
2900		break;
2901	}
2902	return (problems);
2903}
2904
2905int
2906filter_consistent(struct pf_rule *r)
2907{
2908	int	problems = 0;
2909
2910	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
2911	    (r->src.port_op || r->dst.port_op)) {
2912		yyerror("port only applies to tcp/udp");
2913		problems++;
2914	}
2915	if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) {
2916		yyerror("the ':' port operator only applies to rdr");
2917		problems++;
2918	}
2919	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
2920	    (r->type || r->code)) {
2921		yyerror("icmp-type/code only applies to icmp");
2922		problems++;
2923	}
2924	if (!r->af && (r->type || r->code)) {
2925		yyerror("must indicate address family with icmp-type/code");
2926		problems++;
2927	}
2928	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
2929	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
2930		yyerror("proto %s doesn't match address family %s",
2931		    r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
2932		    r->af == AF_INET ? "inet" : "inet6");
2933		problems++;
2934	}
2935	if (r->keep_state == PF_STATE_MODULATE && r->proto &&
2936	    r->proto != IPPROTO_TCP) {
2937		yyerror("modulate state can only be applied to TCP rules");
2938		problems++;
2939	}
2940	if (r->allow_opts && r->action != PF_PASS) {
2941		yyerror("allow-opts can only be specified for pass rules");
2942		problems++;
2943	}
2944	if (!r->af && (r->src.addr.type == PF_ADDR_DYNIFTL ||
2945	    r->dst.addr.type == PF_ADDR_DYNIFTL)) {
2946		yyerror("dynamic addresses require address family "
2947		    "(inet/inet6)");
2948		problems++;
2949	}
2950	if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
2951	    r->dst.port_op || r->flagset || r->type || r->code)) {
2952		yyerror("fragments can be filtered only on IP header fields");
2953		problems++;
2954	}
2955	if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
2956		yyerror("return-rst can only be applied to TCP rules");
2957		problems++;
2958	}
2959	if (r->action == PF_DROP && r->keep_state) {
2960		yyerror("keep state on block rules doesn't make sense");
2961		problems++;
2962	}
2963	if ((r->tagname[0] || r->match_tagname[0]) && !r->keep_state &&
2964	    r->action == PF_PASS) {
2965		yyerror("tags cannot be used without keep state");
2966		problems++;
2967	}
2968	return (-problems);
2969}
2970
2971int
2972nat_consistent(struct pf_rule *r)
2973{
2974	int			 problems = 0;
2975	struct pf_pooladdr	*pa;
2976
2977	if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) {
2978		yyerror("the ':' port operator only applies to rdr");
2979		problems++;
2980	}
2981	if (!r->af) {
2982		TAILQ_FOREACH(pa, &r->rpool.list, entries) {
2983			if (pa->addr.addr.type == PF_ADDR_DYNIFTL) {
2984				yyerror("dynamic addresses require "
2985				    "address family (inet/inet6)");
2986				problems++;
2987				break;
2988			}
2989		}
2990	}
2991	return (-problems);
2992}
2993
2994int
2995rdr_consistent(struct pf_rule *r)
2996{
2997	int			 problems = 0;
2998	struct pf_pooladdr	*pa;
2999
3000	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
3001		if (r->src.port_op) {
3002			yyerror("src port only applies to tcp/udp");
3003			problems++;
3004		}
3005		if (r->dst.port_op) {
3006			yyerror("dst port only applies to tcp/udp");
3007			problems++;
3008		}
3009		if (r->rpool.proxy_port[0]) {
3010			yyerror("rpool port only applies to tcp/udp");
3011			problems++;
3012		}
3013	}
3014	if (r->dst.port_op &&
3015	    r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
3016		yyerror("invalid port operator for rdr destination port");
3017		problems++;
3018	}
3019	if (r->src.port_op == PF_OP_RRG) {
3020		yyerror("the ':' port operator only applies to rdr "
3021		    "destination port");
3022		problems++;
3023	}
3024	if (!r->af) {
3025		if (r->src.addr.type == PF_ADDR_DYNIFTL ||
3026		    r->dst.addr.type == PF_ADDR_DYNIFTL) {
3027			yyerror("dynamic addresses require address family "
3028			    "(inet/inet6)");
3029			problems++;
3030		} else {
3031			TAILQ_FOREACH(pa, &r->rpool.list, entries) {
3032				if (pa->addr.addr.type == PF_ADDR_DYNIFTL) {
3033					yyerror("dynamic addresses require "
3034					    "address family (inet/inet6)");
3035					problems++;
3036					break;
3037				}
3038			}
3039		}
3040	}
3041	return (-problems);
3042}
3043
3044struct keywords {
3045	const char	*k_name;
3046	int		 k_val;
3047};
3048
3049/* macro gore, but you should've seen the prior indentation nightmare... */
3050
3051#define FREE_LIST(T,r) \
3052	do { \
3053		T *p, *node = r; \
3054		while (node != NULL) { \
3055			p = node; \
3056			node = node->next; \
3057			free(p); \
3058		} \
3059	} while (0)
3060
3061#define LOOP_THROUGH(T,n,r,C) \
3062	do { \
3063		T *n; \
3064		if (r == NULL) { \
3065			r = calloc(1, sizeof(T)); \
3066			if (r == NULL) \
3067				err(1, "LOOP: calloc"); \
3068			r->next = NULL; \
3069		} \
3070		n = r; \
3071		while (n != NULL) { \
3072			do { \
3073				C; \
3074			} while (0); \
3075			n = n->next; \
3076		} \
3077	} while (0)
3078
3079void
3080expand_label_str(char *label, const char *srch, const char *repl)
3081{
3082	char tmp[PF_RULE_LABEL_SIZE] = "";
3083	char *p, *q;
3084
3085	p = q = label;
3086	while ((q = strstr(p, srch)) != NULL) {
3087		*q = '\0';
3088		if ((strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp)) ||
3089		    (strlcat(tmp, repl, sizeof(tmp)) >= sizeof(tmp)))
3090			err(1, "expand_label: label too long");
3091		q += strlen(srch);
3092		p = q;
3093	}
3094	if (strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp))
3095		err(1, "expand_label: label too long");
3096	strlcpy(label, tmp, PF_RULE_LABEL_SIZE);	/* always fits */
3097}
3098
3099void
3100expand_label_if(const char *name, char *label, const char *ifname)
3101{
3102	if (strstr(label, name) != NULL) {
3103		if (!*ifname)
3104			expand_label_str(label, name, "any");
3105		else
3106			expand_label_str(label, name, ifname);
3107	}
3108}
3109
3110void
3111expand_label_addr(const char *name, char *label, sa_family_t af,
3112    struct node_host *h)
3113{
3114	char tmp[64], tmp_not[66];
3115
3116	if (strstr(label, name) != NULL) {
3117		if (h->addr.type == PF_ADDR_DYNIFTL)
3118			snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
3119		else if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
3120		    PF_AZERO(&h->addr.v.a.mask, af)))
3121			snprintf(tmp, sizeof(tmp), "any");
3122		else {
3123			char	a[48];
3124			int	bits;
3125
3126			if (inet_ntop(af, &h->addr.v.a.addr, a, sizeof(a)) ==
3127			    NULL)
3128				snprintf(tmp, sizeof(tmp), "?");
3129			else {
3130				bits = unmask(&h->addr.v.a.mask, af);
3131				if ((af == AF_INET && bits < 32) ||
3132				    (af == AF_INET6 && bits < 128))
3133					snprintf(tmp, sizeof(tmp), "%s/%d",
3134					    a, bits);
3135				else
3136					snprintf(tmp, sizeof(tmp), "%s", a);
3137			}
3138		}
3139
3140		if (h->not) {
3141			snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
3142			expand_label_str(label, name, tmp_not);
3143		} else
3144			expand_label_str(label, name, tmp);
3145	}
3146}
3147
3148void
3149expand_label_port(const char *name, char *label, struct node_port *port)
3150{
3151	char	 a1[6], a2[6], op[13] = "";
3152
3153	if (strstr(label, name) != NULL) {
3154		snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
3155		snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
3156		if (!port->op)
3157			;
3158		else if (port->op == PF_OP_IRG)
3159			snprintf(op, sizeof(op), "%s><%s", a1, a2);
3160		else if (port->op == PF_OP_XRG)
3161			snprintf(op, sizeof(op), "%s<>%s", a1, a2);
3162		else if (port->op == PF_OP_EQ)
3163			snprintf(op, sizeof(op), "%s", a1);
3164		else if (port->op == PF_OP_NE)
3165			snprintf(op, sizeof(op), "!=%s", a1);
3166		else if (port->op == PF_OP_LT)
3167			snprintf(op, sizeof(op), "<%s", a1);
3168		else if (port->op == PF_OP_LE)
3169			snprintf(op, sizeof(op), "<=%s", a1);
3170		else if (port->op == PF_OP_GT)
3171			snprintf(op, sizeof(op), ">%s", a1);
3172		else if (port->op == PF_OP_GE)
3173			snprintf(op, sizeof(op), ">=%s", a1);
3174		expand_label_str(label, name, op);
3175	}
3176}
3177
3178void
3179expand_label_proto(const char *name, char *label, u_int8_t proto)
3180{
3181	struct protoent *pe;
3182	char n[4];
3183
3184	if (strstr(label, name) != NULL) {
3185		pe = getprotobynumber(proto);
3186		if (pe != NULL)
3187			expand_label_str(label, name, pe->p_name);
3188		else {
3189			snprintf(n, sizeof(n), "%u", proto);
3190			expand_label_str(label, name, n);
3191		}
3192	}
3193}
3194
3195void
3196expand_label_nr(const char *name, char *label)
3197{
3198	char n[11];
3199
3200	if (strstr(label, name) != NULL) {
3201		snprintf(n, sizeof(n), "%u", pf->rule_nr);
3202		expand_label_str(label, name, n);
3203	}
3204}
3205
3206void
3207expand_label(char *label, const char *ifname, sa_family_t af,
3208    struct node_host *src_host, struct node_port *src_port,
3209    struct node_host *dst_host, struct node_port *dst_port,
3210    u_int8_t proto)
3211{
3212	expand_label_if("$if", label, ifname);
3213	expand_label_addr("$srcaddr", label, af, src_host);
3214	expand_label_addr("$dstaddr", label, af, dst_host);
3215	expand_label_port("$srcport", label, src_port);
3216	expand_label_port("$dstport", label, dst_port);
3217	expand_label_proto("$proto", label, proto);
3218	expand_label_nr("$nr", label);
3219}
3220
3221int
3222expand_altq(struct pf_altq *a, struct node_if *interfaces,
3223    struct node_queue *nqueues, struct node_queue_bw bwspec,
3224    struct node_queue_opt *opts)
3225{
3226	struct pf_altq		 pa, pb;
3227	char			 qname[PF_QNAME_SIZE];
3228	struct node_queue	*n;
3229	struct node_queue_bw	 bw;
3230	int			 errs = 0;
3231
3232	if ((pf->loadopt & (PFCTL_FLAG_ALTQ | PFCTL_FLAG_ALL)) == 0) {
3233		FREE_LIST(struct node_if, interfaces);
3234		FREE_LIST(struct node_queue, nqueues);
3235		return (0);
3236	}
3237
3238	LOOP_THROUGH(struct node_if, interface, interfaces,
3239		memcpy(&pa, a, sizeof(struct pf_altq));
3240		if (strlcpy(pa.ifname, interface->ifname,
3241		    sizeof(pa.ifname)) >= sizeof(pa.ifname))
3242			errx(1, "expand_altq: strlcpy");
3243
3244		if (interface->not) {
3245			yyerror("altq on ! <interface> is not supported");
3246			errs++;
3247		} else {
3248			if (eval_pfaltq(pf, &pa, &bwspec, opts))
3249				errs++;
3250			else
3251				if (pfctl_add_altq(pf, &pa))
3252					errs++;
3253
3254			if (pf->opts & PF_OPT_VERBOSE) {
3255				print_altq(&pf->paltq->altq, 0,
3256				    &bwspec, opts);
3257				if (nqueues && nqueues->tail) {
3258					printf("queue { ");
3259					LOOP_THROUGH(struct node_queue, queue,
3260					    nqueues,
3261						printf("%s ",
3262						    queue->queue);
3263					);
3264					printf("}");
3265				}
3266				printf("\n");
3267			}
3268
3269			if (pa.scheduler == ALTQT_CBQ ||
3270			    pa.scheduler == ALTQT_HFSC) {
3271				/* now create a root queue */
3272				memset(&pb, 0, sizeof(struct pf_altq));
3273				if (strlcpy(qname, "root_", sizeof(qname)) >=
3274				    sizeof(qname))
3275					errx(1, "expand_altq: strlcpy");
3276				if (strlcat(qname, interface->ifname,
3277				    sizeof(qname)) >= sizeof(qname))
3278					errx(1, "expand_altq: strlcat");
3279				if (strlcpy(pb.qname, qname,
3280				    sizeof(pb.qname)) >= sizeof(pb.qname))
3281					errx(1, "expand_altq: strlcpy");
3282				if (strlcpy(pb.ifname, interface->ifname,
3283				    sizeof(pb.ifname)) >= sizeof(pb.ifname))
3284					errx(1, "expand_altq: strlcpy");
3285				pb.qlimit = pa.qlimit;
3286				pb.scheduler = pa.scheduler;
3287				bw.bw_absolute = pa.ifbandwidth;
3288				bw.bw_percent = 0;
3289				if (eval_pfqueue(pf, &pb, &bw, opts))
3290					errs++;
3291				else
3292					if (pfctl_add_altq(pf, &pb))
3293						errs++;
3294			}
3295
3296			LOOP_THROUGH(struct node_queue, queue, nqueues,
3297				n = calloc(1, sizeof(struct node_queue));
3298				if (n == NULL)
3299					err(1, "expand_altq: calloc");
3300				if (pa.scheduler == ALTQT_CBQ ||
3301				    pa.scheduler == ALTQT_HFSC)
3302					if (strlcpy(n->parent, qname,
3303					    sizeof(n->parent)) >=
3304					    sizeof(n->parent))
3305						errx(1, "expand_altq: strlcpy");
3306				if (strlcpy(n->queue, queue->queue,
3307				    sizeof(n->queue)) >= sizeof(n->queue))
3308					errx(1, "expand_altq: strlcpy");
3309				if (strlcpy(n->ifname, interface->ifname,
3310				    sizeof(n->ifname)) >= sizeof(n->ifname))
3311					errx(1, "expand_altq: strlcpy");
3312				n->scheduler = pa.scheduler;
3313				n->next = NULL;
3314				n->tail = n;
3315				if (queues == NULL)
3316					queues = n;
3317				else {
3318					queues->tail->next = n;
3319					queues->tail = n;
3320				}
3321			);
3322		}
3323	);
3324	FREE_LIST(struct node_if, interfaces);
3325	FREE_LIST(struct node_queue, nqueues);
3326
3327	return (errs);
3328}
3329
3330int
3331expand_queue(struct pf_altq *a, struct node_if *interfaces,
3332    struct node_queue *nqueues, struct node_queue_bw bwspec,
3333    struct node_queue_opt *opts)
3334{
3335	struct node_queue	*n, *nq;
3336	struct pf_altq		 pa;
3337	u_int8_t		 found = 0;
3338	u_int8_t		 errs = 0;
3339
3340	if ((pf->loadopt & (PFCTL_FLAG_ALTQ | PFCTL_FLAG_ALL)) == 0) {
3341		FREE_LIST(struct node_queue, nqueues);
3342		return (0);
3343	}
3344
3345	if (queues == NULL) {
3346		yyerror("queue %s has no parent", a->qname);
3347		FREE_LIST(struct node_queue, nqueues);
3348		return (1);
3349	}
3350
3351	LOOP_THROUGH(struct node_if, interface, interfaces,
3352		LOOP_THROUGH(struct node_queue, tqueue, queues,
3353			if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
3354			    (interface->ifname[0] == 0 ||
3355			    (!interface->not && !strncmp(interface->ifname,
3356			    tqueue->ifname, IFNAMSIZ)) ||
3357			    (interface->not && strncmp(interface->ifname,
3358			    tqueue->ifname, IFNAMSIZ)))) {
3359				/* found ourselve in queues */
3360				found++;
3361
3362				memcpy(&pa, a, sizeof(struct pf_altq));
3363
3364				if (pa.scheduler != ALTQT_NONE &&
3365				    pa.scheduler != tqueue->scheduler) {
3366					yyerror("exactly one scheduler type "
3367					    "per interface allowed");
3368					return (1);
3369				}
3370				pa.scheduler = tqueue->scheduler;
3371
3372				/* scheduler dependent error checking */
3373				switch (pa.scheduler) {
3374				case ALTQT_PRIQ:
3375					if (nqueues != NULL) {
3376						yyerror("priq queues cannot "
3377						    "have child queues");
3378						return (1);
3379					}
3380					if (bwspec.bw_absolute > 0 ||
3381					    bwspec.bw_percent < 100) {
3382						yyerror("priq doesn't take "
3383						    "bandwidth");
3384						return (1);
3385					}
3386					break;
3387				default:
3388					break;
3389				}
3390
3391				if (strlcpy(pa.ifname, tqueue->ifname,
3392				    sizeof(pa.ifname)) >= sizeof(pa.ifname))
3393					errx(1, "expand_queue: strlcpy");
3394				if (strlcpy(pa.parent, tqueue->parent,
3395				    sizeof(pa.parent)) >= sizeof(pa.parent))
3396					errx(1, "expand_queue: strlcpy");
3397
3398				if (eval_pfqueue(pf, &pa, &bwspec, opts))
3399					errs++;
3400				else
3401					if (pfctl_add_altq(pf, &pa))
3402						errs++;
3403
3404				for (nq = nqueues; nq != NULL; nq = nq->next) {
3405					n = calloc(1,
3406					    sizeof(struct node_queue));
3407					if (n == NULL)
3408						err(1, "expand_queue: calloc");
3409					if (strlcpy(n->parent, a->qname,
3410					    sizeof(n->parent)) >=
3411					    sizeof(n->parent))
3412						errx(1, "expand_queue strlcpy");
3413					if (strlcpy(n->queue, nq->queue,
3414					    sizeof(n->queue)) >=
3415					    sizeof(n->queue))
3416						errx(1, "expand_queue strlcpy");
3417					if (strlcpy(n->ifname, tqueue->ifname,
3418					    sizeof(n->ifname)) >=
3419					    sizeof(n->ifname))
3420						errx(1, "expand_queue strlcpy");
3421					n->scheduler = tqueue->scheduler;
3422					n->next = NULL;
3423					n->tail = n;
3424					if (queues == NULL)
3425						queues = n;
3426					else {
3427						queues->tail->next = n;
3428						queues->tail = n;
3429					}
3430				}
3431				if ((pf->opts & PF_OPT_VERBOSE) && (
3432				    (found == 1 && interface->ifname[0] == 0) ||
3433				    (found > 0 && interface->ifname[0] != 0))) {
3434					print_queue(&pf->paltq->altq, 0,
3435					    &bwspec, interface->ifname[0] != 0,
3436					    opts);
3437					if (nqueues && nqueues->tail) {
3438						printf("{ ");
3439						LOOP_THROUGH(struct node_queue,
3440						    queue, nqueues,
3441							printf("%s ",
3442							    queue->queue);
3443						);
3444						printf("}");
3445					}
3446					printf("\n");
3447				}
3448			}
3449		);
3450	);
3451
3452	FREE_LIST(struct node_queue, nqueues);
3453	FREE_LIST(struct node_if, interfaces);
3454
3455	if (!found) {
3456		yyerror("queue %s has no parent", a->qname);
3457		errs++;
3458	}
3459
3460	if (errs)
3461		return (1);
3462	else
3463		return (0);
3464}
3465
3466void
3467expand_rule(struct pf_rule *r,
3468    struct node_if *interfaces, struct node_host *rpool_hosts,
3469    struct node_proto *protos, struct node_host *src_hosts,
3470    struct node_port *src_ports, struct node_host *dst_hosts,
3471    struct node_port *dst_ports, struct node_uid *uids,
3472    struct node_gid *gids, struct node_icmp *icmp_types)
3473{
3474	sa_family_t		 af = r->af;
3475	int			 added = 0, error = 0;
3476	char			 ifname[IF_NAMESIZE];
3477	char			 label[PF_RULE_LABEL_SIZE];
3478	struct pf_pooladdr	*pa;
3479	struct node_host	*h;
3480	u_int8_t		 flags, flagset;
3481
3482	if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
3483		errx(1, "expand_rule: strlcpy");
3484	flags = r->flags;
3485	flagset = r->flagset;
3486
3487	LOOP_THROUGH(struct node_if, interface, interfaces,
3488	LOOP_THROUGH(struct node_proto, proto, protos,
3489	LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
3490	LOOP_THROUGH(struct node_host, src_host, src_hosts,
3491	LOOP_THROUGH(struct node_port, src_port, src_ports,
3492	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
3493	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
3494	LOOP_THROUGH(struct node_uid, uid, uids,
3495	LOOP_THROUGH(struct node_gid, gid, gids,
3496
3497		r->af = af;
3498		/* for link-local IPv6 address, interface must match up */
3499		if ((r->af && src_host->af && r->af != src_host->af) ||
3500		    (r->af && dst_host->af && r->af != dst_host->af) ||
3501		    (src_host->af && dst_host->af &&
3502		    src_host->af != dst_host->af) ||
3503		    (src_host->ifindex && dst_host->ifindex &&
3504		    src_host->ifindex != dst_host->ifindex) ||
3505		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
3506		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
3507		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
3508		    dst_host->ifindex != if_nametoindex(interface->ifname)))
3509			continue;
3510		if (!r->af && src_host->af)
3511			r->af = src_host->af;
3512		else if (!r->af && dst_host->af)
3513			r->af = dst_host->af;
3514
3515		if (if_indextoname(src_host->ifindex, ifname))
3516			memcpy(r->ifname, ifname, sizeof(r->ifname));
3517		else if (if_indextoname(dst_host->ifindex, ifname))
3518			memcpy(r->ifname, ifname, sizeof(r->ifname));
3519		else
3520			memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
3521
3522		if (strlcpy(r->label, label, sizeof(r->label)) >=
3523		    sizeof(r->label))
3524			errx(1, "expand_rule: strlcpy");
3525		expand_label(r->label, r->ifname, r->af, src_host, src_port,
3526		    dst_host, dst_port, proto->proto);
3527		r->ifnot = interface->not;
3528		r->proto = proto->proto;
3529		r->src.addr = src_host->addr;
3530		r->src.not = src_host->not;
3531		r->src.port[0] = src_port->port[0];
3532		r->src.port[1] = src_port->port[1];
3533		r->src.port_op = src_port->op;
3534		r->dst.addr = dst_host->addr;
3535		r->dst.not = dst_host->not;
3536		r->dst.port[0] = dst_port->port[0];
3537		r->dst.port[1] = dst_port->port[1];
3538		r->dst.port_op = dst_port->op;
3539		r->uid.op = uid->op;
3540		r->uid.uid[0] = uid->uid[0];
3541		r->uid.uid[1] = uid->uid[1];
3542		r->gid.op = gid->op;
3543		r->gid.gid[0] = gid->gid[0];
3544		r->gid.gid[1] = gid->gid[1];
3545		r->type = icmp_type->type;
3546		r->code = icmp_type->code;
3547
3548		if (r->proto && r->proto != IPPROTO_TCP) {
3549			r->flags = 0;
3550			r->flagset = 0;
3551		} else {
3552			r->flags = flags;
3553			r->flagset = flagset;
3554		}
3555		if (icmp_type->proto && r->proto != icmp_type->proto) {
3556			yyerror("icmp-type mismatch");
3557			error++;
3558		}
3559
3560		TAILQ_INIT(&r->rpool.list);
3561		for (h = rpool_hosts; h != NULL; h = h->next) {
3562			pa = calloc(1, sizeof(struct pf_pooladdr));
3563			if (pa == NULL)
3564				err(1, "expand_rule: calloc");
3565			pa->addr.addr = h->addr;
3566			if (h->ifname != NULL) {
3567				if (strlcpy(pa->ifname, h->ifname,
3568				    sizeof(pa->ifname)) >=
3569				    sizeof(pa->ifname))
3570					errx(1, "expand_rule: strlcpy");
3571			} else
3572				pa->ifname[0] = 0;
3573			TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
3574		}
3575
3576		if (rule_consistent(r) < 0 || error)
3577			yyerror("skipping rule due to errors");
3578		else {
3579			r->nr = pf->rule_nr++;
3580			pfctl_add_rule(pf, r);
3581			added++;
3582		}
3583
3584	)))))))));
3585
3586	FREE_LIST(struct node_if, interfaces);
3587	FREE_LIST(struct node_proto, protos);
3588	FREE_LIST(struct node_host, src_hosts);
3589	FREE_LIST(struct node_port, src_ports);
3590	FREE_LIST(struct node_host, dst_hosts);
3591	FREE_LIST(struct node_port, dst_ports);
3592	FREE_LIST(struct node_uid, uids);
3593	FREE_LIST(struct node_gid, gids);
3594	FREE_LIST(struct node_icmp, icmp_types);
3595	FREE_LIST(struct node_host, rpool_hosts);
3596
3597	if (!added)
3598		yyerror("rule expands to no valid combination");
3599}
3600
3601#undef FREE_LIST
3602#undef LOOP_THROUGH
3603
3604int
3605check_rulestate(int desired_state)
3606{
3607	if (require_order && (rulestate > desired_state)) {
3608		yyerror("Rules must be in order: options, normalization, "
3609		    "queueing, translation, filtering");
3610		return (1);
3611	}
3612	rulestate = desired_state;
3613	return (0);
3614}
3615
3616int
3617kw_cmp(const void *k, const void *e)
3618{
3619	return (strcmp(k, ((const struct keywords *)e)->k_name));
3620}
3621
3622int
3623lookup(char *s)
3624{
3625	/* this has to be sorted always */
3626	static const struct keywords keywords[] = {
3627		{ "all",		ALL},
3628		{ "allow-opts",		ALLOWOPTS},
3629		{ "altq",		ALTQ},
3630		{ "anchor",		ANCHOR},
3631		{ "antispoof",		ANTISPOOF},
3632		{ "any",		ANY},
3633		{ "bandwidth",		BANDWIDTH},
3634		{ "binat",		BINAT},
3635		{ "binat-anchor",	BINATANCHOR},
3636		{ "bitmask",		BITMASK},
3637		{ "block",		BLOCK},
3638		{ "block-policy",	BLOCKPOLICY},
3639		{ "cbq",		CBQ},
3640		{ "code",		CODE},
3641		{ "crop",		FRAGCROP},
3642		{ "drop",		DROP},
3643		{ "drop-ovl",		FRAGDROP},
3644		{ "dup-to",		DUPTO},
3645		{ "fastroute",		FASTROUTE},
3646		{ "file",		FILENAME},
3647		{ "flags",		FLAGS},
3648		{ "for",		FOR},
3649		{ "fragment",		FRAGMENT},
3650		{ "from",		FROM},
3651		{ "group",		GROUP},
3652		{ "hfsc",		HFSC},
3653		{ "icmp-type",		ICMPTYPE},
3654		{ "icmp6-type",		ICMP6TYPE},
3655		{ "in",			IN},
3656		{ "inet",		INET},
3657		{ "inet6",		INET6},
3658		{ "keep",		KEEP},
3659		{ "label",		LABEL},
3660		{ "limit",		LIMIT},
3661		{ "linkshare",		LINKSHARE},
3662		{ "load",		LOAD},
3663		{ "log",		LOG},
3664		{ "log-all",		LOGALL},
3665		{ "loginterface",	LOGINTERFACE},
3666		{ "max",		MAXIMUM},
3667		{ "max-mss",		MAXMSS},
3668		{ "min-ttl",		MINTTL},
3669		{ "modulate",		MODULATE},
3670		{ "nat",		NAT},
3671		{ "nat-anchor",		NATANCHOR},
3672		{ "no",			NO},
3673		{ "no-df",		NODF},
3674		{ "no-route",		NOROUTE},
3675		{ "on",			ON},
3676		{ "optimization",	OPTIMIZATION},
3677		{ "out",		OUT},
3678		{ "pass",		PASS},
3679		{ "port",		PORT},
3680		{ "priority",		PRIORITY},
3681		{ "priq",		PRIQ},
3682		{ "proto",		PROTO},
3683		{ "qlimit",		QLIMIT},
3684		{ "queue",		QUEUE},
3685		{ "quick",		QUICK},
3686		{ "random",		RANDOM},
3687		{ "random-id",		RANDOMID},
3688		{ "rdr",		RDR},
3689		{ "rdr-anchor",		RDRANCHOR},
3690		{ "realtime",		REALTIME},
3691		{ "reassemble",		FRAGNORM},
3692		{ "reply-to",		REPLYTO},
3693		{ "require-order",	REQUIREORDER},
3694		{ "return",		RETURN},
3695		{ "return-icmp",	RETURNICMP},
3696		{ "return-icmp6",	RETURNICMP6},
3697		{ "return-rst",		RETURNRST},
3698		{ "round-robin",	ROUNDROBIN},
3699		{ "route-to",		ROUTETO},
3700		{ "scrub",		SCRUB},
3701		{ "set",		SET},
3702		{ "source-hash",	SOURCEHASH},
3703		{ "state",		STATE},
3704		{ "static-port",	STATICPORT},
3705		{ "table",		TABLE},
3706		{ "tag",		TAG},
3707		{ "tagged",		TAGGED},
3708		{ "tbrsize",		TBRSIZE},
3709		{ "timeout",		TIMEOUT},
3710		{ "to",			TO},
3711		{ "tos",		TOS},
3712		{ "ttl",		TTL},
3713		{ "upperlimit",		UPPERLIMIT},
3714		{ "user",		USER},
3715	};
3716	const struct keywords	*p;
3717
3718	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
3719	    sizeof(keywords[0]), kw_cmp);
3720
3721	if (p) {
3722		if (debug > 1)
3723			fprintf(stderr, "%s: %d\n", s, p->k_val);
3724		return (p->k_val);
3725	} else {
3726		if (debug > 1)
3727			fprintf(stderr, "string: %s\n", s);
3728		return (STRING);
3729	}
3730}
3731
3732#define MAXPUSHBACK	128
3733
3734char	*parsebuf;
3735int	 parseindex;
3736char	 pushback_buffer[MAXPUSHBACK];
3737int	 pushback_index = 0;
3738
3739int
3740lgetc(FILE *f)
3741{
3742	int	c, next;
3743
3744	if (parsebuf) {
3745		/* Read character from the parsebuffer instead of input. */
3746		if (parseindex >= 0) {
3747			c = parsebuf[parseindex++];
3748			if (c != '\0')
3749				return (c);
3750			parsebuf = NULL;
3751		} else
3752			parseindex++;
3753	}
3754
3755	if (pushback_index)
3756		return (pushback_buffer[--pushback_index]);
3757
3758	while ((c = getc(f)) == '\\') {
3759		next = getc(f);
3760		if (next != '\n') {
3761			if (isspace(next))
3762				yyerror("whitespace after \\");
3763			ungetc(next, f);
3764			break;
3765		}
3766		yylval.lineno = lineno;
3767		lineno++;
3768	}
3769	if (c == '\t' || c == ' ') {
3770		/* Compress blanks to a single space. */
3771		do {
3772			c = getc(f);
3773		} while (c == '\t' || c == ' ');
3774		ungetc(c, f);
3775		c = ' ';
3776	}
3777
3778	return (c);
3779}
3780
3781int
3782lungetc(int c)
3783{
3784	if (c == EOF)
3785		return (EOF);
3786	if (parsebuf) {
3787		parseindex--;
3788		if (parseindex >= 0)
3789			return (c);
3790	}
3791	if (pushback_index < MAXPUSHBACK-1)
3792		return (pushback_buffer[pushback_index++] = c);
3793	else
3794		return (EOF);
3795}
3796
3797int
3798findeol(void)
3799{
3800	int	c;
3801
3802	parsebuf = NULL;
3803	pushback_index = 0;
3804
3805	/* skip to either EOF or the first real EOL */
3806	while (1) {
3807		c = lgetc(fin);
3808		if (c == '\n') {
3809			lineno++;
3810			break;
3811		}
3812		if (c == EOF)
3813			break;
3814	}
3815	return (ERROR);
3816}
3817
3818int
3819yylex(void)
3820{
3821	char	 buf[8096];
3822	char	*p, *val;
3823	int	 endc, c, next;
3824	int	 token;
3825
3826top:
3827	p = buf;
3828	while ((c = lgetc(fin)) == ' ')
3829		; /* nothing */
3830
3831	yylval.lineno = lineno;
3832	if (c == '#')
3833		while ((c = lgetc(fin)) != '\n' && c != EOF)
3834			; /* nothing */
3835	if (c == '$' && parsebuf == NULL) {
3836		while (1) {
3837			if ((c = lgetc(fin)) == EOF)
3838				return (0);
3839
3840			if (p + 1 >= buf + sizeof(buf) - 1) {
3841				yyerror("string too long");
3842				return (findeol());
3843			}
3844			if (isalnum(c) || c == '_') {
3845				*p++ = (char)c;
3846				continue;
3847			}
3848			*p = '\0';
3849			lungetc(c);
3850			break;
3851		}
3852		val = symget(buf);
3853		if (val == NULL) {
3854			yyerror("macro '%s' not defined", buf);
3855			return (findeol());
3856		}
3857		parsebuf = val;
3858		parseindex = 0;
3859		goto top;
3860	}
3861
3862	switch (c) {
3863	case '\'':
3864	case '"':
3865		endc = c;
3866		while (1) {
3867			if ((c = lgetc(fin)) == EOF)
3868				return (0);
3869			if (c == endc) {
3870				*p = '\0';
3871				break;
3872			}
3873			if (c == '\n') {
3874				lineno++;
3875				continue;
3876			}
3877			if (p + 1 >= buf + sizeof(buf) - 1) {
3878				yyerror("string too long");
3879				return (findeol());
3880			}
3881			*p++ = (char)c;
3882		}
3883		yylval.v.string = strdup(buf);
3884		if (yylval.v.string == NULL)
3885			err(1, "yylex: strdup");
3886		return (STRING);
3887	case '<':
3888		next = lgetc(fin);
3889		if (next == '>') {
3890			yylval.v.i = PF_OP_XRG;
3891			return (PORTBINARY);
3892		}
3893		lungetc(next);
3894		break;
3895	case '>':
3896		next = lgetc(fin);
3897		if (next == '<') {
3898			yylval.v.i = PF_OP_IRG;
3899			return (PORTBINARY);
3900		}
3901		lungetc(next);
3902		break;
3903	case '-':
3904		next = lgetc(fin);
3905		if (next == '>')
3906			return (ARROW);
3907		lungetc(next);
3908		break;
3909	}
3910
3911#define allowed_in_string(x) \
3912	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
3913	x != '{' && x != '}' && x != '<' && x != '>' && \
3914	x != '!' && x != '=' && x != '/' && x != '#' && \
3915	x != ','))
3916
3917	if (isalnum(c) || c == ':' || c == '_') {
3918		do {
3919			*p++ = c;
3920			if ((unsigned)(p-buf) >= sizeof(buf)) {
3921				yyerror("string too long");
3922				return (findeol());
3923			}
3924		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
3925		lungetc(c);
3926		*p = '\0';
3927		token = lookup(buf);
3928		yylval.v.string = strdup(buf);
3929		if (yylval.v.string == NULL)
3930			err(1, "yylex: strdup");
3931		return (token);
3932	}
3933	if (c == '\n') {
3934		yylval.lineno = lineno;
3935		lineno++;
3936	}
3937	if (c == EOF)
3938		return (0);
3939	return (c);
3940}
3941
3942int
3943parse_rules(FILE *input, struct pfctl *xpf)
3944{
3945	struct sym	*sym;
3946
3947	fin = input;
3948	pf = xpf;
3949	lineno = 1;
3950	errors = 0;
3951	rulestate = PFCTL_STATE_NONE;
3952	returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
3953	returnicmp6default =
3954	    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
3955	blockpolicy = PFRULE_DROP;
3956	require_order = 1;
3957
3958	yyparse();
3959
3960	/* Free macros and check which have not been used. */
3961	TAILQ_FOREACH(sym, &symhead, entries) {
3962		if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
3963			fprintf(stderr, "warning: macro '%s' not "
3964			    "used\n", sym->nam);
3965		free(sym->nam);
3966		free(sym->val);
3967		TAILQ_REMOVE(&symhead, sym, entries);
3968	}
3969
3970	return (errors ? -1 : 0);
3971}
3972
3973/*
3974 * Over-designed efficiency is a French and German concept, so how about
3975 * we wait until they discover this ugliness and make it all fancy.
3976 */
3977int
3978symset(const char *nam, const char *val, int persist)
3979{
3980	struct sym	*sym;
3981
3982	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
3983	    sym = TAILQ_NEXT(sym, entries))
3984		;	/* nothing */
3985
3986	if (sym != NULL) {
3987		if (sym->persist == 1)
3988			return (0);
3989		else {
3990			free(sym->nam);
3991			free(sym->val);
3992			TAILQ_REMOVE(&symhead, sym, entries);
3993			free(sym);
3994		}
3995	}
3996	if ((sym = calloc(1, sizeof(*sym))) == NULL)
3997		return (-1);
3998
3999	sym->nam = strdup(nam);
4000	if (sym->nam == NULL) {
4001		free(sym);
4002		return (-1);
4003	}
4004	sym->val = strdup(val);
4005	if (sym->val == NULL) {
4006		free(sym->nam);
4007		free(sym);
4008		return (-1);
4009	}
4010	sym->used = 0;
4011	sym->persist = persist;
4012	TAILQ_INSERT_TAIL(&symhead, sym, entries);
4013	return (0);
4014}
4015
4016int
4017pfctl_cmdline_symset(char *s)
4018{
4019	char	*sym, *val;
4020	int	 ret;
4021
4022	if ((val = strrchr(s, '=')) == NULL)
4023		return (-1);
4024
4025	if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
4026		err(1, "pfctl_cmdline_symset: malloc");
4027
4028	strlcpy(sym, s, strlen(s) - strlen(val) + 1);
4029
4030	ret = symset(sym, val + 1, 1);
4031	free(sym);
4032
4033	return (ret);
4034}
4035
4036char *
4037symget(const char *nam)
4038{
4039	struct sym	*sym;
4040
4041	TAILQ_FOREACH(sym, &symhead, entries)
4042		if (strcmp(nam, sym->nam) == 0) {
4043			sym->used = 1;
4044			return (sym->val);
4045		}
4046	return (NULL);
4047}
4048
4049void
4050decide_address_family(struct node_host *n, sa_family_t *af)
4051{
4052	sa_family_t	target_af = 0;
4053
4054	while (!*af && n != NULL) {
4055		if (n->af) {
4056			if (target_af == 0)
4057				target_af = n->af;
4058			if (target_af != n->af)
4059				return;
4060		}
4061		n = n->next;
4062	}
4063	if (!*af && target_af)
4064		*af = target_af;
4065}
4066
4067void
4068remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
4069{
4070	struct node_host	*n = *nh, *prev = NULL;
4071
4072	while (n != NULL) {
4073		if (*af && n->af && n->af != *af) {
4074			/* unlink and free n */
4075			struct node_host *next = n->next;
4076
4077			/* adjust tail pointer */
4078			if (n == (*nh)->tail)
4079				(*nh)->tail = prev;
4080			/* adjust previous node's next pointer */
4081			if (prev == NULL)
4082				*nh = next;
4083			else
4084				prev->next = next;
4085			/* free node */
4086			if (n->ifname != NULL)
4087				free(n->ifname);
4088			free(n);
4089			n = next;
4090		} else {
4091			if (n->af && !*af)
4092				*af = n->af;
4093			prev = n;
4094			n = n->next;
4095		}
4096	}
4097}
4098
4099int
4100invalid_redirect(struct node_host *nh, sa_family_t af)
4101{
4102	if (!af) {
4103		yyerror("address family not given and translation "
4104		    "address expands to multiple address families");
4105		return (1);
4106	}
4107	if (nh == NULL) {
4108		yyerror("no translation address with matching address family "
4109		    "found.");
4110		return (1);
4111	}
4112	return (0);
4113}
4114
4115int
4116atoul(char *s, u_long *ulvalp)
4117{
4118	u_long	 ulval;
4119	char	*ep;
4120
4121	errno = 0;
4122	ulval = strtoul(s, &ep, 0);
4123	if (s[0] == '\0' || *ep != '\0')
4124		return (-1);
4125	if (errno == ERANGE && ulval == ULONG_MAX)
4126		return (-1);
4127	*ulvalp = ulval;
4128	return (0);
4129}
4130
4131int
4132getservice(char *n)
4133{
4134	struct servent	*s;
4135	u_long		 ulval;
4136
4137	if (atoul(n, &ulval) == 0) {
4138		if (ulval > 65535) {
4139			yyerror("illegal port value %d", ulval);
4140			return (-1);
4141		}
4142		return (htons(ulval));
4143	} else {
4144		s = getservbyname(n, "tcp");
4145		if (s == NULL)
4146			s = getservbyname(n, "udp");
4147		if (s == NULL) {
4148			yyerror("unknown port %s", n);
4149			return (-1);
4150		}
4151		return (s->s_port);
4152	}
4153}
4154
4155int
4156rule_label(struct pf_rule *r, char *s)
4157{
4158	if (s) {
4159		if (strlcpy(r->label, s, sizeof(r->label)) >=
4160		    sizeof(r->label)) {
4161			yyerror("rule label too long (max %d chars)",
4162			    sizeof(r->label)-1);
4163			return (-1);
4164		}
4165	}
4166	return (0);
4167}
4168
4169u_int16_t
4170parseicmpspec(char *w, sa_family_t af)
4171{
4172	const struct icmpcodeent	*p;
4173	u_long				 ulval;
4174	u_int8_t			 icmptype;
4175
4176	if (af == AF_INET)
4177		icmptype = returnicmpdefault >> 8;
4178	else
4179		icmptype = returnicmp6default >> 8;
4180
4181	if (atoul(w, &ulval) == -1) {
4182		if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
4183			yyerror("unknown icmp code %s", w);
4184			return (0);
4185		}
4186		ulval = p->code;
4187	}
4188	if (ulval > 255) {
4189		yyerror("invalid icmp code %ld", ulval);
4190		return (0);
4191	}
4192	return (icmptype << 8 | ulval);
4193}
4194
4195int
4196pfctl_load_anchors(int dev, int opts)
4197{
4198	struct loadanchors	*la;
4199
4200	TAILQ_FOREACH(la, &loadanchorshead, entries) {
4201		if (opts & PF_OPT_VERBOSE)
4202			fprintf(stderr, "\nLoading anchor %s:%s from %s\n",
4203			    la->anchorname, la->rulesetname, la->filename);
4204		if (pfctl_rules(dev, la->filename, opts, la->anchorname,
4205		    la->rulesetname) == -1)
4206			return (-1);
4207	}
4208
4209	return (0);
4210}
4211
4212