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