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