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