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