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