parse.y revision 1.161
1/*	$OpenBSD: parse.y,v 1.161 2002/10/07 13:18:40 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
52#include "pfctl_parser.h"
53
54static struct pfctl *pf = NULL;
55static FILE *fin = NULL;
56static int debug = 0;
57static int lineno = 1;
58static int errors = 0;
59static int rulestate = 0;
60static u_int16_t returnicmpdefault =  (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
61static u_int16_t returnicmp6default = (ICMP6_DST_UNREACH << 8)
62    | ICMP6_DST_UNREACH_NOPORT;
63
64enum {
65	PFCTL_STATE_NONE = 0,
66	PFCTL_STATE_OPTION = 1,
67	PFCTL_STATE_SCRUB = 2,
68	PFCTL_STATE_NAT = 3,
69	PFCTL_STATE_FILTER = 4
70};
71
72enum pfctl_iflookup_mode {
73	PFCTL_IFLOOKUP_HOST = 0,
74	PFCTL_IFLOOKUP_NET = 1,
75	PFCTL_IFLOOKUP_BCAST = 2
76};
77
78struct node_if {
79	char			 ifname[IFNAMSIZ];
80	u_int8_t		 not;
81	u_int			 ifa_flags;
82	struct node_if		*next;
83	struct node_if		*tail;
84};
85
86struct node_proto {
87	u_int8_t		 proto;
88	struct node_proto	*next;
89	struct node_proto	*tail;
90};
91
92struct node_host {
93	struct pf_addr_wrap	 addr;
94	struct pf_addr		 mask;
95	struct pf_addr		 bcast;
96	u_int8_t		 af;
97	u_int8_t		 not;
98	u_int8_t		 noroute;
99	u_int32_t		 ifindex;	/* link-local IPv6 addrs */
100	char			*ifname;
101	u_int			 ifa_flags;
102	struct node_host	*next;
103	struct node_host	*tail;
104};
105
106struct node_port {
107	u_int16_t		 port[2];
108	u_int8_t		 op;
109	struct node_port	*next;
110	struct node_port	*tail;
111};
112
113struct node_uid {
114	uid_t			 uid[2];
115	u_int8_t		 op;
116	struct node_uid		*next;
117	struct node_uid		*tail;
118};
119
120struct node_gid {
121	gid_t			 gid[2];
122	u_int8_t		 op;
123	struct node_gid		*next;
124	struct node_gid		*tail;
125};
126
127struct node_icmp {
128	u_int8_t		 code;
129	u_int8_t		 type;
130	u_int8_t		 proto;
131	struct node_icmp	*next;
132	struct node_icmp	*tail;
133};
134
135enum	{ PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 };
136struct node_state_opt {
137	int			 type;
138	union {
139		u_int32_t	 max_states;
140		struct {
141			int		number;
142			u_int32_t	seconds;
143		}		 timeout;
144	}			 data;
145	struct node_state_opt	*next;
146	struct node_state_opt	*tail;
147};
148
149struct peer {
150	struct node_host	*host;
151	struct node_port	*port;
152};
153
154int	yyerror(char *, ...);
155int	rule_consistent(struct pf_rule *);
156int	nat_consistent(struct pf_nat *);
157int	rdr_consistent(struct pf_rdr *);
158int	yyparse(void);
159void	ipmask(struct pf_addr *, u_int8_t);
160void	expand_rdr(struct pf_rdr *, struct node_if *, struct node_proto *,
161	    struct node_host *, struct node_host *);
162void	expand_nat(struct pf_nat *, struct node_if *, struct node_proto *,
163	    struct node_host *, struct node_port *,
164	    struct node_host *, struct node_port *);
165void	expand_label_addr(const char *, char *, u_int8_t, struct node_host *);
166void	expand_label_port(const char *, char *, struct node_port *);
167void	expand_label_proto(const char *, char *, u_int8_t);
168void	expand_label_nr(const char *, char *);
169void	expand_label(char *, u_int8_t, struct node_host *, struct node_port *,
170	    struct node_host *, struct node_port *, u_int8_t);
171void	expand_rule(struct pf_rule *, struct node_if *, struct node_proto *,
172	    struct node_host *, struct node_port *, struct node_host *,
173	    struct node_port *, struct node_uid *, struct node_gid *,
174	    struct node_icmp *);
175int	check_rulestate(int);
176int	kw_cmp(const void *, const void *);
177int	lookup(char *);
178int	lgetc(FILE *);
179int	lungetc(int, FILE *);
180int	findeol(void);
181int	yylex(void);
182struct	node_host *host(char *);
183int	atoul(char *, u_long *);
184int	getservice(char *);
185
186
187struct sym {
188	struct sym *next;
189	char *nam;
190	char *val;
191};
192struct sym *symhead = NULL;
193
194int	symset(const char *, const char *);
195char *	symget(const char *);
196
197void	ifa_load(void);
198struct	node_host *ifa_exists(char *);
199struct	node_host *ifa_lookup(char *, enum pfctl_iflookup_mode);
200struct	node_host *ifa_pick_ip(struct node_host *, u_int8_t);
201u_int16_t	parseicmpspec(char *, u_int8_t);
202
203typedef struct {
204	union {
205		u_int32_t		number;
206		int			i;
207		char			*string;
208		struct {
209			u_int8_t	b1;
210			u_int8_t	b2;
211			u_int16_t	w;
212			u_int16_t	w2;
213		}			b;
214		struct range {
215			int		a;
216			int		b;
217			int		t;
218		}			range;
219		struct node_if		*interface;
220		struct node_proto	*proto;
221		struct node_icmp	*icmp;
222		struct node_host	*host;
223		struct node_port	*port;
224		struct node_uid		*uid;
225		struct node_gid		*gid;
226		struct node_state_opt	*state_opt;
227		struct peer		peer;
228		struct {
229			struct peer	src, dst;
230		}			fromto;
231		struct {
232			char		*string;
233			struct pf_addr	*addr;
234			u_int8_t	rt;
235			u_int8_t	af;
236		}			route;
237		struct redirection {
238			struct node_host	*address;
239			struct range		 rport;
240		}			*redirection;
241		struct {
242			int			 action;
243			struct node_state_opt	*options;
244		}			keep_state;
245		struct {
246			u_int8_t	log;
247			u_int8_t	quick;
248		}			logquick;
249	} v;
250	int lineno;
251} YYSTYPE;
252
253%}
254
255%token	PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS
256%token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
257%token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
258%token	MINTTL ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO REPLYTO NO LABEL
259%token	NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS
260%token	FRAGNORM FRAGDROP FRAGCROP
261%token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE
262%token	ANTISPOOF FOR
263%token	<v.string> STRING
264%token	<v.i>	PORTUNARY PORTBINARY
265%type	<v.interface>	interface if_list if_item_not if_item
266%type	<v.number>	number port icmptype icmp6type minttl uid gid maxmss
267%type	<v.number>	tos
268%type	<v.i>	no dir log af nodf allowopts fragment fragcache
269%type	<v.b>	action flag flags blockspec
270%type	<v.range>	dport rport
271%type	<v.proto>	proto proto_list proto_item
272%type	<v.icmp>	icmpspec icmp_list icmp6_list icmp_item icmp6_item
273%type	<v.fromto>	fromto
274%type	<v.peer>	ipportspec
275%type	<v.host>	ipspec xhost host address host_list
276%type	<v.port>	portspec port_list port_item
277%type	<v.uid>		uids uid_list uid_item
278%type	<v.gid>		gids gid_list gid_item
279%type	<v.route>	route
280%type	<v.redirection>	redirection
281%type	<v.string>	label string
282%type	<v.keep_state>	keep
283%type	<v.state_opt>	state_opt_spec state_opt_list state_opt_item
284%type	<v.logquick>	logquick
285%type	<v.interface>	antispoof_ifspc antispoof_iflst
286%%
287
288ruleset		: /* empty */
289		| ruleset '\n'
290		| ruleset option '\n'
291		| ruleset scrubrule '\n'
292		| ruleset natrule '\n'
293		| ruleset binatrule '\n'
294		| ruleset rdrrule '\n'
295		| ruleset pfrule '\n'
296		| ruleset varset '\n'
297		| ruleset antispoof '\n'
298		| ruleset error '\n'		{ errors++; }
299		;
300
301option		: SET OPTIMIZATION STRING		{
302			if (pf->opts & PF_OPT_VERBOSE)
303				printf("set optimization %s\n", $3);
304			if (check_rulestate(PFCTL_STATE_OPTION))
305				YYERROR;
306			if (pfctl_set_optimization(pf, $3) != 0) {
307				yyerror("unknown optimization %s", $3);
308				YYERROR;
309			}
310		}
311		| SET TIMEOUT timeout_spec
312		| SET TIMEOUT '{' timeout_list '}'
313		| SET LIMIT limit_spec
314		| SET LIMIT '{' limit_list '}'
315		| SET LOGINTERFACE STRING		{
316			if (pf->opts & PF_OPT_VERBOSE)
317				printf("set loginterface %s\n", $3);
318			if (check_rulestate(PFCTL_STATE_OPTION))
319				YYERROR;
320			if (pfctl_set_logif(pf, $3) != 0) {
321				yyerror("error setting loginterface %s", $3);
322				YYERROR;
323			}
324		}
325		;
326
327string		: string STRING				{
328			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
329				yyerror("malloc failed");
330				YYERROR;
331			}
332			free($1);
333			free($2);
334		}
335		| STRING
336		;
337
338varset		: STRING PORTUNARY string		{
339			if (pf->opts & PF_OPT_VERBOSE)
340				printf("%s = %s\n", $1, $3);
341			if (symset($1, $3) == -1) {
342				yyerror("cannot store variable %s", $1);
343				YYERROR;
344			}
345		}
346		;
347
348scrubrule	: SCRUB dir interface fromto nodf minttl maxmss fragcache
349		{
350			struct pf_rule r;
351
352			if (check_rulestate(PFCTL_STATE_SCRUB))
353				YYERROR;
354
355			memset(&r, 0, sizeof(r));
356
357			r.action = PF_SCRUB;
358			r.direction = $2;
359
360			if ($3) {
361				if ($3->not) {
362					yyerror("scrub rules don't support "
363					    "'! <if>'");
364					YYERROR;
365				} else if ($3->next) {
366					yyerror("scrub rules don't support "
367					    "{} expansion");
368					YYERROR;
369				}
370				memcpy(r.ifname, $3->ifname,
371				    sizeof(r.ifname));
372				free($3);
373			}
374			if ($5)
375				r.rule_flag |= PFRULE_NODF;
376			if ($6)
377				r.min_ttl = $6;
378			if ($7)
379				r.max_mss = $7;
380			if ($8)
381				r.rule_flag |= $8;
382
383			r.nr = pf->rule_nr++;
384			if (rule_consistent(&r) < 0)
385				yyerror("skipping scrub rule due to errors");
386			else
387				pfctl_add_rule(pf, &r);
388
389		}
390		;
391
392antispoof	: ANTISPOOF logquick antispoof_ifspc af {
393			struct pf_rule r;
394			struct node_host *h = NULL;
395			struct node_if *i, *j;
396
397			if (check_rulestate(PFCTL_STATE_FILTER))
398				YYERROR;
399
400			for (i = $3; i; i = i->next) {
401				memset(&r, 0, sizeof(r));
402
403				r.action = PF_DROP;
404				r.direction = PF_IN;
405				r.log = $2.log;
406				r.quick = $2.quick;
407				r.af = $4;
408
409				j = calloc(1, sizeof(struct node_if));
410				if (j == NULL)
411					errx(1, "antispoof: calloc");
412				strlcpy(j->ifname, i->ifname, IFNAMSIZ);
413				j->not = 1;
414				h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET);
415
416				expand_rule(&r, j, NULL, h, NULL, NULL, NULL,
417				    NULL, NULL, NULL);
418
419				if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
420					memset(&r, 0, sizeof(r));
421
422					r.action = PF_DROP;
423					r.direction = PF_IN;
424					r.log = $2.log;
425					r.quick = $2.quick;
426					r.af = $4;
427
428					h = ifa_lookup(i->ifname,
429					    PFCTL_IFLOOKUP_HOST);
430
431					expand_rule(&r, NULL, NULL, h, NULL,
432					    NULL, NULL, NULL, NULL, NULL);
433				}
434			}
435		}
436		;
437
438antispoof_ifspc	: FOR if_item			{ $$ = $2; }
439		| FOR '{' antispoof_iflst '}'	{ $$ = $3; }
440		;
441
442antispoof_iflst	: if_item			{ $$ = $1; }
443		| antispoof_iflst comma if_item	{
444			$1->tail->next = $3;
445			$1->tail = $3;
446			$$ = $1;
447		}
448		;
449
450pfrule		: action dir logquick interface route af proto fromto
451		  uids gids flags icmpspec tos keep fragment allowopts label
452		{
453			struct pf_rule r;
454			struct node_state_opt *o;
455			struct node_proto *proto;
456
457			if (check_rulestate(PFCTL_STATE_FILTER))
458				YYERROR;
459
460			memset(&r, 0, sizeof(r));
461
462			r.action = $1.b1;
463			switch ($1.b2) {
464			case PFRULE_RETURNRST:
465				r.rule_flag |= PFRULE_RETURNRST;
466				r.return_ttl = $1.w;
467				break;
468			case PFRULE_RETURNICMP:
469				r.rule_flag |= PFRULE_RETURNICMP;
470				r.return_icmp = $1.w;
471				r.return_icmp6 = $1.w2;
472				break;
473			case PFRULE_RETURN:
474				r.rule_flag |= PFRULE_RETURN;
475				r.return_icmp = $1.w;
476				r.return_icmp6 = $1.w2;
477				break;
478			}
479			r.direction = $2;
480			r.log = $3.log;
481			r.quick = $3.quick;
482
483			r.af = $6;
484			r.flags = $11.b1;
485			r.flagset = $11.b2;
486
487			if ($11.b1 || $11.b2) {
488				for (proto = $7; proto != NULL &&
489				    proto->proto != IPPROTO_TCP;
490				    proto = proto->next)
491					;	/* nothing */
492				if (proto == NULL && $7 != NULL) {
493					yyerror("flags only apply to tcp");
494					YYERROR;
495				}
496			}
497
498			r.tos = $13;
499			r.keep_state = $14.action;
500			o = $14.options;
501			while (o) {
502				struct node_state_opt *p = o;
503
504				switch (o->type) {
505				case PF_STATE_OPT_MAX:
506					if (r.max_states) {
507						yyerror("state option 'max' "
508						    "multiple definitions");
509						YYERROR;
510					}
511					r.max_states = o->data.max_states;
512					break;
513				case PF_STATE_OPT_TIMEOUT:
514					if (r.timeout[o->data.timeout.number]) {
515						yyerror("state timeout %s "
516						    "multiple definitions",
517						    pf_timeouts[o->data.
518						    timeout.number].name);
519						YYERROR;
520					}
521					r.timeout[o->data.timeout.number] =
522					    o->data.timeout.seconds;
523				}
524				o = o->next;
525				free(p);
526			}
527
528			if ($15)
529				r.rule_flag |= PFRULE_FRAGMENT;
530			r.allow_opts = $16;
531
532			if ($5.rt) {
533				r.rt = $5.rt;
534				if ($5.string) {
535					strlcpy(r.rt_ifname, $5.string,
536					    IFNAMSIZ);
537					if (ifa_exists(r.rt_ifname) == NULL) {
538						yyerror("unknown interface %s",
539						    r.rt_ifname);
540						YYERROR;
541					}
542					free($5.string);
543				}
544				if ($5.addr) {
545					if (!r.af)
546						r.af = $5.af;
547					else if (r.af != $5.af) {
548						yyerror("address family"
549						    " mismatch");
550						YYERROR;
551					}
552					memcpy(&r.rt_addr, $5.addr,
553					    sizeof(r.rt_addr));
554					free($5.addr);
555				}
556			}
557
558			if ($17) {
559				if (strlen($17) >= PF_RULE_LABEL_SIZE) {
560					yyerror("rule label too long (max "
561					    "%d chars)", PF_RULE_LABEL_SIZE-1);
562					YYERROR;
563				}
564				strlcpy(r.label, $17, sizeof(r.label));
565				free($17);
566			}
567
568			expand_rule(&r, $4, $7, $8.src.host, $8.src.port,
569			    $8.dst.host, $8.dst.port, $9, $10, $12);
570		}
571		;
572
573action		: PASS			{ $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
574		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
575		;
576
577blockspec	: /* empty */		{ $$.b2 = 0; $$.w = 0; $$.w2 = 0; }
578		| RETURNRST		{
579			$$.b2 = PFRULE_RETURNRST;
580			$$.w = 0;
581			$$.w2 = 0;
582		}
583		| RETURNRST '(' TTL number ')'	{
584			$$.b2 = PFRULE_RETURNRST;
585			$$.w = $4;
586			$$.w2 = 0;
587		}
588		| RETURNICMP		{
589			$$.b2 = PFRULE_RETURNICMP;
590			$$.w = returnicmpdefault;
591			$$.w2 = returnicmp6default;
592		}
593		| RETURNICMP6		{
594			$$.b2 = PFRULE_RETURNICMP;
595			$$.w = returnicmpdefault;
596			$$.w2 = returnicmp6default;
597		}
598		| RETURNICMP '(' STRING ')'	{
599			$$.b2 = PFRULE_RETURNICMP;
600			if (!($$.w = parseicmpspec($3, AF_INET)))
601				YYERROR;
602			$$.w2 = returnicmp6default;
603		}
604		| RETURNICMP6 '(' STRING ')'	{
605			$$.b2 = PFRULE_RETURNICMP;
606			$$.w = returnicmpdefault;
607			if (!($$.w2 = parseicmpspec($3, AF_INET6)))
608				YYERROR;
609		}
610		| RETURNICMP '(' STRING comma STRING ')' {
611			$$.b2 = PFRULE_RETURNICMP;
612			if (!($$.w = parseicmpspec($3, AF_INET)))
613				YYERROR;
614			if (!($$.w2 = parseicmpspec($5, AF_INET6)));
615		}
616		| RETURN {
617			$$.b2 = PFRULE_RETURN;
618			$$.w = returnicmpdefault;
619			$$.w2 = returnicmp6default;
620		}
621		;
622
623fragcache	: /* empty */		{ $$ = 0; }
624		| fragment FRAGNORM	{ $$ = 0; /* default */ }
625		| fragment FRAGCROP	{ $$ = PFRULE_FRAGCROP; }
626		| fragment FRAGDROP	{ $$ = PFRULE_FRAGDROP; }
627		;
628
629
630dir		: IN				{ $$ = PF_IN; }
631		| OUT				{ $$ = PF_OUT; }
632		;
633
634logquick	: /* empty */			{ $$.log = 0; $$.quick = 0; }
635		| log				{ $$.log = $1; $$.quick = 0; }
636		| QUICK				{ $$.log = 0; $$.quick = 1; }
637		| log QUICK			{ $$.log = $1; $$.quick = 1; }
638		| QUICK log			{ $$.log = $2; $$.quick = 1; }
639		;
640
641log		: LOG				{ $$ = 1; }
642		| LOGALL			{ $$ = 2; }
643		;
644
645interface	: /* empty */			{ $$ = NULL; }
646		| ON if_item_not		{ $$ = $2; }
647		| ON '{' if_list '}'		{ $$ = $3; }
648		;
649
650if_list		: if_item_not			{ $$ = $1; }
651		| if_list comma if_item_not	{
652			$1->tail->next = $3;
653			$1->tail = $3;
654			$$ = $1;
655		}
656		;
657
658if_item_not	: '!' if_item			{ $$ = $2; $$->not = 1; }
659		| if_item			{ $$ = $1; }
660
661if_item		: STRING			{
662			struct node_host *n;
663
664			if ((n = ifa_exists($1)) == NULL) {
665				yyerror("unknown interface %s", $1);
666				YYERROR;
667			}
668			$$ = malloc(sizeof(struct node_if));
669			if ($$ == NULL)
670				err(1, "if_item: malloc");
671			strlcpy($$->ifname, $1, IFNAMSIZ);
672			$$->ifa_flags = n->ifa_flags;
673			$$->not = 0;
674			$$->next = NULL;
675			$$->tail = $$;
676		}
677		;
678
679af		: /* empty */			{ $$ = 0; }
680		| INET				{ $$ = AF_INET; }
681		| INET6				{ $$ = AF_INET6; }
682
683proto		: /* empty */			{ $$ = NULL; }
684		| PROTO proto_item		{ $$ = $2; }
685		| PROTO '{' proto_list '}'	{ $$ = $3; }
686		;
687
688proto_list	: proto_item			{ $$ = $1; }
689		| proto_list comma proto_item	{
690			$1->tail->next = $3;
691			$1->tail = $3;
692			$$ = $1;
693		}
694		;
695
696proto_item	: STRING			{
697			struct protoent *p;
698			u_long ulval;
699
700			if (atoul($1, &ulval) == 0)
701				p = getprotobynumber(ulval);
702			else
703				p = getprotobyname($1);
704
705			if (p == NULL) {
706				yyerror("unknown protocol %s", $1);
707				YYERROR;
708			}
709			$$ = malloc(sizeof(struct node_proto));
710			if ($$ == NULL)
711				err(1, "proto_item: malloc");
712			$$->proto = p->p_proto;
713			$$->next = NULL;
714			$$->tail = $$;
715		}
716		;
717
718fromto		: ALL				{
719			$$.src.host = NULL;
720			$$.src.port = NULL;
721			$$.dst.host = NULL;
722			$$.dst.port = NULL;
723		}
724		| FROM ipportspec TO ipportspec	{
725			$$.src = $2;
726			$$.dst = $4;
727		}
728		;
729
730ipportspec	: ipspec			{ $$.host = $1; $$.port = NULL; }
731		| ipspec PORT portspec		{
732			$$.host = $1;
733			$$.port = $3;
734		}
735		;
736
737ipspec		: ANY				{ $$ = NULL; }
738		| xhost				{ $$ = $1; }
739		| '{' host_list '}'		{ $$ = $2; }
740		;
741
742host_list	: xhost				{ $$ = $1; }
743		| host_list comma xhost		{
744			/* $3 may be a list, so use its tail pointer */
745			$1->tail->next = $3->tail;
746			$1->tail = $3->tail;
747			$$ = $1;
748		}
749		;
750
751xhost		: '!' host			{
752			struct node_host *h;
753			for (h = $2; h; h = h->next)
754				h->not = 1;
755			$$ = $2;
756		}
757		| host				{ $$ = $1; }
758		| NOROUTE			{
759			$$ = calloc(1, sizeof(struct node_host));
760			if ($$ == NULL)
761				err(1, "xhost: calloc");
762			$$->noroute = 1;
763			$$->next = NULL;
764			$$->tail = $$;
765		}
766		;
767
768host		: address
769		| address '/' number		{
770			struct node_host *n;
771			for (n = $1; n; n = n->next) {
772				if ($1->af == AF_INET) {
773					if ($3 < 0 || $3 > 32) {
774						yyerror(
775						    "illegal netmask value /%d",
776						    $3);
777						YYERROR;
778					}
779				} else {
780					if ($3 < 0 || $3 > 128) {
781						yyerror(
782						    "illegal netmask value /%d",
783						    $3);
784						YYERROR;
785					}
786				}
787				ipmask(&n->mask, $3);
788			}
789			$$ = $1;
790		}
791		;
792
793number:		STRING
794		{
795			u_long ulval;
796
797			if (atoul($1, &ulval) == -1) {
798				yyerror("%s is not a number", $1);
799				YYERROR;
800			} else
801				$$ = ulval;
802		}
803		;
804
805address		: '(' STRING ')'		{
806			$$ = calloc(1, sizeof(struct node_host));
807			if ($$ == NULL)
808				err(1, "address: calloc");
809			$$->af = 0;
810			ipmask(&$$->mask, 128);
811			$$->addr.addr_dyn = (struct pf_addr_dyn *)1;
812			strncpy($$->addr.addr.pfa.ifname, $2,
813			    sizeof($$->addr.addr.pfa.ifname));
814		}
815		| STRING			{ $$ = host($1); }
816		;
817
818portspec	: port_item			{ $$ = $1; }
819		| '{' port_list '}'		{ $$ = $2; }
820		;
821
822port_list	: port_item			{ $$ = $1; }
823		| port_list comma port_item	{
824			$1->tail->next = $3;
825			$1->tail = $3;
826			$$ = $1;
827		}
828		;
829
830port_item	: port				{
831			$$ = malloc(sizeof(struct node_port));
832			if ($$ == NULL)
833				err(1, "port_item: malloc");
834			$$->port[0] = $1;
835			$$->port[1] = $1;
836			$$->op = PF_OP_EQ;
837			$$->next = NULL;
838			$$->tail = $$;
839		}
840		| PORTUNARY port		{
841			$$ = malloc(sizeof(struct node_port));
842			if ($$ == NULL)
843				err(1, "port_item: malloc");
844			$$->port[0] = $2;
845			$$->port[1] = $2;
846			$$->op = $1;
847			$$->next = NULL;
848			$$->tail = $$;
849		}
850		| port PORTBINARY port		{
851			$$ = malloc(sizeof(struct node_port));
852			if ($$ == NULL)
853				err(1, "port_item: malloc");
854			$$->port[0] = $1;
855			$$->port[1] = $3;
856			$$->op = $2;
857			$$->next = NULL;
858			$$->tail = $$;
859		}
860		;
861
862port		: STRING			{
863			struct servent *s = NULL;
864			u_long ulval;
865
866			if (atoul($1, &ulval) == 0) {
867				if (ulval < 0 || ulval > 65535) {
868					yyerror("illegal port value %d", ulval);
869					YYERROR;
870				}
871				$$ = htons(ulval);
872			} else {
873				s = getservbyname($1, "tcp");
874				if (s == NULL)
875					s = getservbyname($1, "udp");
876				if (s == NULL) {
877					yyerror("unknown port %s", $1);
878					YYERROR;
879				}
880				$$ = s->s_port;
881			}
882		}
883		;
884
885uids		: /* empty */			{ $$ = NULL; }
886		| USER uid_item			{ $$ = $2; }
887		| USER '{' uid_list '}'		{ $$ = $3; }
888		;
889
890uid_list	: uid_item			{ $$ = $1; }
891		| uid_list comma uid_item	{
892			$1->tail->next = $3;
893			$1->tail = $3;
894			$$ = $1;
895		}
896		;
897
898uid_item	: uid				{
899			$$ = malloc(sizeof(struct node_uid));
900			if ($$ == NULL)
901				err(1, "uid_item: malloc");
902			$$->uid[0] = $1;
903			$$->uid[1] = $1;
904			$$->op = PF_OP_EQ;
905			$$->next = NULL;
906			$$->tail = $$;
907		}
908		| PORTUNARY uid			{
909			if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
910				yyerror("user unknown requires operator = or !=");
911				YYERROR;
912			}
913			$$ = malloc(sizeof(struct node_uid));
914			if ($$ == NULL)
915				err(1, "uid_item: malloc");
916			$$->uid[0] = $2;
917			$$->uid[1] = $2;
918			$$->op = $1;
919			$$->next = NULL;
920			$$->tail = $$;
921		}
922		| uid PORTBINARY uid		{
923			if ($1 == UID_MAX || $3 == UID_MAX) {
924				yyerror("user unknown requires operator = or !=");
925				YYERROR;
926			}
927			$$ = malloc(sizeof(struct node_uid));
928			if ($$ == NULL)
929				err(1, "uid_item: malloc");
930			$$->uid[0] = $1;
931			$$->uid[1] = $3;
932			$$->op = $2;
933			$$->next = NULL;
934			$$->tail = $$;
935		}
936		;
937
938uid		: STRING			{
939			u_long ulval;
940
941			if (atoul($1, &ulval) == -1) {
942				if (!strcmp($1, "unknown"))
943					$$ = UID_MAX;
944				else {
945					struct passwd *pw;
946
947					if ((pw = getpwnam($1)) == NULL) {
948						yyerror("unknown user %s", $1);
949						YYERROR;
950					}
951					$$ = pw->pw_uid;
952				}
953			} else {
954				if (ulval < 0 || ulval >= UID_MAX) {
955					yyerror("illegal uid value %ul", ulval);
956					YYERROR;
957				}
958				$$ = ulval;
959			}
960		}
961		;
962
963gids		: /* empty */			{ $$ = NULL; }
964		| GROUP gid_item		{ $$ = $2; }
965		| GROUP '{' gid_list '}'	{ $$ = $3; }
966		;
967
968gid_list	: gid_item			{ $$ = $1; }
969		| gid_list comma gid_item	{
970			$1->tail->next = $3;
971			$1->tail = $3;
972			$$ = $1;
973		}
974		;
975
976gid_item	: gid				{
977			$$ = malloc(sizeof(struct node_gid));
978			if ($$ == NULL)
979				err(1, "gid_item: malloc");
980			$$->gid[0] = $1;
981			$$->gid[1] = $1;
982			$$->op = PF_OP_EQ;
983			$$->next = NULL;
984			$$->tail = $$;
985		}
986		| PORTUNARY gid			{
987			if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
988				yyerror("group unknown requires operator = or !=");
989				YYERROR;
990			}
991			$$ = malloc(sizeof(struct node_gid));
992			if ($$ == NULL)
993				err(1, "gid_item: malloc");
994			$$->gid[0] = $2;
995			$$->gid[1] = $2;
996			$$->op = $1;
997			$$->next = NULL;
998			$$->tail = $$;
999		}
1000		| gid PORTBINARY gid		{
1001			if ($1 == GID_MAX || $3 == GID_MAX) {
1002				yyerror("group unknown requires operator = or !=");
1003				YYERROR;
1004			}
1005			$$ = malloc(sizeof(struct node_gid));
1006			if ($$ == NULL)
1007				err(1, "gid_item: malloc");
1008			$$->gid[0] = $1;
1009			$$->gid[1] = $3;
1010			$$->op = $2;
1011			$$->next = NULL;
1012			$$->tail = $$;
1013		}
1014		;
1015
1016gid		: STRING			{
1017			u_long ulval;
1018
1019			if (atoul($1, &ulval) == -1) {
1020				if (!strcmp($1, "unknown"))
1021					$$ = GID_MAX;
1022				else {
1023					struct group *grp;
1024
1025					if ((grp = getgrnam($1)) == NULL) {
1026						yyerror("unknown group %s", $1);
1027						YYERROR;
1028					}
1029					$$ = grp->gr_gid;
1030				}
1031			} else {
1032				if (ulval < 0 || ulval >= GID_MAX) {
1033					yyerror("illegal gid value %ul", ulval);
1034					YYERROR;
1035				}
1036				$$ = ulval;
1037			}
1038		}
1039		;
1040
1041flag		: STRING			{
1042			int f;
1043
1044			if ((f = parse_flags($1)) < 0) {
1045				yyerror("bad flags %s", $1);
1046				YYERROR;
1047			}
1048			$$.b1 = f;
1049		}
1050		;
1051
1052flags		: /* empty */			{ $$.b1 = 0; $$.b2 = 0; }
1053		| FLAGS flag			{ $$.b1 = $2.b1; $$.b2 = PF_TH_ALL; }
1054		| FLAGS flag "/" flag		{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
1055		| FLAGS "/" flag		{ $$.b1 = 0; $$.b2 = $3.b1; }
1056		;
1057
1058icmpspec	: /* empty */			{ $$ = NULL; }
1059		| ICMPTYPE icmp_item		{ $$ = $2; }
1060		| ICMPTYPE '{' icmp_list '}'	{ $$ = $3; }
1061		| ICMP6TYPE icmp6_item		{ $$ = $2; }
1062		| ICMP6TYPE '{' icmp6_list '}'	{ $$ = $3; }
1063		;
1064
1065icmp_list	: icmp_item			{ $$ = $1; }
1066		| icmp_list comma icmp_item	{
1067			$1->tail->next = $3;
1068			$1->tail = $3;
1069			$$ = $1;
1070		}
1071		;
1072
1073icmp6_list	: icmp6_item			{ $$ = $1; }
1074		| icmp6_list comma icmp6_item	{
1075			$1->tail->next = $3;
1076			$1->tail = $3;
1077			$$ = $1;
1078		}
1079		;
1080
1081icmp_item	: icmptype		{
1082			$$ = malloc(sizeof(struct node_icmp));
1083			if ($$ == NULL)
1084				err(1, "icmp_item: malloc");
1085			$$->type = $1;
1086			$$->code = 0;
1087			$$->proto = IPPROTO_ICMP;
1088			$$->next = NULL;
1089			$$->tail = $$;
1090		}
1091		| icmptype CODE STRING	{
1092			const struct icmpcodeent *p;
1093			u_long ulval;
1094
1095			if (atoul($3, &ulval) == 0) {
1096				if (ulval < 0 || ulval > 255) {
1097					yyerror("illegal icmp-code %d", ulval);
1098					YYERROR;
1099				}
1100			} else {
1101				if ((p = geticmpcodebyname($1, $3,
1102				    AF_INET)) == NULL) {
1103					yyerror("unknown icmp-code %s", $3);
1104					YYERROR;
1105				}
1106				ulval = p->code;
1107			}
1108			$$ = malloc(sizeof(struct node_icmp));
1109			if ($$ == NULL)
1110				err(1, "icmp_item: malloc");
1111			$$->type = $1;
1112			$$->code = ulval + 1;
1113			$$->proto = IPPROTO_ICMP;
1114			$$->next = NULL;
1115			$$->tail = $$;
1116		}
1117		;
1118
1119icmp6_item	: icmp6type		{
1120			$$ = malloc(sizeof(struct node_icmp));
1121			if ($$ == NULL)
1122				err(1, "icmp_item: malloc");
1123			$$->type = $1;
1124			$$->code = 0;
1125			$$->proto = IPPROTO_ICMPV6;
1126			$$->next = NULL;
1127			$$->tail = $$;
1128		}
1129		| icmp6type CODE STRING	{
1130			const struct icmpcodeent *p;
1131			u_long ulval;
1132
1133			if (atoul($3, &ulval) == 0) {
1134				if (ulval < 0 || ulval > 255) {
1135					yyerror("illegal icmp6-code %ld", ulval);
1136					YYERROR;
1137				}
1138			} else {
1139				if ((p = geticmpcodebyname($1, $3,
1140				    AF_INET6)) == NULL) {
1141					yyerror("unknown icmp6-code %s", $3);
1142					YYERROR;
1143				}
1144				ulval = p->code;
1145			}
1146			$$ = malloc(sizeof(struct node_icmp));
1147			if ($$ == NULL)
1148				err(1, "icmp_item: malloc");
1149			$$->type = $1;
1150			$$->code = ulval + 1;
1151			$$->proto = IPPROTO_ICMPV6;
1152			$$->next = NULL;
1153			$$->tail = $$;
1154		}
1155		;
1156
1157icmptype	: STRING			{
1158			const struct icmptypeent *p;
1159			u_long ulval;
1160
1161			if (atoul($1, &ulval) == 0) {
1162				if (ulval < 0 || ulval > 255) {
1163					yyerror("illegal icmp-type %d", ulval);
1164					YYERROR;
1165				}
1166				$$ = ulval + 1;
1167			} else {
1168				if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
1169					yyerror("unknown icmp-type %s", $1);
1170					YYERROR;
1171				}
1172				$$ = p->type + 1;
1173			}
1174		}
1175		;
1176
1177icmp6type	: STRING			{
1178			const struct icmptypeent *p;
1179			u_long ulval;
1180
1181			if (atoul($1, &ulval) == 0) {
1182				if (ulval < 0 || ulval > 255) {
1183					yyerror("illegal icmp6-type %d", ulval);
1184					YYERROR;
1185				}
1186				$$ = ulval + 1;
1187			} else {
1188				if ((p = geticmptypebyname($1, AF_INET6)) == NULL) {
1189					yyerror("unknown ipv6-icmp-type %s", $1);
1190					YYERROR;
1191				}
1192				$$ = p->type + 1;
1193			}
1194		}
1195		;
1196
1197tos		: /* empty */			{ $$ = 0; }
1198		| TOS STRING			{
1199			if (!strcmp($2, "lowdelay"))
1200				$$ = IPTOS_LOWDELAY;
1201			else if (!strcmp($2, "throughput"))
1202				$$ = IPTOS_THROUGHPUT;
1203			else if (!strcmp($2, "reliability"))
1204				$$ = IPTOS_RELIABILITY;
1205			else if ($2[0] == '0' && $2[1] == 'x')
1206				$$ = strtoul($2, NULL, 16);
1207			else
1208				$$ = strtoul($2, NULL, 10);
1209			if (!$$ || $$ > 255) {
1210				yyerror("illegal tos value %s", $2);
1211				YYERROR;
1212			}
1213		}
1214		;
1215
1216keep		: /* empty */			{
1217			$$.action = 0;
1218			$$.options = NULL;
1219		}
1220		| KEEP STATE state_opt_spec	{
1221			$$.action = PF_STATE_NORMAL;
1222			$$.options = $3;
1223		}
1224		| MODULATE STATE state_opt_spec	{
1225			$$.action = PF_STATE_MODULATE;
1226			$$.options = $3;
1227		}
1228		;
1229
1230state_opt_spec	: /* empty */			{ $$ = NULL; }
1231		| '(' state_opt_list ')'	{ $$ = $2; }
1232		;
1233
1234state_opt_list	: state_opt_item		{ $$ = $1; }
1235		| state_opt_list comma state_opt_item {
1236			$1->tail->next = $3;
1237			$1->tail = $3;
1238			$$ = $1;
1239		}
1240		;
1241
1242state_opt_item	: MAXIMUM number		{
1243			if ($2 <= 0) {
1244				yyerror("illegal states max value %d", $2);
1245				YYERROR;
1246			}
1247			$$ = calloc(1, sizeof(struct node_state_opt));
1248			if ($$ == NULL)
1249				err(1, "state_opt_item: calloc");
1250			$$->type = PF_STATE_OPT_MAX;
1251			$$->data.max_states = $2;
1252			$$->next = NULL;
1253			$$->tail = $$;
1254		}
1255		| STRING number			{
1256			int i;
1257
1258			for (i = 0; pf_timeouts[i].name &&
1259			    strcmp(pf_timeouts[i].name, $1); ++i);
1260			if (!pf_timeouts[i].name) {
1261				yyerror("illegal timeout name %s", $1);
1262				YYERROR;
1263			}
1264			if (strchr(pf_timeouts[i].name, '.') == NULL) {
1265				yyerror("illegal state timeout %s", $1);
1266				YYERROR;
1267			}
1268			if ($2 < 0) {
1269				yyerror("illegal timeout value %d", $2);
1270				YYERROR;
1271			}
1272			$$ = calloc(1, sizeof(struct node_state_opt));
1273			if ($$ == NULL)
1274				err(1, "state_opt_item: calloc");
1275			$$->type = PF_STATE_OPT_TIMEOUT;
1276			$$->data.timeout.number = pf_timeouts[i].timeout;
1277			$$->data.timeout.seconds = $2;
1278			$$->next = NULL;
1279			$$->tail = $$;
1280		}
1281		;
1282
1283fragment	: /* empty */			{ $$ = 0; }
1284		| FRAGMENT			{ $$ = 1; }
1285
1286minttl		: /* empty */			{ $$ = 0; }
1287		| MINTTL number			{
1288			if ($2 < 0 || $2 > 255) {
1289				yyerror("illegal min-ttl value %d", $2);
1290				YYERROR;
1291			}
1292			$$ = $2;
1293		}
1294		;
1295
1296nodf		: /* empty */			{ $$ = 0; }
1297		| NODF				{ $$ = 1; }
1298		;
1299
1300maxmss		: /* empty */			{ $$ = 0; }
1301		| MAXMSS number			{
1302			if ($2 < 0) {
1303				yyerror("illegal max-mss value %d", $2);
1304				YYERROR;
1305			}
1306			$$ = $2;
1307		}
1308		;
1309
1310allowopts	: /* empty */			{ $$ = 0; }
1311		| ALLOWOPTS			{ $$ = 1; }
1312
1313label		: /* empty */			{ $$ = NULL; }
1314		| LABEL STRING			{
1315			if (($$ = strdup($2)) == NULL) {
1316				yyerror("rule label strdup() failed");
1317				YYERROR;
1318			}
1319		}
1320		;
1321
1322no		: /* empty */			{ $$ = 0; }
1323		| NO				{ $$ = 1; }
1324		;
1325
1326rport		: STRING			{
1327			char *p = strchr($1, ':');
1328
1329			if (p == NULL) {
1330				if (($$.a = getservice($1)) == -1)
1331					YYERROR;
1332				$$.b = $$.t = 0;
1333			} else if (!strcmp(p+1, "*")) {
1334				*p = 0;
1335				if (($$.a = getservice($1)) == -1)
1336					YYERROR;
1337				$$.b = 0;
1338				$$.t = PF_RPORT_RANGE;
1339			} else {
1340				*p++ = 0;
1341				if (($$.a = getservice($1)) == -1 ||
1342				    ($$.b = getservice(p)) == -1)
1343					YYERROR;
1344				$$.t = PF_RPORT_RANGE;
1345			}
1346		}
1347		;
1348
1349redirection	: /* empty */			{ $$ = NULL; }
1350		| ARROW address			{
1351			$$ = malloc(sizeof(struct redirection));
1352			if ($$ == NULL)
1353				err(1, "redirection: malloc");
1354			$$->address = $2;
1355			$$->rport.a = $$->rport.b = $$->rport.t = 0;
1356		}
1357		| ARROW address PORT rport	{
1358			$$ = malloc(sizeof(struct redirection));
1359			if ($$ == NULL)
1360				err(1, "redirection: malloc");
1361			$$->address = $2;
1362			$$->rport = $4;
1363		}
1364		;
1365
1366natrule		: no NAT interface af proto fromto redirection
1367		{
1368			struct pf_nat nat;
1369
1370			if (check_rulestate(PFCTL_STATE_NAT))
1371				YYERROR;
1372
1373			memset(&nat, 0, sizeof(nat));
1374
1375			nat.no = $1;
1376			nat.af = $4;
1377
1378			if (!nat.af) {
1379				if ($6.src.host && $6.src.host->af
1380				    && !$6.src.host->ifindex)
1381					nat.af = $6.src.host->af;
1382				else if ($6.dst.host && $6.dst.host->af
1383				    && !$6.dst.host->ifindex)
1384					nat.af = $6.dst.host->af;
1385			}
1386
1387			if (nat.no) {
1388				if ($7 != NULL) {
1389					yyerror("'no nat' rule does not need "
1390					    "'->'");
1391					YYERROR;
1392				}
1393			} else {
1394				struct node_host *n;
1395
1396				if ($7 == NULL || $7->address == NULL) {
1397					yyerror("'nat' rule requires '-> "
1398					    "address'");
1399					YYERROR;
1400				}
1401				if (!nat.af && !$7->address->ifindex)
1402					nat.af = $7->address->af;
1403				n = ifa_pick_ip($7->address, nat.af);
1404				if (n == NULL)
1405					YYERROR;
1406				if (!nat.af)
1407					nat.af = n->af;
1408				memcpy(&nat.raddr, &n->addr,
1409				    sizeof(nat.raddr));
1410				nat.proxy_port[0] = ntohs($7->rport.a);
1411				nat.proxy_port[1] = ntohs($7->rport.b);
1412				if (!nat.proxy_port[0] && !nat.proxy_port[1]) {
1413					nat.proxy_port[0] =
1414					    PF_NAT_PROXY_PORT_LOW;
1415					nat.proxy_port[1] =
1416					    PF_NAT_PROXY_PORT_HIGH;
1417				} else if (!nat.proxy_port[1])
1418					nat.proxy_port[1] = nat.proxy_port[0];
1419				free($7->address);
1420				free($7);
1421			}
1422
1423			expand_nat(&nat, $3, $5, $6.src.host, $6.src.port,
1424			    $6.dst.host, $6.dst.port);
1425		}
1426		;
1427
1428binatrule	: no BINAT interface af proto FROM address TO ipspec redirection
1429		{
1430			struct pf_binat binat;
1431
1432			if (check_rulestate(PFCTL_STATE_NAT))
1433				YYERROR;
1434
1435			memset(&binat, 0, sizeof(binat));
1436
1437			binat.no = $1;
1438			if ($3 != NULL) {
1439				memcpy(binat.ifname, $3->ifname,
1440				    sizeof(binat.ifname));
1441				free($3);
1442			}
1443			binat.af = $4;
1444			if ($5 != NULL) {
1445				binat.proto = $5->proto;
1446				free($5);
1447			}
1448			if ($7 != NULL && $9 != NULL && $7->af != $9->af) {
1449				yyerror("binat ip versions must match");
1450				YYERROR;
1451			}
1452			if ($7 != NULL) {
1453				if ($7->next) {
1454					yyerror("multiple binat ip addresses");
1455					YYERROR;
1456				}
1457				if ($7->addr.addr_dyn != NULL) {
1458					if (!binat.af) {
1459						yyerror("address family (inet/"
1460						    "inet6) undefined");
1461						YYERROR;
1462					}
1463					$7->af = binat.af;
1464				}
1465				if (binat.af && $7->af != binat.af) {
1466					yyerror("binat ip versions must match");
1467					YYERROR;
1468				}
1469				binat.af = $7->af;
1470				memcpy(&binat.saddr, &$7->addr,
1471				    sizeof(binat.saddr));
1472				free($7);
1473			}
1474			if ($9 != NULL) {
1475				if ($9->next) {
1476					yyerror("multiple binat ip addresses");
1477					YYERROR;
1478				}
1479				if ($9->addr.addr_dyn != NULL) {
1480					if (!binat.af) {
1481						yyerror("address family (inet/"
1482						    "inet6) undefined");
1483						YYERROR;
1484					}
1485					$9->af = binat.af;
1486				}
1487				if (binat.af && $9->af != binat.af) {
1488					yyerror("binat ip versions must match");
1489					YYERROR;
1490				}
1491				binat.af = $9->af;
1492				memcpy(&binat.daddr, &$9->addr,
1493				    sizeof(binat.daddr));
1494				memcpy(&binat.dmask, &$9->mask,
1495				    sizeof(binat.dmask));
1496				binat.dnot  = $9->not;
1497				free($9);
1498			}
1499
1500			if (binat.no) {
1501				if ($10 != NULL) {
1502					yyerror("'no binat' rule does not need"
1503					    " '->'");
1504					YYERROR;
1505				}
1506			} else {
1507				struct node_host *n;
1508
1509				if ($10 == NULL || $10->address == NULL) {
1510					yyerror("'binat' rule requires"
1511					    " '-> address'");
1512					YYERROR;
1513				}
1514				n = ifa_pick_ip($10->address, binat.af);
1515				if (n == NULL)
1516					YYERROR;
1517				if (n->addr.addr_dyn != NULL) {
1518					if (!binat.af) {
1519						yyerror("address family (inet/"
1520						    "inet6) undefined");
1521						YYERROR;
1522					}
1523					n->af = binat.af;
1524				}
1525				if (binat.af && n->af != binat.af) {
1526					yyerror("binat ip versions must match");
1527					YYERROR;
1528				}
1529				binat.af = n->af;
1530				memcpy(&binat.raddr, &n->addr,
1531				    sizeof(binat.raddr));
1532				free($10->address);
1533				free($10);
1534			}
1535
1536			pfctl_add_binat(pf, &binat);
1537		}
1538
1539rdrrule		: no RDR interface af proto FROM ipspec TO ipspec dport redirection
1540		{
1541			struct pf_rdr rdr;
1542
1543			if (check_rulestate(PFCTL_STATE_NAT))
1544				YYERROR;
1545
1546			memset(&rdr, 0, sizeof(rdr));
1547
1548			rdr.no = $1;
1549			rdr.af = $4;
1550			if ($7 != NULL) {
1551				memcpy(&rdr.saddr, &$7->addr,
1552				    sizeof(rdr.saddr));
1553				memcpy(&rdr.smask, &$7->mask,
1554				    sizeof(rdr.smask));
1555				rdr.snot  = $7->not;
1556				if (!rdr.af && !$7->ifindex)
1557					rdr.af = $7->af;
1558			}
1559			if ($9 != NULL) {
1560				memcpy(&rdr.daddr, &$9->addr,
1561				    sizeof(rdr.daddr));
1562				memcpy(&rdr.dmask, &$9->mask,
1563				    sizeof(rdr.dmask));
1564				rdr.dnot  = $9->not;
1565				if (!rdr.af && !$9->ifindex)
1566					rdr.af = $9->af;
1567			}
1568
1569			rdr.dport  = $10.a;
1570			rdr.dport2 = $10.b;
1571			rdr.opts  |= $10.t;
1572
1573			if (rdr.no) {
1574				if ($11 != NULL) {
1575					yyerror("'no rdr' rule does not need '->'");
1576					YYERROR;
1577				}
1578			} else {
1579				struct node_host *n;
1580
1581				if ($11 == NULL || $11->address == NULL) {
1582					yyerror("'rdr' rule requires '-> "
1583					    "address'");
1584					YYERROR;
1585				}
1586				if (!rdr.af && !$11->address->ifindex)
1587					rdr.af = $11->address->af;
1588				n = ifa_pick_ip($11->address, rdr.af);
1589				if (n == NULL)
1590					YYERROR;
1591				if (!rdr.af)
1592					rdr.af = n->af;
1593				memcpy(&rdr.raddr, &n->addr,
1594				    sizeof(rdr.raddr));
1595				free($11->address);
1596				rdr.rport  = $11->rport.a;
1597				rdr.opts  |= $11->rport.t;
1598				free($11);
1599			}
1600
1601			expand_rdr(&rdr, $3, $5, $7, $9);
1602		}
1603		;
1604
1605dport		: /* empty */			{
1606			$$.a = $$.b = $$.t = 0;
1607		}
1608		| PORT STRING			{
1609			char *p = strchr($2, ':');
1610
1611			if (p == NULL) {
1612				if (($$.a = getservice($2)) == -1)
1613					YYERROR;
1614				$$.b = $$.t = 0;
1615			} else {
1616				*p++ = 0;
1617				if (($$.a = getservice($2)) == -1 ||
1618				    ($$.b = getservice(p)) == -1)
1619					YYERROR;
1620				$$.t = PF_DPORT_RANGE;
1621			}
1622		}
1623		;
1624
1625route		: /* empty */			{
1626			$$.string = NULL;
1627			$$.rt = 0;
1628			$$.addr = NULL;
1629			$$.af = 0;
1630		}
1631		| FASTROUTE {
1632			$$.string = NULL;
1633			$$.rt = PF_FASTROUTE;
1634			$$.addr = NULL;
1635		}
1636		| ROUTETO '(' STRING address ')' {
1637			if (($$.string = strdup($3)) == NULL) {
1638				yyerror("routeto: strdup");
1639				YYERROR;
1640			}
1641			$$.rt = PF_ROUTETO;
1642			if ($4->addr.addr_dyn != NULL) {
1643				yyerror("route-to does not support"
1644				    " dynamic addresses");
1645				YYERROR;
1646			}
1647			if ($4->next) {
1648				yyerror("multiple route-to ip addresses");
1649				YYERROR;
1650			}
1651			$$.addr = &$4->addr.addr;
1652			$$.af = $4->af;
1653		}
1654		| ROUTETO STRING {
1655			if (($$.string = strdup($2)) == NULL) {
1656				yyerror("routeto: strdup");
1657				YYERROR;
1658			}
1659			$$.rt = PF_ROUTETO;
1660			$$.addr = NULL;
1661		}
1662		| REPLYTO '(' STRING address ')' {
1663			if (($$.string = strdup($3)) == NULL) {
1664				yyerror("reply-to: strdup");
1665				YYERROR;
1666			}
1667			$$.rt = PF_REPLYTO;
1668			if ($4->addr.addr_dyn != NULL) {
1669				yyerror("reply-to does not support"
1670				    " dynamic addresses");
1671				YYERROR;
1672			}
1673			if ($4->next) {
1674				yyerror("multiple reply-to ip addresses");
1675				YYERROR;
1676			}
1677			$$.addr = &$4->addr.addr;
1678			$$.af = $4->af;
1679		}
1680		| REPLYTO STRING {
1681			if (($$.string = strdup($2)) == NULL) {
1682				yyerror("reply-to: strdup");
1683				YYERROR;
1684			}
1685			$$.rt = PF_REPLYTO;
1686			$$.addr = NULL;
1687		}
1688		| DUPTO '(' STRING address ')' {
1689			if (($$.string = strdup($3)) == NULL) {
1690				yyerror("dupto: strdup");
1691				YYERROR;
1692			}
1693			$$.rt = PF_DUPTO;
1694			if ($4->addr.addr_dyn != NULL) {
1695				yyerror("dup-to does not support"
1696				    " dynamic addresses");
1697				YYERROR;
1698			}
1699			if ($4->next) {
1700				yyerror("multiple dup-to ip addresses");
1701				YYERROR;
1702			}
1703			$$.addr = &$4->addr.addr;
1704			$$.af = $4->af;
1705		}
1706		| DUPTO STRING {
1707			if (($$.string = strdup($2)) == NULL) {
1708				yyerror("dupto: strdup");
1709				YYERROR;
1710			}
1711			$$.rt = PF_DUPTO;
1712			$$.addr = NULL;
1713		}
1714		;
1715
1716timeout_spec	: STRING number
1717		{
1718			if (pf->opts & PF_OPT_VERBOSE)
1719				printf("set timeout %s %us\n", $1, $2);
1720			if (check_rulestate(PFCTL_STATE_OPTION))
1721				YYERROR;
1722			if (pfctl_set_timeout(pf, $1, $2) != 0) {
1723				yyerror("unknown timeout %s", $1);
1724				YYERROR;
1725			}
1726		}
1727		;
1728
1729timeout_list	: timeout_list comma timeout_spec
1730		| timeout_spec
1731		;
1732
1733limit_spec	: STRING number
1734		{
1735			if (pf->opts & PF_OPT_VERBOSE)
1736				printf("set limit %s %u\n", $1, $2);
1737			if (check_rulestate(PFCTL_STATE_OPTION))
1738				YYERROR;
1739			if (pfctl_set_limit(pf, $1, $2) != 0) {
1740				yyerror("unable to set limit %s %u", $1, $2);
1741				YYERROR;
1742			}
1743		}
1744
1745limit_list	: limit_list comma limit_spec
1746		| limit_spec
1747		;
1748
1749comma		: ','
1750		| /* empty */
1751		;
1752
1753%%
1754
1755int
1756yyerror(char *fmt, ...)
1757{
1758	va_list ap;
1759	extern char *infile;
1760	errors = 1;
1761
1762	va_start(ap, fmt);
1763	fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
1764	vfprintf(stderr, fmt, ap);
1765	fprintf(stderr, "\n");
1766	va_end(ap);
1767	return (0);
1768}
1769
1770int
1771rule_consistent(struct pf_rule *r)
1772{
1773	int problems = 0;
1774
1775	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
1776	    (r->src.port_op || r->dst.port_op)) {
1777		yyerror("port only applies to tcp/udp");
1778		problems++;
1779	}
1780	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
1781	    (r->type || r->code)) {
1782		yyerror("icmp-type/code only applies to icmp");
1783		problems++;
1784	}
1785	if (!r->af && (r->type || r->code)) {
1786		yyerror("must indicate address family with icmp-type/code");
1787		problems++;
1788	}
1789	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
1790	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
1791		yyerror("icmp version does not match address family");
1792		problems++;
1793	}
1794	if (r->keep_state == PF_STATE_MODULATE && r->proto &&
1795	    r->proto != IPPROTO_TCP) {
1796		yyerror("modulate state can only be applied to TCP rules");
1797		problems++;
1798	}
1799	if (r->allow_opts && r->action != PF_PASS) {
1800		yyerror("allow-opts can only be specified for pass rules");
1801		problems++;
1802	}
1803	if (!r->af && (r->src.addr.addr_dyn != NULL ||
1804	    r->dst.addr.addr_dyn != NULL)) {
1805		yyerror("dynamic addresses require address family (inet/inet6)");
1806		problems++;
1807	}
1808	if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
1809	    r->dst.port_op || r->flagset || r->type || r->code)) {
1810		yyerror("fragments can be filtered only on IP header fields");
1811		problems++;
1812	}
1813	if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
1814		yyerror("return-rst can only be applied to TCP rules");
1815		problems++;
1816	}
1817	if (r->action == PF_DROP && r->keep_state) {
1818		yyerror("keep state on block rules doesn't make sense");
1819		problems++;
1820	}
1821	return (-problems);
1822}
1823
1824int
1825nat_consistent(struct pf_nat *r)
1826{
1827	int problems = 0;
1828
1829	if (!r->af && (r->raddr.addr_dyn != NULL)) {
1830		yyerror("dynamic addresses require address family (inet/inet6)");
1831		problems++;
1832	}
1833	return (-problems);
1834}
1835
1836int
1837rdr_consistent(struct pf_rdr *r)
1838{
1839	int problems = 0;
1840
1841	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
1842	    (r->dport || r->dport2 || r->rport)) {
1843		yyerror("port only applies to tcp/udp");
1844		problems++;
1845	}
1846	if (!r->af && (r->saddr.addr_dyn != NULL ||
1847	    r->daddr.addr_dyn != NULL || r->raddr.addr_dyn != NULL)) {
1848		yyerror("dynamic addresses require address family (inet/inet6)");
1849		problems++;
1850	}
1851	return (-problems);
1852}
1853
1854struct keywords {
1855	const char	*k_name;
1856	int	 k_val;
1857};
1858
1859/* macro gore, but you should've seen the prior indentation nightmare... */
1860
1861#define FREE_LIST(T,r) \
1862	do { \
1863		T *p, *n = r; \
1864		while (n != NULL) { \
1865			p = n; \
1866			n = n->next; \
1867			free(p); \
1868		} \
1869	} while (0)
1870
1871#define LOOP_THROUGH(T,n,r,C) \
1872	do { \
1873		T *n; \
1874		if (r == NULL) { \
1875			r = calloc(1, sizeof(T)); \
1876			if (r == NULL) \
1877				err(1, "LOOP: calloc"); \
1878			r->next = NULL; \
1879		} \
1880		n = r; \
1881		while (n != NULL) { \
1882			do { \
1883				C; \
1884			} while (0); \
1885			n = n->next; \
1886		} \
1887	} while (0)
1888
1889void
1890expand_label_addr(const char *name, char *label, u_int8_t af,
1891    struct node_host *host)
1892{
1893	char tmp[PF_RULE_LABEL_SIZE];
1894	char *p;
1895
1896	while ((p = strstr(label, name)) != NULL) {
1897		tmp[0] = 0;
1898
1899		strlcat(tmp, label, p-label+1);
1900
1901		if (host->not)
1902			strlcat(tmp, "! ", PF_RULE_LABEL_SIZE);
1903		if (host->addr.addr_dyn != NULL) {
1904			strlcat(tmp, "(", PF_RULE_LABEL_SIZE);
1905			strlcat(tmp, host->addr.addr.pfa.ifname,
1906			    PF_RULE_LABEL_SIZE);
1907			strlcat(tmp, ")", PF_RULE_LABEL_SIZE);
1908		} else if (!af || (PF_AZERO(&host->addr.addr, af) &&
1909		    PF_AZERO(&host->mask, af)))
1910			strlcat(tmp, "any", PF_RULE_LABEL_SIZE);
1911		else {
1912			char a[48];
1913			int bits;
1914
1915			if (inet_ntop(af, &host->addr.addr, a,
1916			    sizeof(a)) == NULL)
1917				strlcat(a, "?", sizeof(a));
1918			strlcat(tmp, a, PF_RULE_LABEL_SIZE);
1919			bits = unmask(&host->mask, af);
1920			a[0] = 0;
1921			if ((af == AF_INET && bits < 32) ||
1922			    (af == AF_INET6 && bits < 128))
1923				snprintf(a, sizeof(a), "/%u", bits);
1924			strlcat(tmp, a, PF_RULE_LABEL_SIZE);
1925		}
1926		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
1927		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
1928	}
1929}
1930
1931void
1932expand_label_port(const char *name, char *label, struct node_port *port)
1933{
1934	char tmp[PF_RULE_LABEL_SIZE];
1935	char *p;
1936	char a1[6], a2[6], op[13];
1937
1938	while ((p = strstr(label, name)) != NULL) {
1939		tmp[0] = 0;
1940
1941		strlcat(tmp, label, p-label+1);
1942
1943		snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
1944		snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
1945		if (!port->op)
1946			op[0] = 0;
1947		else if (port->op == PF_OP_IRG)
1948			snprintf(op, sizeof(op), "%s><%s", a1, a2);
1949		else if (port->op == PF_OP_XRG)
1950			snprintf(op, sizeof(op), "%s<>%s", a1, a2);
1951		else if (port->op == PF_OP_EQ)
1952			snprintf(op, sizeof(op), "%s", a1);
1953		else if (port->op == PF_OP_NE)
1954			snprintf(op, sizeof(op), "!=%s", a1);
1955		else if (port->op == PF_OP_LT)
1956			snprintf(op, sizeof(op), "<%s", a1);
1957		else if (port->op == PF_OP_LE)
1958			snprintf(op, sizeof(op), "<=%s", a1);
1959		else if (port->op == PF_OP_GT)
1960			snprintf(op, sizeof(op), ">%s", a1);
1961		else if (port->op == PF_OP_GE)
1962			snprintf(op, sizeof(op), ">=%s", a1);
1963		strlcat(tmp, op, PF_RULE_LABEL_SIZE);
1964		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
1965		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
1966	}
1967}
1968
1969void
1970expand_label_proto(const char *name, char *label, u_int8_t proto)
1971{
1972	char tmp[PF_RULE_LABEL_SIZE];
1973	char *p;
1974	struct protoent *pe;
1975
1976	while ((p = strstr(label, name)) != NULL) {
1977		tmp[0] = 0;
1978		strlcat(tmp, label, p-label+1);
1979		pe = getprotobynumber(proto);
1980		if (pe != NULL)
1981		    strlcat(tmp, pe->p_name, PF_RULE_LABEL_SIZE);
1982		else
1983		    snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp),
1984			"%u", proto);
1985		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
1986		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
1987	}
1988}
1989
1990void
1991expand_label_nr(const char *name, char *label)
1992{
1993	char tmp[PF_RULE_LABEL_SIZE];
1994	char *p;
1995
1996	while ((p = strstr(label, name)) != NULL) {
1997		tmp[0] = 0;
1998		strlcat(tmp, label, p-label+1);
1999		snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp),
2000		    "%u", pf->rule_nr);
2001		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
2002		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2003	}
2004}
2005
2006void
2007expand_label(char *label, u_int8_t af,
2008    struct node_host *src_host, struct node_port *src_port,
2009    struct node_host *dst_host, struct node_port *dst_port,
2010    u_int8_t proto)
2011{
2012	expand_label_addr("$srcaddr", label, af, src_host);
2013	expand_label_addr("$dstaddr", label, af, dst_host);
2014	expand_label_port("$srcport", label, src_port);
2015	expand_label_port("$dstport", label, dst_port);
2016	expand_label_proto("$proto", label, proto);
2017	expand_label_nr("$nr", label);
2018}
2019
2020void
2021expand_rule(struct pf_rule *r,
2022    struct node_if *interfaces, struct node_proto *protos,
2023    struct node_host *src_hosts, struct node_port *src_ports,
2024    struct node_host *dst_hosts, struct node_port *dst_ports,
2025    struct node_uid *uids, struct node_gid *gids,
2026    struct node_icmp *icmp_types)
2027{
2028	int	af = r->af, nomatch = 0, added = 0;
2029	char	ifname[IF_NAMESIZE];
2030	char	label[PF_RULE_LABEL_SIZE];
2031	u_int8_t 	flags, flagset;
2032
2033	strlcpy(label, r->label, sizeof(label));
2034	flags = r->flags;
2035	flagset = r->flagset;
2036
2037	LOOP_THROUGH(struct node_if, interface, interfaces,
2038	LOOP_THROUGH(struct node_proto, proto, protos,
2039	LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
2040	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2041	LOOP_THROUGH(struct node_port, src_port, src_ports,
2042	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2043	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
2044	LOOP_THROUGH(struct node_uid, uid, uids,
2045	LOOP_THROUGH(struct node_gid, gid, gids,
2046
2047		r->af = af;
2048		/* for link-local IPv6 address, interface must match up */
2049		if ((r->af && src_host->af && r->af != src_host->af) ||
2050		    (r->af && dst_host->af && r->af != dst_host->af) ||
2051		    (src_host->af && dst_host->af &&
2052		    src_host->af != dst_host->af) ||
2053		    (src_host->ifindex && dst_host->ifindex &&
2054		    src_host->ifindex != dst_host->ifindex) ||
2055		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2056		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2057		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2058		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2059			continue;
2060		if (!r->af && src_host->af)
2061			r->af = src_host->af;
2062		else if (!r->af && dst_host->af)
2063			r->af = dst_host->af;
2064
2065		if (if_indextoname(src_host->ifindex, ifname))
2066			memcpy(r->ifname, ifname, sizeof(r->ifname));
2067		else if (if_indextoname(dst_host->ifindex, ifname))
2068			memcpy(r->ifname, ifname, sizeof(r->ifname));
2069		else
2070			memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
2071
2072		strlcpy(r->label, label, PF_RULE_LABEL_SIZE);
2073		expand_label(r->label, r->af, src_host, src_port,
2074		    dst_host, dst_port, proto->proto);
2075		r->ifnot = interface->not;
2076		r->proto = proto->proto;
2077		r->src.addr = src_host->addr;
2078		r->src.mask = src_host->mask;
2079		r->src.noroute = src_host->noroute;
2080		r->src.not = src_host->not;
2081		r->src.port[0] = src_port->port[0];
2082		r->src.port[1] = src_port->port[1];
2083		r->src.port_op = src_port->op;
2084		r->dst.addr = dst_host->addr;
2085		r->dst.mask = dst_host->mask;
2086		r->dst.noroute = dst_host->noroute;
2087		r->dst.not = dst_host->not;
2088		r->dst.port[0] = dst_port->port[0];
2089		r->dst.port[1] = dst_port->port[1];
2090		r->dst.port_op = dst_port->op;
2091		r->uid.op = uid->op;
2092		r->uid.uid[0] = uid->uid[0];
2093		r->uid.uid[1] = uid->uid[1];
2094		r->gid.op = gid->op;
2095		r->gid.gid[0] = gid->gid[0];
2096		r->gid.gid[1] = gid->gid[1];
2097		r->type = icmp_type->type;
2098		r->code = icmp_type->code;
2099
2100		if (r->proto && r->proto != IPPROTO_TCP) {
2101			r->flags = 0;
2102			r->flagset = 0;
2103		} else {
2104			r->flags = flags;
2105			r->flagset = flagset;
2106		}
2107		if (icmp_type->proto && r->proto != icmp_type->proto) {
2108			yyerror("icmp-type mismatch");
2109			nomatch++;
2110		}
2111
2112		if (rule_consistent(r) < 0 || nomatch)
2113			yyerror("skipping filter rule due to errors");
2114		else {
2115			r->nr = pf->rule_nr++;
2116			pfctl_add_rule(pf, r);
2117			added++;
2118		}
2119
2120	)))))))));
2121
2122	FREE_LIST(struct node_if, interfaces);
2123	FREE_LIST(struct node_proto, protos);
2124	FREE_LIST(struct node_host, src_hosts);
2125	FREE_LIST(struct node_port, src_ports);
2126	FREE_LIST(struct node_host, dst_hosts);
2127	FREE_LIST(struct node_port, dst_ports);
2128	FREE_LIST(struct node_uid, uids);
2129	FREE_LIST(struct node_gid, gids);
2130	FREE_LIST(struct node_icmp, icmp_types);
2131
2132	if (!added)
2133		yyerror("rule expands to no valid combination");
2134}
2135
2136void
2137expand_nat(struct pf_nat *n,
2138    struct node_if *interfaces, struct node_proto *protos,
2139    struct node_host *src_hosts, struct node_port *src_ports,
2140    struct node_host *dst_hosts, struct node_port *dst_ports)
2141{
2142	char ifname[IF_NAMESIZE];
2143	int af = n->af, added = 0;
2144
2145	LOOP_THROUGH(struct node_if, interface, interfaces,
2146	LOOP_THROUGH(struct node_proto, proto, protos,
2147	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2148	LOOP_THROUGH(struct node_port, src_port, src_ports,
2149	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2150	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
2151
2152		n->af = af;
2153		/* for link-local IPv6 address, interface must match up */
2154		if ((n->af && src_host->af && n->af != src_host->af) ||
2155		    (n->af && dst_host->af && n->af != dst_host->af) ||
2156		    (src_host->af && dst_host->af &&
2157		    src_host->af != dst_host->af) ||
2158		    (src_host->ifindex && dst_host->ifindex &&
2159		    src_host->ifindex != dst_host->ifindex) ||
2160		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2161		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2162		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2163		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2164			continue;
2165		if (!n->af && src_host->af)
2166			n->af = src_host->af;
2167		else if (!n->af && dst_host->af)
2168			n->af = dst_host->af;
2169
2170		if (if_indextoname(src_host->ifindex, ifname))
2171			memcpy(n->ifname, ifname, sizeof(n->ifname));
2172		else if (if_indextoname(dst_host->ifindex, ifname))
2173			memcpy(n->ifname, ifname, sizeof(n->ifname));
2174		else
2175			memcpy(n->ifname, interface->ifname, sizeof(n->ifname));
2176
2177		if (!n->af && n->raddr.addr_dyn != NULL) {
2178			yyerror("address family (inet/inet6) undefined");
2179			continue;
2180		}
2181
2182		n->ifnot = interface->not;
2183		n->proto = proto->proto;
2184		n->src.addr = src_host->addr;
2185		n->src.mask = src_host->mask;
2186		n->src.noroute = src_host->noroute;
2187		n->src.not = src_host->not;
2188		n->src.port[0] = src_port->port[0];
2189		n->src.port[1] = src_port->port[1];
2190		n->src.port_op = src_port->op;
2191		n->dst.addr = dst_host->addr;
2192		n->dst.mask = dst_host->mask;
2193		n->dst.noroute = dst_host->noroute;
2194		n->dst.not = dst_host->not;
2195		n->dst.port[0] = dst_port->port[0];
2196		n->dst.port[1] = dst_port->port[1];
2197		n->dst.port_op = dst_port->op;
2198
2199		if (nat_consistent(n) < 0)
2200			yyerror("skipping nat rule due to errors");
2201		else {
2202			pfctl_add_nat(pf, n);
2203			added++;
2204		}
2205
2206	))))));
2207
2208	FREE_LIST(struct node_if, interfaces);
2209	FREE_LIST(struct node_proto, protos);
2210	FREE_LIST(struct node_host, src_hosts);
2211	FREE_LIST(struct node_port, src_ports);
2212	FREE_LIST(struct node_host, dst_hosts);
2213	FREE_LIST(struct node_port, dst_ports);
2214
2215	if (!added)
2216		yyerror("nat rule expands to no valid combinations");
2217}
2218
2219void
2220expand_rdr(struct pf_rdr *r, struct node_if *interfaces,
2221    struct node_proto *protos, struct node_host *src_hosts,
2222    struct node_host *dst_hosts)
2223{
2224	int af = r->af, added = 0;
2225	char ifname[IF_NAMESIZE];
2226
2227	LOOP_THROUGH(struct node_if, interface, interfaces,
2228	LOOP_THROUGH(struct node_proto, proto, protos,
2229	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2230	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2231
2232		r->af = af;
2233		if ((r->af && src_host->af && r->af != src_host->af) ||
2234		    (r->af && dst_host->af && r->af != dst_host->af) ||
2235		    (src_host->af && dst_host->af &&
2236		    src_host->af != dst_host->af) ||
2237		    (src_host->ifindex && dst_host->ifindex &&
2238		    src_host->ifindex != dst_host->ifindex) ||
2239		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2240		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2241		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2242		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2243			continue;
2244
2245		if (!r->af && src_host->af)
2246			r->af = src_host->af;
2247		else if (!r->af && dst_host->af)
2248			r->af = dst_host->af;
2249		if (!r->af && (r->saddr.addr_dyn != NULL ||
2250		    r->daddr.addr_dyn != NULL || r->raddr.addr_dyn)) {
2251			yyerror("address family (inet/inet6) undefined");
2252			continue;
2253		}
2254
2255		if (if_indextoname(src_host->ifindex, ifname))
2256			memcpy(r->ifname, ifname, sizeof(r->ifname));
2257		else if (if_indextoname(dst_host->ifindex, ifname))
2258			memcpy(r->ifname, ifname, sizeof(r->ifname));
2259		else
2260			memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
2261
2262		r->proto = proto->proto;
2263		r->ifnot = interface->not;
2264		r->saddr = src_host->addr;
2265		r->smask = src_host->mask;
2266		r->daddr = dst_host->addr;
2267		r->dmask = dst_host->mask;
2268
2269		if (rdr_consistent(r) < 0)
2270			yyerror("skipping rdr rule due to errors");
2271		else {
2272			pfctl_add_rdr(pf, r);
2273			added++;
2274		}
2275
2276	))));
2277
2278	FREE_LIST(struct node_if, interfaces);
2279	FREE_LIST(struct node_proto, protos);
2280	FREE_LIST(struct node_host, src_hosts);
2281	FREE_LIST(struct node_host, dst_hosts);
2282
2283	if (!added)
2284		yyerror("rdr rule expands to no valid combination");
2285}
2286
2287#undef FREE_LIST
2288#undef LOOP_THROUGH
2289
2290int
2291check_rulestate(int desired_state)
2292{
2293	if (rulestate > desired_state) {
2294		yyerror("Rules must be in order: options, normalization, "
2295		    "translation, filter");
2296		return (1);
2297	}
2298	rulestate = desired_state;
2299	return (0);
2300}
2301
2302int
2303kw_cmp(const void *k, const void *e)
2304{
2305	return (strcmp(k, ((struct keywords *)e)->k_name));
2306}
2307
2308int
2309lookup(char *s)
2310{
2311	/* this has to be sorted always */
2312	static const struct keywords keywords[] = {
2313		{ "all",	ALL},
2314		{ "allow-opts",	ALLOWOPTS},
2315		{ "antispoof",	ANTISPOOF},
2316		{ "any",	ANY},
2317		{ "binat",	BINAT},
2318		{ "block",	BLOCK},
2319		{ "code",	CODE},
2320		{ "crop",	FRAGCROP},
2321		{ "drop-ovl",	FRAGDROP},
2322		{ "dup-to",	DUPTO},
2323		{ "fastroute",	FASTROUTE},
2324		{ "flags",	FLAGS},
2325		{ "for", 	FOR},
2326		{ "fragment",	FRAGMENT},
2327		{ "from",	FROM},
2328		{ "group",	GROUP},
2329		{ "icmp-type",	ICMPTYPE},
2330		{ "in",		IN},
2331		{ "inet",	INET},
2332		{ "inet6",	INET6},
2333		{ "ipv6-icmp-type", ICMP6TYPE},
2334		{ "keep",	KEEP},
2335		{ "label",	LABEL},
2336		{ "limit",	LIMIT},
2337		{ "log",	LOG},
2338		{ "log-all",	LOGALL},
2339		{ "loginterface", LOGINTERFACE},
2340		{ "max",	MAXIMUM},
2341		{ "max-mss",	MAXMSS},
2342		{ "min-ttl",	MINTTL},
2343		{ "modulate",	MODULATE},
2344		{ "nat",	NAT},
2345		{ "no",		NO},
2346		{ "no-df",	NODF},
2347		{ "no-route",	NOROUTE},
2348		{ "on",		ON},
2349		{ "optimization", OPTIMIZATION},
2350		{ "out",	OUT},
2351		{ "pass",	PASS},
2352		{ "port",	PORT},
2353		{ "proto",	PROTO},
2354		{ "quick",	QUICK},
2355		{ "rdr",	RDR},
2356		{ "reassemble",	FRAGNORM},
2357		{ "reply-to",	REPLYTO},
2358		{ "return",	RETURN},
2359		{ "return-icmp",RETURNICMP},
2360		{ "return-icmp6",RETURNICMP6},
2361		{ "return-rst",	RETURNRST},
2362		{ "route-to",	ROUTETO},
2363		{ "scrub",	SCRUB},
2364		{ "set",	SET},
2365		{ "state",	STATE},
2366		{ "timeout",	TIMEOUT},
2367		{ "to",		TO},
2368		{ "tos",	TOS},
2369		{ "ttl",	TTL},
2370		{ "user",	USER},
2371	};
2372	const struct keywords *p;
2373
2374	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
2375	    sizeof(keywords[0]), kw_cmp);
2376
2377	if (p) {
2378		if (debug > 1)
2379			fprintf(stderr, "%s: %d\n", s, p->k_val);
2380		return (p->k_val);
2381	} else {
2382		if (debug > 1)
2383			fprintf(stderr, "string: %s\n", s);
2384		return (STRING);
2385	}
2386}
2387
2388#define MAXPUSHBACK	128
2389
2390char	*parsebuf;
2391int	parseindex;
2392char	pushback_buffer[MAXPUSHBACK];
2393int	pushback_index = 0;
2394
2395int
2396lgetc(FILE *fin)
2397{
2398	int c, next;
2399
2400	if (parsebuf) {
2401		/* Reading characters from the parse buffer, instead of input */
2402		if (parseindex >= 0) {
2403			c = parsebuf[parseindex++];
2404			if (c != '\0')
2405				return (c);
2406			parsebuf = NULL;
2407		} else
2408			parseindex++;
2409	}
2410
2411	if (pushback_index)
2412		return (pushback_buffer[--pushback_index]);
2413
2414	while ((c = getc(fin)) == '\\') {
2415		next = getc(fin);
2416		if (next != '\n') {
2417			ungetc(next, fin);
2418			break;
2419		}
2420		yylval.lineno = lineno;
2421		lineno++;
2422	}
2423	return (c);
2424}
2425
2426int
2427lungetc(int c, FILE *fin)
2428{
2429	if (c == EOF)
2430		return (EOF);
2431	if (parsebuf) {
2432		parseindex--;
2433		if (parseindex >= 0)
2434			return (c);
2435	}
2436	if (pushback_index < MAXPUSHBACK-1)
2437		return (pushback_buffer[pushback_index++] = c);
2438	else
2439		return (EOF);
2440}
2441
2442int
2443findeol(void)
2444{
2445	int c;
2446
2447	parsebuf = NULL;
2448	pushback_index = 0;
2449
2450	/* skip to either EOF or the first real EOL */
2451	while (1) {
2452		c = lgetc(fin);
2453		if (c == '\n') {
2454			lineno++;
2455			break;
2456		}
2457		if (c == EOF)
2458			break;
2459	}
2460	return (ERROR);
2461}
2462
2463int
2464yylex(void)
2465{
2466	char buf[8096], *p, *val;
2467	int endc, c, next;
2468	int token;
2469
2470top:
2471	p = buf;
2472	while ((c = lgetc(fin)) == ' ' || c == '\t')
2473		;
2474
2475	yylval.lineno = lineno;
2476	if (c == '#')
2477		while ((c = lgetc(fin)) != '\n' && c != EOF)
2478			;
2479	if (c == '$' && parsebuf == NULL) {
2480		while (1) {
2481			if ((c = lgetc(fin)) == EOF)
2482				return (0);
2483			if (p + 1 >= buf + sizeof(buf) - 1) {
2484				yyerror("string too long");
2485				return (findeol());
2486			}
2487			if (isalnum(c) || c == '_') {
2488				*p++ = (char)c;
2489				continue;
2490			}
2491			*p = '\0';
2492			lungetc(c, fin);
2493			break;
2494		}
2495		val = symget(buf);
2496		if (val == NULL)
2497			return (ERROR);
2498		parsebuf = val;
2499		parseindex = 0;
2500		goto top;
2501	}
2502
2503	switch (c) {
2504	case '\'':
2505	case '"':
2506		endc = c;
2507		while (1) {
2508			if ((c = lgetc(fin)) == EOF)
2509				return (0);
2510			if (c == endc) {
2511				*p = '\0';
2512				break;
2513			}
2514			if (c == '\n') {
2515				lineno++;
2516				continue;
2517			}
2518			if (p + 1 >= buf + sizeof(buf) - 1) {
2519				yyerror("string too long");
2520				return (findeol());
2521			}
2522			*p++ = (char)c;
2523		}
2524		yylval.v.string = strdup(buf);
2525		if (yylval.v.string == NULL)
2526			err(1, "yylex: strdup");
2527		return (STRING);
2528	case '=':
2529		yylval.v.i = PF_OP_EQ;
2530		return (PORTUNARY);
2531	case '!':
2532		next = lgetc(fin);
2533		if (next == '=') {
2534			yylval.v.i = PF_OP_NE;
2535			return (PORTUNARY);
2536		}
2537		lungetc(next, fin);
2538		break;
2539	case '<':
2540		next = lgetc(fin);
2541		if (next == '>') {
2542			yylval.v.i = PF_OP_XRG;
2543			return (PORTBINARY);
2544		} else  if (next == '=') {
2545			yylval.v.i = PF_OP_LE;
2546		} else {
2547			yylval.v.i = PF_OP_LT;
2548			lungetc(next, fin);
2549		}
2550		return (PORTUNARY);
2551		break;
2552	case '>':
2553		next = lgetc(fin);
2554		if (next == '<') {
2555			yylval.v.i = PF_OP_IRG;
2556			return (PORTBINARY);
2557		} else  if (next == '=') {
2558			yylval.v.i = PF_OP_GE;
2559		} else {
2560			yylval.v.i = PF_OP_GT;
2561			lungetc(next, fin);
2562		}
2563		return (PORTUNARY);
2564		break;
2565	case '-':
2566		next = lgetc(fin);
2567		if (next == '>')
2568			return (ARROW);
2569		lungetc(next, fin);
2570		break;
2571	}
2572
2573#define allowed_in_string(x) \
2574	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
2575	x != '{' && x != '}' && x != '<' && x != '>' && \
2576	x != '!' && x != '=' && x != '/' && x != '#' && \
2577	x != ','))
2578
2579	if (isalnum(c) || c == ':') {
2580		do {
2581			*p++ = c;
2582			if (p-buf >= sizeof(buf)) {
2583				yyerror("string too long");
2584				return (findeol());
2585			}
2586		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
2587		lungetc(c, fin);
2588		*p = '\0';
2589		token = lookup(buf);
2590		yylval.v.string = strdup(buf);
2591		if (yylval.v.string == NULL)
2592			err(1, "yylex: strdup");
2593		return (token);
2594	}
2595	if (c == '\n') {
2596		yylval.lineno = lineno;
2597		lineno++;
2598	}
2599	if (c == EOF)
2600		return (0);
2601	return (c);
2602}
2603
2604int
2605parse_rules(FILE *input, struct pfctl *xpf)
2606{
2607	fin = input;
2608	pf = xpf;
2609	lineno = 1;
2610	errors = 0;
2611	rulestate = PFCTL_STATE_NONE;
2612	yyparse();
2613	return (errors ? -1 : 0);
2614}
2615
2616void
2617ipmask(struct pf_addr *m, u_int8_t b)
2618{
2619	int i, j = 0;
2620
2621	for (i = 0; i < 4; i++)
2622		m->addr32[i] = 0;
2623
2624	while (b >= 32) {
2625		m->addr32[j++] = 0xffffffff;
2626		b -= 32;
2627	}
2628	for (i = 31; i > 31-b; --i)
2629		m->addr32[j] |= (1 << i);
2630	if (b)
2631		m->addr32[j] = htonl(m->addr32[j]);
2632}
2633
2634/*
2635 * Over-designed efficiency is a French and German concept, so how about
2636 * we wait until they discover this ugliness and make it all fancy.
2637 */
2638int
2639symset(const char *nam, const char *val)
2640{
2641	struct sym *sym;
2642
2643	sym = calloc(1, sizeof(*sym));
2644	if (sym == NULL)
2645		return (-1);
2646	sym->nam = strdup(nam);
2647	if (sym->nam == NULL) {
2648		free(sym);
2649		return (-1);
2650	}
2651	sym->val = strdup(val);
2652	if (sym->val == NULL) {
2653		free(sym->nam);
2654		free(sym);
2655		return (-1);
2656	}
2657	sym->next = symhead;
2658	symhead = sym;
2659	return (0);
2660}
2661
2662char *
2663symget(const char *nam)
2664{
2665	struct sym *sym;
2666
2667	for (sym = symhead; sym; sym = sym->next)
2668		if (strcmp(nam, sym->nam) == 0)
2669			return (sym->val);
2670	return (NULL);
2671}
2672
2673/* interface lookup routines */
2674
2675struct node_host *iftab;
2676
2677void
2678ifa_load(void)
2679{
2680	struct ifaddrs *ifap, *ifa;
2681	struct node_host *n = NULL, *h = NULL;
2682
2683	if (getifaddrs(&ifap) < 0)
2684		err(1, "getifaddrs");
2685
2686	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
2687		if (!(ifa->ifa_addr->sa_family == AF_INET ||
2688		    ifa->ifa_addr->sa_family == AF_INET6 ||
2689		    ifa->ifa_addr->sa_family == AF_LINK))
2690				continue;
2691		n = calloc(1, sizeof(struct node_host));
2692		if (n == NULL)
2693			err(1, "address: calloc");
2694		n->af = ifa->ifa_addr->sa_family;
2695		n->addr.addr_dyn = NULL;
2696		n->ifa_flags = ifa->ifa_flags;
2697#ifdef __KAME__
2698		if (n->af == AF_INET6 &&
2699		    IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr) &&
2700		    ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
2701			struct sockaddr_in6 *sin6;
2702
2703			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
2704			sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
2705			    sin6->sin6_addr.s6_addr[3];
2706			sin6->sin6_addr.s6_addr[2] = 0;
2707			sin6->sin6_addr.s6_addr[3] = 0;
2708		}
2709#endif
2710		n->ifindex = 0;
2711		if (n->af == AF_INET) {
2712			memcpy(&n->addr.addr, &((struct sockaddr_in *)
2713			    ifa->ifa_addr)->sin_addr.s_addr,
2714			    sizeof(struct in_addr));
2715			memcpy(&n->mask, &((struct sockaddr_in *)
2716			    ifa->ifa_netmask)->sin_addr.s_addr,
2717			    sizeof(struct in_addr));
2718			if (ifa->ifa_broadaddr != NULL)
2719				memcpy(&n->bcast, &((struct sockaddr_in *)
2720				    ifa->ifa_broadaddr)->sin_addr.s_addr,
2721				    sizeof(struct in_addr));
2722		} else if (n->af == AF_INET6) {
2723			memcpy(&n->addr.addr, &((struct sockaddr_in6 *)
2724			    ifa->ifa_addr)->sin6_addr.s6_addr,
2725			    sizeof(struct in6_addr));
2726			memcpy(&n->mask, &((struct sockaddr_in6 *)
2727			    ifa->ifa_netmask)->sin6_addr.s6_addr,
2728			    sizeof(struct in6_addr));
2729			if (ifa->ifa_broadaddr != NULL)
2730				memcpy(&n->bcast, &((struct sockaddr_in6 *)
2731				    ifa->ifa_broadaddr)->sin6_addr.s6_addr,
2732				    sizeof(struct in6_addr));
2733			n->ifindex = ((struct sockaddr_in6 *)
2734			    ifa->ifa_addr)->sin6_scope_id;
2735		}
2736		if ((n->ifname = strdup(ifa->ifa_name)) == NULL) {
2737			yyerror("malloc failed");
2738			exit(1);
2739		}
2740		n->next = NULL;
2741		n->tail = n;
2742		if (h == NULL)
2743			h = n;
2744		else {
2745			h->tail->next = n;
2746			h->tail = n;
2747		}
2748	}
2749	iftab = h;
2750	freeifaddrs(ifap);
2751}
2752
2753struct node_host *
2754ifa_exists(char *ifa_name)
2755{
2756	struct node_host *n;
2757
2758	if (iftab == NULL)
2759		ifa_load();
2760
2761	for (n = iftab; n; n = n->next) {
2762		if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
2763			return (n);
2764	}
2765	return (NULL);
2766}
2767
2768struct node_host *
2769ifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode)
2770{
2771	struct node_host *p = NULL, *h = NULL, *n = NULL;
2772	int return_all = 0;
2773
2774	if (!strncmp(ifa_name, "self", IFNAMSIZ))
2775		return_all = 1;
2776
2777	if (iftab == NULL)
2778		ifa_load();
2779
2780	for (p = iftab; p; p = p->next) {
2781		if (!((p->af == AF_INET || p->af == AF_INET6)
2782		    && (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
2783			continue;
2784		if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
2785			continue;
2786		if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
2787			continue;
2788		n = calloc(1, sizeof(struct node_host));
2789		if (n == NULL)
2790			err(1, "address: calloc");
2791		n->af = p->af;
2792		n->addr.addr_dyn = NULL;
2793		if (mode == PFCTL_IFLOOKUP_BCAST) {
2794				memcpy(&n->addr.addr, &p->bcast,
2795				    sizeof(struct pf_addr));
2796		} else
2797			memcpy(&n->addr.addr, &p->addr.addr,
2798			    sizeof(struct pf_addr));
2799		if (mode == PFCTL_IFLOOKUP_NET)
2800			memcpy(&n->mask, &p->mask, sizeof(struct pf_addr));
2801		else {
2802			if (n->af == AF_INET)
2803				ipmask(&n->mask, 32);
2804			else
2805				ipmask(&n->mask, 128);
2806		}
2807		n->ifindex = p->ifindex;
2808
2809		n->next = NULL;
2810		n->tail = n;
2811		if (h == NULL)
2812			h = n;
2813		else {
2814			h->tail->next = n;
2815			h->tail = n;
2816		}
2817	}
2818	if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
2819		yyerror("no IP address found for %s", ifa_name);
2820	}
2821	return (h);
2822}
2823
2824struct node_host *
2825ifa_pick_ip(struct node_host *nh, u_int8_t af)
2826{
2827	struct node_host *h, *n = NULL;
2828
2829	if (af == 0 && nh && nh->next) {
2830		yyerror("address family not given and translation address "
2831		    "expands to multiple IPs");
2832		return (NULL);
2833	}
2834	for (h = nh; h; h = h->next) {
2835		if (h->af == af || h->af == 0 || af == 0) {
2836			if (n != NULL) {
2837				yyerror("translation address expands to "
2838				    "multiple IPs of this address family");
2839				return (NULL);
2840			}
2841			n = h;
2842		}
2843	}
2844	if (n == NULL)
2845		yyerror("no translation address with matching address family "
2846		    "found.");
2847	else {
2848		n->next = NULL;
2849		n->tail = n;
2850	}
2851
2852	return (n);
2853}
2854
2855struct node_host *
2856host(char *s)
2857{
2858	struct node_host *h = NULL, *n;
2859	struct in_addr ina;
2860	struct addrinfo hints, *res0, *res;
2861	int error;
2862
2863	if (ifa_exists(s) || !strncmp(s, "self", IFNAMSIZ)) {
2864		/* interface with this name exists */
2865		if ((h = ifa_lookup(s, PFCTL_IFLOOKUP_HOST)) == NULL)
2866			return (NULL);
2867		else {
2868			h->next = NULL;
2869			h->tail = h;
2870			return (h);
2871		}
2872	}
2873
2874	if (inet_aton(s, &ina) == 1) {
2875		h = calloc(1, sizeof(struct node_host));
2876		if (h == NULL)
2877			err(1, "address: calloc");
2878		h->af = AF_INET;
2879		h->addr.addr_dyn = NULL;
2880		h->addr.addr.addr32[0] = ina.s_addr;
2881		ipmask(&h->mask, 32);
2882		h->next = NULL;
2883		h->tail = h;
2884		return (h);
2885	}
2886
2887	memset(&hints, 0, sizeof(hints));
2888	hints.ai_family = AF_INET6;
2889	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
2890	hints.ai_flags = AI_NUMERICHOST;
2891	if (getaddrinfo(s, "0", &hints, &res) == 0) {
2892		n = calloc(1, sizeof(struct node_host));
2893		if (n == NULL)
2894			err(1, "address: calloc");
2895		n->af = AF_INET6;
2896		n->addr.addr_dyn = NULL;
2897		memcpy(&n->addr.addr,
2898		    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
2899		    sizeof(n->addr.addr));
2900		n->ifindex = ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
2901		ipmask(&n->mask, 128);
2902		freeaddrinfo(res);
2903		n->next = NULL;
2904		n->tail = n;
2905		return (n);
2906	}
2907
2908	memset(&hints, 0, sizeof(hints));
2909	hints.ai_family = PF_UNSPEC;
2910	hints.ai_socktype = SOCK_STREAM; /* DUMMY */
2911	error = getaddrinfo(s, NULL, &hints, &res0);
2912	if (error) {
2913		yyerror("cannot resolve %s: %s",
2914		    s, gai_strerror(error));
2915		return (NULL);
2916	}
2917	for (res = res0; res; res = res->ai_next) {
2918		if (res->ai_family != AF_INET &&
2919		    res->ai_family != AF_INET6)
2920			continue;
2921		n = calloc(1, sizeof(struct node_host));
2922		if (n == NULL)
2923			err(1, "address: calloc");
2924		n->af = res->ai_family;
2925		n->addr.addr_dyn = NULL;
2926		if (res->ai_family == AF_INET) {
2927			memcpy(&n->addr.addr,
2928			    &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
2929			    sizeof(struct in_addr));
2930			ipmask(&n->mask, 32);
2931		} else {
2932			memcpy(&n->addr.addr,
2933			    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr,
2934			    sizeof(struct in6_addr));
2935			n->ifindex =
2936			    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
2937			ipmask(&n->mask, 128);
2938		}
2939		n->next = NULL;
2940		n->tail = n;
2941		if (h == NULL)
2942			h = n;
2943		else {
2944			h->tail->next = n;
2945			h->tail = n;
2946		}
2947	}
2948	freeaddrinfo(res0);
2949	if (h == NULL) {
2950		yyerror("no IP address found for %s", s);
2951		return (NULL);
2952	}
2953	return (h);
2954}
2955
2956int
2957atoul(char *s, u_long *ulvalp)
2958{
2959	u_long ulval;
2960	char *ep;
2961
2962	errno = 0;
2963	ulval = strtoul(s, &ep, 0);
2964	if (s[0] == '\0' || *ep != '\0')
2965		return (-1);
2966	if (errno == ERANGE && ulval == ULONG_MAX)
2967		return (-1);
2968	*ulvalp = ulval;
2969	return (0);
2970}
2971
2972int
2973getservice(char *n)
2974{
2975	struct servent *s;
2976	u_long ulval;
2977
2978	if (atoul(n, &ulval) == 0) {
2979		if (ulval < 0 || ulval > 65535) {
2980			yyerror("illegal port value %d", ulval);
2981			return (-1);
2982		}
2983		return (htons(ulval));
2984	} else {
2985		s = getservbyname(n, "tcp");
2986		if (s == NULL)
2987			s = getservbyname(n, "udp");
2988		if (s == NULL) {
2989			yyerror("unknown port %s", n);
2990			return (-1);
2991		}
2992		return (s->s_port);
2993	}
2994}
2995
2996u_int16_t
2997parseicmpspec(char *w, u_int8_t af)
2998{
2999	const struct icmpcodeent *p;
3000	u_long ulval;
3001	u_int8_t icmptype;
3002
3003	if (af == AF_INET)
3004		icmptype = returnicmpdefault >> 8;
3005	else
3006		icmptype = returnicmp6default >> 8;
3007
3008	if (atoul(w, &ulval) == -1) {
3009		if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
3010			yyerror("unknown icmp code %s", w);
3011			return (0);
3012		}
3013		ulval = p->code;
3014	}
3015	return (icmptype << 8 | ulval);
3016}
3017