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