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