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