xref: /openbsd/sbin/pfctl/parse.y (revision fd84ef7e)
1 /*	$OpenBSD: parse.y,v 1.48 2001/12/23 03:50:03 deraadt 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 
50 #include "pfctl_parser.h"
51 
52 static struct pfctl *pf = NULL;
53 static FILE *fin = NULL;
54 static int debug = 0;
55 static int lineno = 1;
56 static int errors = 0;
57 static int natmode = 0;
58 
59 struct node_if {
60 	char			 ifname[IFNAMSIZ];
61 	u_int8_t		 not;
62 	struct node_if		*next;
63 };
64 
65 struct node_proto {
66 	u_int8_t		 proto;
67 	struct node_proto	*next;
68 };
69 
70 struct node_host {
71 	struct pf_addr		 addr;
72 	struct pf_addr		 mask;
73 	u_int8_t		 af;
74 	u_int8_t		 not;
75 	struct node_host	*next;
76 };
77 
78 struct node_port {
79 	u_int16_t		 port[2];
80 	u_int8_t		 op;
81 	struct node_port	*next;
82 };
83 
84 struct node_icmp {
85 	u_int8_t		 code;
86 	u_int8_t		 type;
87 	u_int8_t		 proto;
88 	struct node_icmp	*next;
89 };
90 
91 struct peer {
92 	struct node_host	*host;
93 	struct node_port	*port;
94 };
95 
96 int			 rule_consistent(struct pf_rule *);
97 int			 yyparse(void);
98 struct pf_rule_addr	*new_addr(void);
99 void		 	 ipmask(struct pf_addr *, u_int8_t, int);
100 void			 expand_rule_hosts(struct pf_rule *,
101 			    struct node_if *, struct node_proto *,
102 			    struct node_host *, struct node_port *,
103 			    struct node_host *, struct node_port *,
104 			    struct node_icmp *);
105 void			 expand_rule_protos(struct pf_rule *,
106 			    struct node_if *, struct node_proto *,
107 			    struct node_host *, struct node_port *,
108 			    struct node_host *, struct node_port *,
109 			    struct node_icmp *);
110 void			 expand_rule(struct pf_rule *,
111 			    struct node_if *, struct node_proto *,
112 			    struct node_host *, struct node_port *,
113 			    struct node_host *, struct node_port *,
114 			    struct node_icmp *);
115 
116 struct sym {
117 	struct sym *next;
118 	char *nam;
119 	char *val;
120 };
121 struct sym *symhead = NULL;
122 
123 int	symset(char *name, char *val);
124 char *	symget(char *name);
125 
126 struct ifaddrs    *ifa0_lookup(char *ifa_name);
127 struct ifaddrs    *ifa4_lookup(char *ifa_name);
128 struct ifaddrs    *ifa6_lookup(char *ifa_name);
129 
130 typedef struct {
131 	union {
132 		u_int32_t		number;
133 		int			i;
134 		char			*string;
135 		struct {
136 			u_int8_t	b1;
137 			u_int8_t	b2;
138 			u_int16_t	w;
139 		}			b;
140 		struct {
141 			int		a;
142 			int		b;
143 			int		t;
144 		}			range;
145 		struct node_if		*interface;
146 		struct node_proto	*proto;
147 		struct node_icmp	*icmp;
148 		struct node_host	*host;
149 		struct node_port	*port;
150 		struct peer		peer;
151 		struct {
152 			struct peer	src, dst;
153 		}			fromto;
154 		struct {
155 			char		*string;
156 			struct pf_addr	*addr;
157 			u_int8_t	rt;
158 			u_int8_t	af;
159 		}			route;
160 	} v;
161 	int lineno;
162 } YYSTYPE;
163 
164 %}
165 
166 %token	PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS
167 %token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
168 %token  ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
169 %token	MINTTL IPV6ADDR ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO
170 %token	<v.string> STRING
171 %token	<v.number> NUMBER
172 %token	<v.i>	PORTUNARY PORTBINARY
173 %type	<v.interface>	interface if_list if_item_not if_item
174 %type	<v.number>	port icmptype icmp6type minttl
175 %type	<v.i>	dir log quick af keep nodf allowopts
176 %type	<v.b>	action flag flags blockspec
177 %type	<v.range>	dport rport
178 %type	<v.proto>	proto proto_list proto_item
179 %type	<v.icmp>	icmpspec icmp_list icmp6_list icmp_item icmp6_item
180 %type	<v.fromto>	fromto
181 %type	<v.peer>	ipportspec
182 %type	<v.host>	ipspec xhost host address host_list IPV6ADDR
183 %type	<v.port>	portspec port_list port_item
184 %type	<v.route>	route
185 %%
186 
187 ruleset		: /* empty */
188 		| ruleset '\n'
189 		| ruleset pfrule '\n'
190 		| ruleset natrule '\n'
191 		| ruleset binatrule '\n'
192 		| ruleset rdrrule '\n'
193 		| ruleset varset '\n'
194 		| ruleset error '\n'		{ errors++; }
195 		;
196 
197 varset		: STRING PORTUNARY STRING
198 		{
199 			if (pf->opts & PF_OPT_VERBOSE)
200 				printf("%s = %s\n", $1, $3);
201 			if (symset($1, $3) == -1) {
202 				yyerror("cannot store variable %s", $1);
203 				YYERROR;
204 			}
205 		}
206 		;
207 
208 pfrule		: action dir log quick interface route af proto fromto flags icmpspec keep nodf minttl allowopts
209 		{
210 			struct pf_rule r;
211 
212 			if (natmode) {
213 				yyerror("filter rule not permitted in nat mode");
214 				YYERROR;
215 			}
216 			memset(&r, 0, sizeof(r));
217 
218 			r.action = $1.b1;
219 			if ($1.b2)
220 				r.rule_flag |= PFRULE_RETURNRST;
221 			else
222 				r.return_icmp = $1.w;
223 			r.direction = $2;
224 			r.log = $3;
225 			r.quick = $4;
226 
227 
228 			r.af = $7;
229 			r.flags = $10.b1;
230 			r.flagset = $10.b2;
231 
232 			r.keep_state = $12;
233 
234 			if ($13)
235 				r.rule_flag |= PFRULE_NODF;
236 			if ($14)
237 				r.min_ttl = $14;
238 			r.allow_opts = $15;
239 
240 			if ($6.rt) {
241 				r.rt = $6.rt;
242 				if ($6.string) {
243 					memcpy(r.rt_ifname, $6.string,
244 					    sizeof(r.rt_ifname));
245 					free($6.string);
246 				}
247 				if ($6.addr) {
248 					if (!r.af)
249 						r.af = $6.af;
250 					else if (r.af != $6.af) {
251 						yyerror("address family"
252 						    " mismatch");
253 						YYERROR;
254 					}
255 					memcpy(&r.rt_addr, $6.addr,
256 					    sizeof(r.rt_addr));
257 					free($6.addr);
258 				}
259 			}
260 
261 			expand_rule(&r, $5, $8, $9.src.host, $9.src.port,
262 			    $9.dst.host, $9.dst.port, $11);
263 		}
264 		;
265 
266 action		: PASS			{ $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
267 		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
268 		| SCRUB			{ $$.b1 = PF_SCRUB; $$.b2 = $$.w = 0; }
269 		;
270 
271 blockspec	: /* empty */		{ $$.b2 = 0; $$.w = 0; }
272 		| RETURNRST		{ $$.b2 = 1; $$.w = 0;}
273 		| RETURNICMP		{
274 			$$.b2 = 0;
275 			$$.w = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
276 		}
277 		| RETURNICMP6		{
278 			$$.b2 = 0;
279 			$$.w = (ICMP6_DST_UNREACH << 8) |
280 			    ICMP6_DST_UNREACH_NOPORT;
281 		}
282 		| RETURNICMP '(' NUMBER ')'	{
283 			$$.w = (ICMP_UNREACH << 8) | $3;
284 			$$.b2 = 0;
285 		}
286 		| RETURNICMP '(' STRING ')'	{
287 			struct icmpcodeent *p;
288 
289 			if ((p = geticmpcodebyname(ICMP_UNREACH, $3,
290 			    AF_INET)) == NULL) {
291 				yyerror("unknown icmp code %s", $3);
292 				YYERROR;
293 			}
294 			$$.w = (p->type << 8) | p->code;
295 			$$.b2 = 0;
296 		}
297 		| RETURNICMP6 '(' NUMBER ')'	{
298 			$$.w = (ICMP6_DST_UNREACH << 8) | $3;
299 			$$.b2 = 0;
300 		}
301 		| RETURNICMP6 '(' STRING ')'	{
302 			struct icmpcodeent *p;
303 
304 			if ((p = geticmpcodebyname(ICMP6_DST_UNREACH, $3,
305 			    AF_INET6)) == NULL) {
306 				yyerror("unknown icmp code %s", $3);
307 				YYERROR;
308 			}
309 			$$.w = (p->type << 8) | p->code;
310 			$$.b2 = 0;
311 		}
312 		;
313 
314 dir		: IN			{ $$ = PF_IN; }
315 		| OUT				{ $$ = PF_OUT; }
316 		;
317 
318 log		: /* empty */			{ $$ = 0; }
319 		| LOG				{ $$ = 1; }
320 		| LOGALL			{ $$ = 2; }
321 		;
322 
323 quick		: /* empty */			{ $$ = 0; }
324 		| QUICK				{ $$ = 1; }
325 		;
326 
327 interface	: /* empty */			{ $$ = NULL; }
328 		| ON if_item_not		{ $$ = $2; }
329 		| ON '{' if_list '}'		{ $$ = $3; }
330 		;
331 
332 if_list		: if_item_not			{ $$ = $1; }
333 		| if_list ',' if_item_not	{ $3->next = $1; $$ = $3; }
334 		;
335 
336 if_item_not	: '!' if_item			{ $$ = $2; $$->not = 1; }
337 		| if_item			{ $$ = $1; }
338 
339 if_item		: STRING			{
340 			if (ifa0_lookup($1) == NULL) {
341 				yyerror("unknown interface %s", $1);
342 				YYERROR;
343 			}
344 			$$ = malloc(sizeof(struct node_if));
345 			if ($$ == NULL)
346 				err(1, "if_item: malloc");
347 			strlcpy($$->ifname, $1, IFNAMSIZ);
348 			$$->not = 0;
349 			$$->next = NULL;
350 		}
351 		;
352 
353 af		: /* empty */			{ $$ = 0; }
354 		| INET				{ $$ = AF_INET; }
355 		| INET6				{ $$ = AF_INET6; }
356 
357 proto		: /* empty */			{ $$ = NULL; }
358 		| PROTO proto_item		{ $$ = $2; }
359 		| PROTO '{' proto_list '}'	{ $$ = $3; }
360 		;
361 
362 proto_list	: proto_item			{ $$ = $1; }
363 		| proto_list ',' proto_item	{ $3->next = $1; $$ = $3; }
364 		;
365 
366 proto_item	: NUMBER			{
367 			struct protoent *p;
368 
369 			if ((p = getprotobynumber($1)) == NULL) {
370 				yyerror("unknown protocol %d", $1);
371 				YYERROR;
372 			}
373 			$$ = malloc(sizeof(struct node_proto));
374 			if ($$ == NULL)
375 				err(1, "proto_item: malloc");
376 			$$->proto = p->p_proto;
377 			$$->next = NULL;
378 		}
379 		| STRING			{
380 			struct protoent *p;
381 
382 			if ((p = getprotobyname($1)) == NULL) {
383 				yyerror("unknown protocol %s", $1);
384 				YYERROR;
385 			}
386 			$$ = malloc(sizeof(struct node_proto));
387 			if ($$ == NULL)
388 				err(1, "proto_item: malloc");
389 			$$->proto = p->p_proto;
390 			$$->next = NULL;
391 		}
392 		;
393 
394 fromto		: ALL				{
395 			$$.src.host = NULL;
396 			$$.src.port = NULL;
397 			$$.dst.host = NULL;
398 			$$.dst.port = NULL;
399 		}
400 		| FROM ipportspec TO ipportspec	{
401 			$$.src = $2;
402 			$$.dst = $4;
403 		}
404 		;
405 
406 ipportspec	: ipspec			{ $$.host = $1; $$.port = NULL; }
407 		| ipspec PORT portspec		{
408 			$$.host = $1;
409 			$$.port = $3;
410 		}
411 		;
412 
413 ipspec		: ANY				{ $$ = NULL; }
414 		| xhost				{ $$ = $1; }
415 		| '{' host_list '}'		{ $$ = $2; }
416 		;
417 
418 host_list	: xhost				{ $$ = $1; }
419 		| host_list ',' xhost		{ $3->next = $1; $$ = $3; }
420 		;
421 
422 xhost		: '!' host			{ $$ = $2; $$->not = 1; }
423 		| host				{ $$ = $1; }
424 		;
425 
426 host		: address			{
427 			$$ = $1;
428 			if ($$->af == AF_INET)
429 				ipmask(&$$->mask, 32, AF_INET);
430 			else
431 				ipmask(&$$->mask, 128, AF_INET6);
432 		}
433 		| address '/' NUMBER		{
434 			if ($$->af == AF_INET) {
435 				if ($3 < 0 || $3 > 32) {
436 					yyerror("illegal netmask value %d", $3);
437 					YYERROR;
438 				}
439 			} else {
440 				if ($3 < 0 || $3 > 128) {
441 					yyerror("illegal netmask value %d", $3);
442 					YYERROR;
443 				}
444 			}
445 			$$ = $1;
446 			ipmask(&$$->mask, $3, $$->af);
447 		}
448 		;
449 
450 address		: STRING			{
451 			struct hostent *hp;
452 			struct ifaddrs *ifa;
453 
454 			if (ifa0_lookup($1)) {
455 				/* an interface with this name exists */
456 				if ((ifa = ifa4_lookup($1))) {
457 					struct sockaddr_in *sin =
458 					    (struct sockaddr_in *)
459 					    ifa->ifa_addr;
460 
461 					$$ = calloc(1,
462 					    sizeof(struct node_host));
463 					if ($$ == NULL)
464 						err(1, "address: calloc");
465 					$$->af = AF_INET;
466 					memcpy(&$$->addr, &sin->sin_addr,
467 					    sizeof(u_int32_t));
468 				} else if ((ifa = ifa6_lookup($1))) {
469 					struct sockaddr_in6 *sin6 =
470 					    (struct sockaddr_in6 *)
471 					    ifa->ifa_addr;
472 
473 					$$ = calloc(1,
474 					    sizeof(struct node_host));
475 					if ($$ == NULL)
476 						err(1, "address: calloc");
477 					$$->af = AF_INET6;
478 					memcpy(&$$->addr, &sin6->sin6_addr,
479 					    sizeof(struct pf_addr));
480 				} else {
481 					yyerror("interface %s has no IP "
482 					    "addresses", $1);
483 					YYERROR;
484 				}
485 			}
486 			else if ((hp = gethostbyname2($1, AF_INET)) == NULL) {
487 				if ((hp = gethostbyname2($1, AF_INET6))
488 				    == NULL) {
489 					yyerror("cannot resolve %s", $1);
490 					YYERROR;
491 				} else {
492 					$$ = calloc(1, sizeof(struct node_host));
493 					if ($$ == NULL)
494 						err(1, "address: calloc");
495 					$$->af = AF_INET6;
496 					memcpy(&$$->addr, hp->h_addr,
497 					    sizeof(struct pf_addr));
498 				}
499 			} else {
500 				$$ = calloc(1, sizeof(struct node_host));
501 				if ($$ == NULL)
502 					err(1, "address: calloc");
503 				$$->af = AF_INET;
504 				memcpy(&$$->addr, hp->h_addr, sizeof(u_int32_t));
505 			}
506 		}
507 		| NUMBER '.' NUMBER '.' NUMBER '.' NUMBER {
508 			if ($1 < 0 || $3 < 0 || $5 < 0 || $7 < 0 ||
509 			    $1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
510 				yyerror("illegal ip address %d.%d.%d.%d",
511 				    $1, $3, $5, $7);
512 				YYERROR;
513 			}
514 			$$ = calloc(1, sizeof(struct node_host));
515 			if ($$ == NULL)
516 				err(1, "address: calloc");
517 			$$->af = AF_INET;
518 			$$->addr.addr32[0] = htonl(($1 << 24) |
519 			    ($3 << 16) | ($5 << 8) | $7);
520 		}
521 		| IPV6ADDR			{ $$ = $1; }
522 		;
523 
524 portspec	: port_item			{ $$ = $1; }
525 		| '{' port_list '}'		{ $$ = $2; }
526 		;
527 
528 port_list	: port_item			{ $$ = $1; }
529 		| port_list ',' port_item	{ $3->next = $1; $$ = $3; }
530 		;
531 
532 port_item	: port				{
533 			$$ = malloc(sizeof(struct node_port));
534 			if ($$ == NULL)
535 				err(1, "port_item: malloc");
536 			$$->port[0] = $1;
537 			$$->port[1] = $1;
538 			$$->op = PF_OP_EQ;
539 			$$->next = NULL;
540 		}
541 		| PORTUNARY port		{
542 			$$ = malloc(sizeof(struct node_port));
543 			if ($$ == NULL)
544 				err(1, "port_item: malloc");
545 			$$->port[0] = $2;
546 			$$->port[1] = $2;
547 			$$->op = $1;
548 			$$->next = NULL;
549 		}
550 		| port PORTBINARY port		{
551 			$$ = malloc(sizeof(struct node_port));
552 			if ($$ == NULL)
553 				err(1, "port_item: malloc");
554 			$$->port[0] = $1;
555 			$$->port[1] = $3;
556 			$$->op = $2;
557 			$$->next = NULL;
558 		}
559 		;
560 
561 port		: NUMBER			{
562 			if (0 > $1 || $1 > 65535) {
563 				yyerror("illegal port value %d", $1);
564 				YYERROR;
565 			}
566 			$$ = htons($1);
567 		}
568 		| STRING			{
569 			struct servent *s = NULL;
570 
571 			s = getservbyname($1, "tcp");
572 			if (s == NULL)
573 				s = getservbyname($1, "udp");
574 			if (s == NULL) {
575 				yyerror("unknown protocol %s", $1);
576 				YYERROR;
577 			}
578 			$$ = s->s_port;
579 		}
580 		;
581 
582 flag		: STRING			{
583 			int f;
584 
585 			if ((f = parse_flags($1)) < 0) {
586 				yyerror("bad flags %s", $1);
587 				YYERROR;
588 			}
589 			$$.b1 = f;
590 		}
591 		;
592 
593 flags		: /* empty */			{ $$.b1 = 0; $$.b2 = 0; }
594 		| FLAGS flag			{ $$.b1 = $2.b1; $$.b2 = 63; }
595 		| FLAGS flag "/" flag		{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
596 		| FLAGS "/" flag		{ $$.b1 = 0; $$.b2 = $3.b1; }
597 		;
598 
599 icmpspec	: /* empty */                   { $$ = NULL; }
600 		| ICMPTYPE icmp_item		{ $$ = $2; }
601 		| ICMPTYPE '{' icmp_list '}'	{ $$ = $3; }
602 		| ICMP6TYPE icmp6_item		{ $$ = $2; }
603 		| ICMP6TYPE '{' icmp6_list '}'	{ $$ = $3; }
604 		;
605 
606 icmp_list	: icmp_item			{ $$ = $1; }
607 		| icmp_list ',' icmp_item	{ $3->next = $1; $$ = $3; }
608 		;
609 
610 icmp6_list	: icmp6_item			{ $$ = $1; }
611 		| icmp6_list ',' icmp6_item	{ $3->next = $1; $$ = $3; }
612 		;
613 
614 icmp_item	: icmptype		{
615 			$$ = malloc(sizeof(struct node_icmp));
616 			if ($$ == NULL)
617 				err(1, "icmp_item: malloc");
618 			$$->type = $1;
619 			$$->code = 0;
620 			$$->proto = IPPROTO_ICMP;
621 			$$->next = NULL;
622 		}
623 		| icmptype CODE NUMBER	{
624 			$$ = malloc(sizeof(struct node_icmp));
625 			if ($$ == NULL)
626 				err(1, "icmp_item: malloc");
627 			if ($3 < 0 || $3 > 255) {
628 				yyerror("illegal icmp code %d", $3);
629 				YYERROR;
630 			}
631 			$$->type = $1;
632 			$$->code = $3 + 1;
633 			$$->proto = IPPROTO_ICMP;
634 			$$->next = NULL;
635 		}
636 		| icmptype CODE STRING	{
637 			struct icmpcodeent *p;
638 
639 			$$ = malloc(sizeof(struct node_icmp));
640 			if ($$ == NULL)
641 				err(1, "icmp_item: malloc");
642 			$$->type = $1;
643 			if ((p = geticmpcodebyname($1, $3,
644 			    AF_INET)) == NULL) {
645 				yyerror("unknown icmp-code %s", $3);
646 				YYERROR;
647 			}
648 			$$->code = p->code + 1;
649 			$$->proto = IPPROTO_ICMP;
650 			$$->next = NULL;
651 		}
652 		;
653 
654 icmp6_item	: icmp6type		{
655 			$$ = malloc(sizeof(struct node_icmp));
656 			if ($$ == NULL)
657 				err(1, "icmp_item: malloc");
658 			$$->type = $1;
659 			$$->code = 0;
660 			$$->proto = IPPROTO_ICMPV6;
661 			$$->next = NULL;
662 		}
663 		| icmp6type CODE NUMBER	{
664 			$$ = malloc(sizeof(struct node_icmp));
665 			if ($$ == NULL)
666 				err(1, "icmp_item: malloc");
667 			if ($3 < 0 || $3 > 255) {
668 				yyerror("illegal icmp6 code %d", $3);
669 				YYERROR;
670 			}
671 			$$->type = $1;
672 			$$->code = $3 + 1;
673 			$$->proto = IPPROTO_ICMPV6;
674 			$$->next = NULL;
675 		}
676 		| icmp6type CODE STRING	{
677 			struct icmpcodeent *p;
678 
679 			$$ = malloc(sizeof(struct node_icmp));
680 			if ($$ == NULL)
681 				err(1, "icmp_item: malloc");
682 			$$->type = $1;
683 			if ((p = geticmpcodebyname($1, $3,
684 			    AF_INET6)) == NULL) {
685 				yyerror("unknown icmp6-code %s", $3);
686 				YYERROR;
687 			}
688 			$$->code = p->code + 1;
689 			$$->proto = IPPROTO_ICMPV6;
690 			$$->next = NULL;
691 		}
692 		;
693 
694 icmptype	: STRING			{
695 			struct icmptypeent *p;
696 
697 			if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
698 				yyerror("unknown icmp-type %s", $1);
699 				YYERROR;
700 			}
701 			$$ = p->type + 1;
702 		}
703 		| NUMBER			{
704 			if ($1 < 0 || $1 > 255) {
705 				yyerror("illegal icmp type %d", $1);
706 				YYERROR;
707 			}
708 			$$ = $1 + 1;
709 		}
710 		;
711 
712 icmp6type	: STRING			{
713 			struct icmptypeent *p;
714 
715 			if ((p = geticmptypebyname($1, AF_INET6)) == NULL) {
716 				yyerror("unknown ipv6-icmp-type %s", $1);
717 				YYERROR;
718 			}
719 			$$ = p->type + 1;
720 		}
721 		| NUMBER			{
722 			if ($1 < 0 || $1 > 255) {
723 				yyerror("illegal icmp6 type %d", $1);
724 				YYERROR;
725 			}
726 			$$ = $1 + 1;
727 		}
728 		;
729 
730 keep		: /* empty */			{ $$ = 0; }
731 		| KEEP STATE			{ $$ = PF_STATE_NORMAL; }
732 		| MODULATE STATE		{ $$ = PF_STATE_MODULATE; }
733 		;
734 
735 minttl		: /* empty */			{ $$ = 0; }
736 		| MINTTL NUMBER			{
737 			if ($2 < 0 || $2 > 255) {
738 				yyerror("illegal min-ttl value %d", $2);
739 				YYERROR;
740 			}
741 			$$ = $2;
742 		}
743 		;
744 
745 nodf		: /* empty */			{ $$ = 0; }
746 		| NODF				{ $$ = 1; }
747 		;
748 
749 allowopts	: /* empty */			{ $$ = 0; }
750 		| ALLOWOPTS			{ $$ = 1; }
751 
752 natrule		: NAT interface proto FROM ipspec TO ipspec ARROW address
753 		{
754 			struct pf_nat nat;
755 
756 			if (!natmode) {
757 				yyerror("nat rule not permitted in filter mode");
758 				YYERROR;
759 			}
760 			memset(&nat, 0, sizeof(nat));
761 
762 			if ($2 != NULL) {
763 				memcpy(nat.ifname, $2->ifname,
764 				    sizeof(nat.ifname));
765 				nat.ifnot = $2->not;
766 			}
767 			if ($3 != NULL) {
768 				nat.proto = $3->proto;
769 				free($3);
770 			}
771 			if ($5 != NULL && $7 != NULL && $5->af != $7->af) {
772 				yyerror("nat ip versions must match");
773 				YYERROR;
774 			}
775 			if ($5 != NULL) {
776 				nat.af = $5->af;
777 				memcpy(&nat.saddr, &$5->addr,
778 				    sizeof(nat.saddr));
779 				memcpy(&nat.smask, &$5->mask,
780 				    sizeof(nat.smask));
781 				nat.snot = $5->not;
782 				free($5);
783 			}
784 			if ($7 != NULL) {
785 				nat.af = $7->af;
786 				memcpy(&nat.daddr, &$7->addr,
787 				    sizeof(nat.daddr));
788 				memcpy(&nat.dmask, &$7->mask,
789 				    sizeof(nat.dmask));
790 				nat.dnot = $7->not;
791 				free($7);
792 			}
793 
794 			if ($9 == NULL) {
795 				yyerror("nat rule requires redirection address");
796 				YYERROR;
797 			}
798 			/* we don't support IPv4 <-> IPv6 nat... yet */
799 			if (nat.af && $9->af != nat.af) {
800 				yyerror("nat ip versions must match");
801 				YYERROR;
802 			}
803 			nat.af = $9->af;
804 			memcpy(&nat.raddr, &$9->addr, sizeof(nat.raddr));
805 			free($9);
806 			pfctl_add_nat(pf, &nat);
807 		}
808 		;
809 
810 binatrule	: BINAT interface proto FROM address TO ipspec ARROW address
811 		{
812 			struct pf_binat binat;
813 
814 			if (!natmode) {
815 				yyerror("binat rule not permitted in filter mode");
816 				YYERROR;
817 			}
818 			memset(&binat, 0, sizeof(binat));
819 
820 			if ($2 != NULL) {
821 				memcpy(binat.ifname, $2->ifname,
822 				    sizeof(binat.ifname));
823 			}
824 			if ($3 != NULL) {
825 				binat.proto = $3->proto;
826 				free($3);
827 			}
828 			if ($5 != NULL && $7 != NULL && $5->af != $7->af) {
829 				yyerror("binat ip versions must match");
830 				YYERROR;
831 			}
832 			if ($5 != NULL) {
833 				binat.af = $5->af;
834 				memcpy(&binat.saddr, &$5->addr,
835 				    sizeof(binat.saddr));
836 				free($5);
837 			}
838 			if ($7 != NULL) {
839 				binat.af = $7->af;
840 				memcpy(&binat.daddr, &$7->addr,
841 				    sizeof(binat.daddr));
842 				memcpy(&binat.dmask, &$7->mask,
843 				    sizeof(binat.dmask));
844 				binat.dnot  = $7->not;
845 				free($7);
846 			}
847 
848 			if ($9 == NULL) {
849 				yyerror("binat rule requires redirection address");
850 				YYERROR;
851 			}
852 			/* we don't support IPv4 <-> IPv6 binat... yet */
853 			if (binat.af && $9->af != binat.af) {
854 				yyerror("binat ip versions must match");
855 				YYERROR;
856 			}
857 			binat.af = $9->af;
858 			memcpy(&binat.raddr, &$9->addr, sizeof(binat.raddr));
859 			free($9);
860 			pfctl_add_binat(pf, &binat);
861 		}
862 
863 rdrrule		: RDR interface proto FROM ipspec TO ipspec dport ARROW address rport
864 		{
865 			struct pf_rdr rdr;
866 
867 			if (!natmode) {
868 				yyerror("rdr rule not permitted in filter mode");
869 				YYERROR;
870 			}
871 			memset(&rdr, 0, sizeof(rdr));
872 
873 			if ($2 != NULL) {
874 				memcpy(rdr.ifname, $2->ifname,
875 				    sizeof(rdr.ifname));
876 				rdr.ifnot = $2->not;
877 			}
878 			if ($3 != NULL) {
879 				rdr.proto = $3->proto;
880 				free($3);
881 			}
882 			if ($5 != NULL && $7 != NULL && $5->af != $7->af) {
883 				yyerror("rdr ip versions must match");
884 				YYERROR;
885 			}
886 			if ($5 != NULL) {
887 				rdr.af = $5->af;
888 				memcpy(&rdr.saddr, &$5->addr,
889 				    sizeof(rdr.saddr));
890 				memcpy(&rdr.smask, &$5->mask,
891 				    sizeof(rdr.smask));
892 				rdr.snot  = $5->not;
893 				free($5);
894 			}
895 			if ($7 != NULL) {
896 				rdr.af = $7->af;
897 				memcpy(&rdr.daddr, &$7->addr,
898 				    sizeof(rdr.daddr));
899 				memcpy(&rdr.dmask, &$7->mask,
900 				    sizeof(rdr.dmask));
901 				rdr.dnot  = $7->not;
902 				free($7);
903 			}
904 
905 			rdr.dport  = $8.a;
906 			rdr.dport2 = $8.b;
907 			rdr.opts  |= $8.t;
908 
909 			if ($10 == NULL) {
910 				yyerror("rdr rule requires redirection address");
911 				YYERROR;
912 			}
913 			if (rdr.af && $10->af != rdr.af) {
914 				yyerror("rdr ip versions must match");
915 				YYERROR;
916 			}
917 			rdr.af = $10->af;
918 			memcpy(&rdr.raddr, &$10->addr, sizeof(rdr.raddr));
919 			free($10);
920 
921 			rdr.rport  = $11.a;
922 			rdr.opts  |= $11.t;
923 
924 			if (rdr.proto && rdr.proto != IPPROTO_TCP &&
925 			    rdr.proto != IPPROTO_UDP &&
926 			    (rdr.dport || rdr.dport2 || rdr.rport)) {
927 				yyerror("rdr ports are only valid for proto tcp/udp");
928 				YYERROR;
929 			}
930 
931 			pfctl_add_rdr(pf, &rdr);
932 		}
933 		;
934 
935 dport		: /* empty */			{
936 			$$.a = $$.b = $$.t = 0;
937 		}
938 		| PORT port			{
939 			$$.a = $2;
940 			$$.b = $$.t = 0;
941 		}
942 		| PORT port ':' port		{
943 			$$.a = $2;
944 			$$.b = $4;
945 			$$.t = PF_DPORT_RANGE;
946 		}
947 		;
948 
949 rport		: /* empty */			{
950 			$$.a = $$.b = $$.t = 0;
951 		}
952 		| PORT port			{
953 			$$.a = $2;
954 			$$.b = $$.t = 0;
955 		}
956 		| PORT port ':' '*'		{
957 			$$.a = $2;
958 			$$.b = 0;
959 			$$.t = PF_RPORT_RANGE;
960 		}
961 		;
962 
963 route		: /* empty */			{
964 			$$.string = NULL;
965 			$$.rt = 0;
966 			$$.addr = NULL;
967 			$$.af = 0;
968 		}
969 		| FASTROUTE {
970 			$$.string = NULL;
971 			$$.rt = PF_FASTROUTE;
972 			$$.addr = NULL;
973 		}
974 		| ROUTETO STRING ':' address {
975 			$$.string = strdup($2);
976 			$$.rt = PF_ROUTETO;
977 			$$.addr = &$4->addr;
978 			$$.af = $4->af;
979 		}
980 		| ROUTETO STRING 		{
981 			$$.string = strdup($2);
982 			$$.rt = PF_ROUTETO;
983 			$$.addr = NULL;
984 		}
985 		| DUPTO STRING ':' address {
986 			$$.string = strdup($2);
987 			$$.rt = PF_DUPTO;
988 			$$.addr = &$4->addr;
989 			$$.af = $4->af;
990 		}
991 		| DUPTO STRING 		{
992 			$$.string = strdup($2);
993 			$$.rt = PF_DUPTO;
994 			$$.addr = NULL;
995 		}
996 		;
997 %%
998 
999 int
1000 yyerror(char *fmt, ...)
1001 {
1002 	va_list ap;
1003 	extern char *infile;
1004 	errors = 1;
1005 
1006 	va_start(ap, fmt);
1007 	fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
1008 	vfprintf(stderr, fmt, ap);
1009 	fprintf(stderr, "\n");
1010 	va_end(ap);
1011 	return (0);
1012 }
1013 
1014 int
1015 rule_consistent(struct pf_rule *r)
1016 {
1017 	int problems = 0;
1018 
1019 	if (r->action == PF_SCRUB) {
1020 		if (r->quick) {
1021 			yyerror("quick does not apply to scrub");
1022 			problems++;
1023 		}
1024 		if (r->keep_state == PF_STATE_MODULATE) {
1025 			yyerror("modulate state does not apply to scrub");
1026 			problems++;
1027 		}
1028 		if (r->keep_state == PF_STATE_NORMAL) {
1029 			yyerror("keep state does not apply to scrub");
1030 			problems++;
1031 		}
1032 		if (r->src.port_op) {
1033 			yyerror("src port does not apply to scrub");
1034 			problems++;
1035 		}
1036 		if (r->dst.port_op) {
1037 			yyerror("dst port does not apply to scrub");
1038 			problems++;
1039 		}
1040 		if (r->type || r->code) {
1041 			yyerror("icmp-type/code does not apply to scrub");
1042 			problems++;
1043 		}
1044 	} else {
1045 		if (r->rule_flag & PFRULE_NODF) {
1046 			yyerror("nodf only applies to scrub");
1047 			problems++;
1048 		}
1049 		if (r->min_ttl) {
1050 			yyerror("min-ttl only applies to scrub");
1051 			problems++;
1052 		}
1053 	}
1054 	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
1055 	    (r->src.port_op || r->dst.port_op)) {
1056 		yyerror("port only applies to tcp/udp");
1057 		problems++;
1058 	}
1059 	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
1060 	    (r->type || r->code)) {
1061 		yyerror("icmp-type/code only applies to icmp");
1062 		problems++;
1063 	}
1064 	if (!r->af && (r->type || r->code)) {
1065 		yyerror("must indicate address family with icmp-type/code");
1066 		problems++;
1067 	}
1068 	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
1069 	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
1070 		yyerror("icmp version does not match address family");
1071 		problems++;
1072 	}
1073 	if (!(r->rule_flag & PFRULE_RETURNRST) && r->return_icmp &&
1074 	    ((r->af != AF_INET6  &&  (r->return_icmp>>8) != ICMP_UNREACH) ||
1075 	    (r->af == AF_INET6 && (r->return_icmp>>8) != ICMP6_DST_UNREACH))) {
1076 		yyerror("return-icmp version does not match address family");
1077 		problems++;
1078 	}
1079 	if (r->keep_state == PF_STATE_MODULATE && r->proto &&
1080 	    r->proto != IPPROTO_TCP) {
1081 		yyerror("modulate state can only be applied to TCP rules");
1082 		problems++;
1083 	}
1084 	if (r->allow_opts && r->action != PF_PASS) {
1085 		yyerror("allow-opts can only be specified for pass rules");
1086 		problems++;
1087 	}
1088 	return (-problems);
1089 }
1090 
1091 #define CHECK_ROOT(T,r) \
1092 	do { \
1093 		if (r == NULL) { \
1094 			r = malloc(sizeof(T)); \
1095 			if (r == NULL) \
1096 				err(1, "malloc"); \
1097 			memset(r, 0, sizeof(T)); \
1098 		} \
1099 	} while (0)
1100 
1101 #define FREE_LIST(T,r) \
1102 	do { \
1103 		T *p, *n = r; \
1104 		while (n != NULL) { \
1105 			p = n; \
1106 			n = n->next; \
1107 			free(p); \
1108 		} \
1109 	} while (0)
1110 
1111 void expand_rule_hosts(struct pf_rule *r,
1112     struct node_if *interface, struct node_proto *proto,
1113     struct node_host *src_hosts, struct node_port *src_ports,
1114     struct node_host *dst_hosts, struct node_port *dst_ports,
1115     struct node_icmp *icmp_type)
1116 {
1117 	struct node_host *src_host, *dst_host;
1118 	struct node_port *src_port, *dst_port;
1119 	int nomatch = 0;
1120 
1121 	src_host = src_hosts;
1122 	while (src_host != NULL) {
1123 		src_port = src_ports;
1124 		while (src_port != NULL) {
1125 			dst_host = dst_hosts;
1126 			while (dst_host != NULL) {
1127 				dst_port = dst_ports;
1128 				while (dst_port != NULL) {
1129 					memcpy(r->ifname, interface->ifname,
1130 					  sizeof(r->ifname));
1131 					r->proto = proto->proto;
1132 					r->src.addr = src_host->addr;
1133 					r->src.mask = src_host->mask;
1134 					r->src.not = src_host->not;
1135 					r->src.port[0] = src_port->port[0];
1136 					r->src.port[1] = src_port->port[1];
1137 					r->src.port_op = src_port->op;
1138 					r->dst.addr = dst_host->addr;
1139 					r->dst.mask = dst_host->mask;
1140 					r->dst.not = dst_host->not;
1141 					r->dst.port[0] = dst_port->port[0];
1142 					r->dst.port[1] = dst_port->port[1];
1143 					r->dst.port_op = dst_port->op;
1144 					r->type = icmp_type->type;
1145 					r->code = icmp_type->code;
1146 
1147 					if ((src_host->af && dst_host->af &&
1148 						r->af) && (src_host->af !=
1149 						    dst_host->af ||
1150 						    src_host->af != r->af ||
1151 						    dst_host->af != r->af)) {
1152 						yyerror("address family"
1153 						    " mismatch");
1154 						nomatch++;
1155 					} else if ((src_host->af &&
1156 						       dst_host->af) &&
1157 					    (src_host->af != dst_host->af)) {
1158 						yyerror("address family"
1159 						    " mismatch");
1160 						nomatch++;
1161 					} else if ((src_host->af && r->af) &&
1162 					    (src_host->af != r->af)) {
1163 						yyerror("address family"
1164 						    " mismatch");
1165 						nomatch++;
1166 					} else if ((dst_host->af && r->af) &&
1167 					    (dst_host->af != r->af)) {
1168 						yyerror("address family"
1169 						    " mismatch");
1170 						nomatch++;
1171 					} else if (src_host->af && !r->af) {
1172 						r->af = src_host->af;
1173 					} else if (dst_host->af && !r->af) {
1174 						r->af= dst_host->af;
1175 					}
1176 
1177 					if (icmp_type->proto &&
1178 					    r->proto != icmp_type->proto) {
1179 						yyerror("icmp-type mismatch");
1180 						nomatch++;
1181 					}
1182 
1183 					if (rule_consistent(r) < 0 || nomatch)
1184 						yyerror("skipping rule "
1185 						    "due to errors");
1186 					else
1187 						pfctl_add_rule(pf, r);
1188 					dst_port = dst_port->next;
1189 				}
1190 				dst_host = dst_host->next;
1191 			}
1192 			src_port = src_port->next;
1193 		}
1194 		src_host = src_host->next;
1195 	}
1196 }
1197 
1198 void expand_rule_protos(struct pf_rule *r,
1199     struct node_if *interface, struct node_proto *protos,
1200     struct node_host *src_hosts, struct node_port *src_ports,
1201     struct node_host *dst_hosts, struct node_port *dst_ports,
1202     struct node_icmp *icmp_types)
1203 {
1204 	struct node_proto *proto;
1205 	struct node_icmp *icmp_type;
1206 
1207 	proto = protos;
1208 	while (proto != NULL) {
1209 		icmp_type = icmp_types;
1210 		while (icmp_type != NULL) {
1211 			expand_rule_hosts(r, interface, proto, src_hosts,
1212 			    src_ports, dst_hosts, dst_ports, icmp_type);
1213 			icmp_type = icmp_type->next;
1214 		}
1215 		proto = proto->next;
1216 	}
1217 }
1218 
1219 void
1220 expand_rule(struct pf_rule *r,
1221     struct node_if *interfaces, struct node_proto *protos,
1222     struct node_host *src_hosts, struct node_port *src_ports,
1223     struct node_host *dst_hosts, struct node_port *dst_ports,
1224     struct node_icmp *icmp_types)
1225 {
1226 	struct node_if *interface;
1227 
1228 	CHECK_ROOT(struct node_if, interfaces);
1229 	CHECK_ROOT(struct node_proto, protos);
1230 	CHECK_ROOT(struct node_host, src_hosts);
1231 	CHECK_ROOT(struct node_port, src_ports);
1232 	CHECK_ROOT(struct node_host, dst_hosts);
1233 	CHECK_ROOT(struct node_port, dst_ports);
1234 	CHECK_ROOT(struct node_icmp, icmp_types);
1235 
1236 	interface = interfaces;
1237 	while (interface != NULL) {
1238 		expand_rule_protos(r, interface, protos, src_hosts,
1239 		    src_ports, dst_hosts, dst_ports, icmp_types);
1240 		interface = interface->next;
1241 	}
1242 
1243 	FREE_LIST(struct node_if, interfaces);
1244 	FREE_LIST(struct node_proto, protos);
1245 	FREE_LIST(struct node_host, src_hosts);
1246 	FREE_LIST(struct node_port, src_ports);
1247 	FREE_LIST(struct node_host, dst_hosts);
1248 	FREE_LIST(struct node_port, dst_ports);
1249 	FREE_LIST(struct node_icmp, icmp_types);
1250 
1251 }
1252 
1253 #undef FREE_LIST
1254 #undef CHECK_ROOT
1255 
1256 int
1257 lookup(char *s)
1258 {
1259 	int i;
1260 	struct keywords {
1261 		char	*k_name;
1262 		int	 k_val;
1263 	} keywords[] = {
1264 		{ "all",	ALL},
1265 		{ "allow-opts",	ALLOWOPTS},
1266 		{ "any",	ANY},
1267 		{ "binat",	BINAT},
1268 		{ "block",	BLOCK},
1269 		{ "code",	CODE},
1270 		{ "dup-to",	DUPTO},
1271 		{ "flags",	FLAGS},
1272 		{ "fastroute",	FASTROUTE},
1273 		{ "from",	FROM},
1274 		{ "icmp-type",	ICMPTYPE},
1275 		{ "ipv6-icmp-type", ICMP6TYPE},
1276 		{ "in",		IN},
1277 		{ "inet",	INET},
1278 		{ "inet6",	INET6},
1279 		{ "keep",	KEEP},
1280 		{ "log",	LOG},
1281 		{ "log-all",	LOGALL},
1282 		{ "min-ttl",	MINTTL},
1283 		{ "modulate",	MODULATE},
1284 		{ "nat",	NAT},
1285 		{ "no-df",	NODF},
1286 		{ "on",		ON},
1287 		{ "out",	OUT},
1288 		{ "pass",	PASS},
1289 		{ "port",	PORT},
1290 		{ "proto",	PROTO},
1291 		{ "quick",	QUICK},
1292 		{ "rdr",	RDR},
1293 		{ "return",	RETURN},
1294 		{ "return-icmp",RETURNICMP},
1295 		{ "return-icmp6",RETURNICMP6},
1296 		{ "return-rst",	RETURNRST},
1297 		{ "route-to",	ROUTETO},
1298 		{ "scrub",	SCRUB},
1299 		{ "state",	STATE},
1300 		{ "to",		TO},
1301 		{ NULL,		0 },
1302 	};
1303 
1304 	for (i = 0; keywords[i].k_name != NULL; i++) {
1305 		if (strcmp(s, keywords[i].k_name) == 0) {
1306 			if (debug > 1)
1307 				fprintf(stderr, "%s: %d\n", s,
1308 				    keywords[i].k_val);
1309 			return (keywords[i].k_val);
1310 		}
1311 	}
1312 	if (debug > 1)
1313 		fprintf(stderr, "string: %s\n", s);
1314 	return (STRING);
1315 }
1316 
1317 char	*parsebuf;
1318 int	parseindex;
1319 
1320 int
1321 lgetc(FILE *fin)
1322 {
1323 	int c, next;
1324 
1325 restart:
1326 	if (parsebuf) {
1327 		/* Reading characters from the parse buffer, instead of input */
1328 		c = parsebuf[parseindex++];
1329 		if (c != '\0')
1330 			return (c);
1331 		free(parsebuf);
1332 		parsebuf = NULL;
1333 		parseindex = 0;
1334 		goto restart;
1335 	}
1336 
1337 	c = getc(fin);
1338 	if (c == '\\') {
1339 		next = getc(fin);
1340 		if (next != '\n') {
1341 			ungetc(next, fin);
1342 			return (c);
1343 		}
1344 		yylval.lineno = lineno;
1345 		lineno++;
1346 		goto restart;
1347 	}
1348 	return (c);
1349 }
1350 
1351 int
1352 lungetc(int c, FILE *fin)
1353 {
1354 	if (parsebuf && parseindex) {
1355 		/* XXX breaks on index 0 */
1356 		parseindex--;
1357 		return (c);
1358 	}
1359 	return ungetc(c, fin);
1360 }
1361 
1362 int
1363 findeol()
1364 {
1365 	int c;
1366 
1367 	if (parsebuf) {
1368 		free(parsebuf);
1369 		parsebuf = NULL;
1370 		parseindex = 0;
1371 	}
1372 
1373 	/* skip to either EOF or the first real EOL */
1374 	while (1) {
1375 		c = lgetc(fin);
1376 		if (c == '\\') {
1377 			c = lgetc(fin);
1378 			if (c == '\n')
1379 				continue;
1380 		}
1381 		if (c == EOF || c == '\n')
1382 			break;
1383 	}
1384 	return (ERROR);
1385 }
1386 
1387 int
1388 yylex(void)
1389 {
1390 	char buf[8096], *p, *val;
1391 	int endc, c, next;
1392 	int token;
1393 
1394 top:
1395 	p = buf;
1396 	while ((c = lgetc(fin)) == ' ' || c == '\t')
1397 		;
1398 
1399 	yylval.lineno = lineno;
1400 	if (c == '#')
1401 		while ((c = lgetc(fin)) != '\n' && c != EOF)
1402 			;
1403 	if (c == '$' && parsebuf == NULL) {
1404 		while (1) {
1405 			if ((c = lgetc(fin)) == EOF)
1406 				return (0);
1407 			if (p + 1 >= buf + sizeof(buf) - 1) {
1408 				yyerror("string too long");
1409 				return (findeol());
1410 			}
1411 			if (isalnum(c) || c == '_') {
1412 				*p++ = (char)c;
1413 				continue;
1414 			}
1415 			*p = '\0';
1416 			lungetc(c, fin);
1417 			break;
1418 		}
1419 		val = symget(buf);
1420 		if (val == NULL)
1421 			return (ERROR);
1422 		parsebuf = strdup(val);
1423 		if (parsebuf == NULL)
1424 			err(1, "parsebuf: strdup");
1425 		parseindex = 0;
1426 		goto top;
1427 	}
1428 
1429 	switch (c) {
1430 	case '\'':
1431 	case '"':
1432 		endc = c;
1433 		while (1) {
1434 			if ((c = lgetc(fin)) == EOF)
1435 				return (0);
1436 			if (c == endc) {
1437 				*p = '\0';
1438 				break;
1439 			}
1440 			if (c == '\n')
1441 				continue;
1442 			if (p + 1 >= buf + sizeof(buf) - 1) {
1443 				yyerror("string too long");
1444 				return (findeol());
1445 			}
1446 			*p++ = (char)c;
1447 		}
1448 		yylval.v.string = strdup(buf);
1449 		if (yylval.v.string == NULL)
1450 			err(1, "yylex: strdup");
1451 		return (STRING);
1452 	case '=':
1453 		yylval.v.i = PF_OP_EQ;
1454 		return (PORTUNARY);
1455 	case '!':
1456 		next = lgetc(fin);
1457 		if (next == '=') {
1458 			yylval.v.i = PF_OP_NE;
1459 			return (PORTUNARY);
1460 		}
1461 		lungetc(next, fin);
1462 		break;
1463 	case '<':
1464 		next = lgetc(fin);
1465 		if (next == '>') {
1466 			yylval.v.i = PF_OP_XRG;
1467 			return (PORTBINARY);
1468 		} else  if (next == '=') {
1469 			yylval.v.i = PF_OP_LE;
1470 		} else {
1471 			yylval.v.i = PF_OP_LT;
1472 			lungetc(next, fin);
1473 		}
1474 		return (PORTUNARY);
1475 		break;
1476 	case '>':
1477 		next = lgetc(fin);
1478 		if (next == '<') {
1479 			yylval.v.i = PF_OP_IRG;
1480 			return (PORTBINARY);
1481 		} else  if (next == '=') {
1482 			yylval.v.i = PF_OP_GE;
1483 		} else {
1484 			yylval.v.i = PF_OP_GT;
1485 			lungetc(next, fin);
1486 		}
1487 		return (PORTUNARY);
1488 		break;
1489 	case '-':
1490 		next = lgetc(fin);
1491 		if (next == '>')
1492 			return (ARROW);
1493 		lungetc(next, fin);
1494 		break;
1495 	}
1496 
1497         /* Need to parse v6 addresses before tokenizing numbers. ick */
1498         if (isxdigit(c) || c == ':') {
1499                 struct node_host *node = NULL;
1500 		u_int32_t addr[4];
1501 		char lookahead[46];
1502                 int i = 0, notv6addr = 0;
1503 
1504 		lookahead[i] = c;
1505 
1506 		while (i < sizeof(lookahead) &&
1507 		    (isxdigit(c) || c == ':' || c == '.')) {
1508 			 	lookahead[++i] = c = lgetc(fin);
1509 		}
1510 
1511 		/* quick check avoids calling inet_pton too often */
1512 		if (isalnum(c)) {
1513 			notv6addr++;
1514 		}
1515 		lungetc(lookahead[i], fin);
1516 		lookahead[i] = '\0';
1517 
1518 		if(!notv6addr && inet_pton(AF_INET6, lookahead, &addr) == 1) {
1519 			node = calloc(1, sizeof(struct node_host));
1520 			node->af = AF_INET6;
1521 			memcpy (&node->addr, &addr, sizeof(addr));
1522                 	yylval.v.host = node;
1523                 	return IPV6ADDR;
1524 		} else {
1525                 	free(node);
1526                 	while (i > 1) {
1527                         	lungetc(lookahead[--i], fin);
1528 			}
1529 			c = lookahead[--i];
1530 		}
1531         }
1532 
1533 	if (isdigit(c)) {
1534 		int index = 0, base = 10;
1535 		u_int64_t n = 0;
1536 
1537 		yylval.v.number = 0;
1538 		while (1) {
1539 			if (base == 10) {
1540 				if (!isdigit(c))
1541 					break;
1542 				c -= '0';
1543 			} else if (base == 16) {
1544 				if (isdigit(c))
1545 					c -= '0';
1546 				else if (c >= 'a' && c <= 'f')
1547 					c -= 'a' - 10;
1548 				else if (c >= 'A' && c <= 'F')
1549 					c -= 'A' - 10;
1550 				else
1551 					break;
1552 			}
1553 			n = n * base + c;
1554 
1555 			if (n > UINT_MAX) {
1556 				yyerror("number is too large");
1557 				return (ERROR);
1558 			}
1559 			c = lgetc(fin);
1560 			if (c == EOF)
1561 				break;
1562 			if (index++ == 0 && n == 0 && c == 'x') {
1563 				base = 16;
1564 				c = lgetc(fin);
1565 				if (c == EOF)
1566 					break;
1567 			}
1568 		}
1569 		yylval.v.number = (u_int32_t)n;
1570 
1571 		if (c != EOF)
1572 			lungetc(c, fin);
1573 		if (debug > 1)
1574 			fprintf(stderr, "number: %d\n", yylval.v.number);
1575 		return (NUMBER);
1576 	}
1577 
1578 #define allowed_in_string(x) \
1579 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1580 	x != '{' && x != '}' && x != '<' && x != '>' && \
1581 	x != '!' && x != '=' && x != '/' && x != '#' && x != ',' && x != ':'))
1582 
1583 	if (isalnum(c)) {
1584 		do {
1585 			*p++ = c;
1586 			if (p-buf >= sizeof buf) {
1587 				yyerror("string too long");
1588 				return (ERROR);
1589 			}
1590 		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
1591 		lungetc(c, fin);
1592 		*p = '\0';
1593 		token = lookup(buf);
1594 		yylval.v.string = strdup(buf);
1595 		if (yylval.v.string == NULL)
1596 			err(1, "yylex: strdup");
1597 		return (token);
1598 	}
1599 	if (c == '\n') {
1600 		yylval.lineno = lineno;
1601 		lineno++;
1602 	}
1603 	if (c == EOF)
1604 		return (0);
1605 	return (c);
1606 }
1607 
1608 int
1609 parse_rules(FILE *input, struct pfctl *xpf)
1610 {
1611 	natmode = 0;
1612 	fin = input;
1613 	pf = xpf;
1614 	errors = 0;
1615 	yyparse();
1616 	return (errors ? -1 : 0);
1617 }
1618 
1619 int
1620 parse_nat(FILE *input, struct pfctl *xpf)
1621 {
1622 	natmode = 1;
1623 	fin = input;
1624 	pf = xpf;
1625 	errors = 0;
1626 	yyparse();
1627 	return (errors ? -1 : 0);
1628 }
1629 
1630 void
1631 ipmask(struct pf_addr *m, u_int8_t b, int af)
1632 {
1633 	int i, j = 0;
1634 
1635 	while (b >= 32) {
1636 		m->addr32[j++] = 0xffffffff;
1637 		b -= 32;
1638 	}
1639 	for (i = 31; i > 31-b; --i)
1640 		m->addr32[j] |= (1 << i);
1641 	if (b)
1642 		m->addr32[j] = htonl(m->addr32[j]);
1643 }
1644 
1645 struct pf_rule_addr *
1646 new_addr(void)
1647 {
1648 	struct pf_rule_addr *ra;
1649 
1650 	ra = malloc(sizeof(struct pf_rule_addr));
1651 	if (ra == NULL)
1652 		err(1, "new_addr: malloc failed");
1653 	memset(ra, 0, sizeof(*ra));
1654 	return (ra);
1655 }
1656 
1657 /*
1658  * Over-designed efficiency is a French and German concept, so how about
1659  * we wait until they discover this ugliness and make it all fancy.
1660  */
1661 int
1662 symset(char *nam, char *val)
1663 {
1664 	struct sym *sym;
1665 
1666 	sym = calloc(1, sizeof(*sym));
1667 	if (sym == NULL)
1668 		return (-1);
1669 	sym->nam = strdup(nam);
1670 	if (sym->nam == NULL) {
1671 		free(sym);
1672 		return (-1);
1673 	}
1674 	sym->val = strdup(val);
1675 	if (sym->val == NULL) {
1676 		free(sym->nam);
1677 		free(sym);
1678 		return (-1);
1679 	}
1680 	sym->next = symhead;
1681 	symhead = sym;
1682 	return (0);
1683 }
1684 
1685 char *
1686 symget(char *nam)
1687 {
1688 	struct sym *sym;
1689 
1690 	for (sym = symhead; sym; sym = sym->next)
1691 		if (strcmp(nam, sym->nam) == 0)
1692 			return (sym->val);
1693 	return (NULL);
1694 }
1695 
1696 struct ifaddrs **ifa0tab, **ifa4tab, **ifa6tab;
1697 int ifa0len, ifa4len, ifa6len;
1698 
1699 int
1700 ifa_comp(const void *p1, const void *p2)
1701 {
1702 	struct ifaddrs *ifa1 = *(struct ifaddrs **)p1;
1703 	struct ifaddrs *ifa2 = *(struct ifaddrs **)p2;
1704 
1705 	return strcmp(ifa1->ifa_name, ifa2->ifa_name);
1706 }
1707 
1708 void
1709 ifa_load(void)
1710 {
1711 	struct ifaddrs *ifap, *ifa;
1712 	int ifalen = 0;
1713 
1714 	if (getifaddrs(&ifap) < 0)
1715 		err(1, "getifaddrs");
1716 	for (ifa = ifap; ifa; ifa = ifa->ifa_next)
1717 		ifalen++;
1718 	/* (over-)allocate tables */
1719 	ifa0tab = malloc(ifalen * sizeof(void *));
1720 	ifa4tab = malloc(ifalen * sizeof(void *));
1721 	ifa6tab = malloc(ifalen * sizeof(void *));
1722 	if (!ifa0tab || !ifa4tab || !ifa6tab)
1723 		err(1, "malloc");
1724 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1725 		if (ifa->ifa_addr->sa_family == AF_LINK) {
1726 			if (bsearch(&ifa, ifa0tab, ifa0len, sizeof(void *),
1727 			    ifa_comp))
1728 				continue; /* take only the first LINK address */
1729 			ifa0tab[ifa0len++] = ifa;
1730 			qsort(ifa0tab, ifa0len, sizeof(void *), ifa_comp);
1731 		}
1732 		if (ifa->ifa_addr->sa_family == AF_INET) {
1733 			if (bsearch(&ifa, ifa4tab, ifa4len, sizeof(void *),
1734 			    ifa_comp))
1735 				continue; /* take only the first IPv4 address */
1736 			ifa4tab[ifa4len++] = ifa;
1737 			qsort(ifa4tab, ifa4len, sizeof(void *), ifa_comp);
1738 		}
1739 		if (ifa->ifa_addr->sa_family == AF_INET6) {
1740 			/* XXX - better address selection required! */
1741 			if (bsearch(&ifa, ifa6tab, ifa6len, sizeof(void *),
1742 			    ifa_comp))
1743 				continue; /* take only the first IPv6 address */
1744 			ifa6tab[ifa6len++] = ifa;
1745 			qsort(ifa6tab, ifa6len, sizeof(void *), ifa_comp);
1746 		}
1747 	}
1748 	/* shrink tables */
1749 	ifa0tab = realloc(ifa0tab, ifa0len * sizeof(void *));
1750 	ifa4tab = realloc(ifa4tab, ifa4len * sizeof(void *));
1751 	ifa6tab = realloc(ifa6tab, ifa6len * sizeof(void *));
1752 	if (!ifa0tab || !ifa4tab || !ifa6tab)
1753 		err(1, "realloc");
1754 }
1755 
1756 struct ifaddrs *
1757 ifa0_lookup(char *ifa_name)
1758 {
1759 	struct ifaddrs ifa, *ifp = &ifa, **ifpp;
1760 
1761 	if (!ifa0tab)
1762 		ifa_load();
1763 	ifa.ifa_name = ifa_name;
1764 	ifpp = bsearch(&ifp, ifa0tab, ifa0len, sizeof(void *), ifa_comp);
1765 	return ifpp ? *ifpp : NULL;
1766 }
1767 
1768 struct ifaddrs *
1769 ifa4_lookup(char *ifa_name)
1770 {
1771 	struct ifaddrs ifa, *ifp = &ifa, **ifpp;
1772 
1773 	if (!ifa4tab)
1774 		ifa_load();
1775 	ifa.ifa_name = ifa_name;
1776 	ifpp = bsearch(&ifp, ifa4tab, ifa4len, sizeof(void *), ifa_comp);
1777 	return ifpp ? *ifpp : NULL;
1778 }
1779 
1780 struct ifaddrs *
1781 ifa6_lookup(char *ifa_name)
1782 {
1783 	struct ifaddrs ifa, *ifp = &ifa, **ifpp;
1784 
1785 	if (!ifa6tab)
1786 		ifa_load();
1787 	ifa.ifa_name = ifa_name;
1788 	ifpp = bsearch(&ifp, ifa6tab, ifa6len, sizeof(void *), ifa_comp);
1789 	return ifpp ? *ifpp : NULL;
1790 }
1791 
1792