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