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