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