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