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