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