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