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