parse.y revision 1.225
1/*	$OpenBSD: parse.y,v 1.225 2002/11/28 14:43:39 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#include <md5.h>
52
53#include "pfctl_parser.h"
54#include "pfctl_altq.h"
55
56static struct pfctl *pf = NULL;
57static FILE *fin = NULL;
58static int debug = 0;
59static int lineno = 1;
60static int errors = 0;
61static int rulestate = 0;
62static u_int16_t returnicmpdefault =  (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
63static u_int16_t returnicmp6default = (ICMP6_DST_UNREACH << 8) |
64    ICMP6_DST_UNREACH_NOPORT;
65static int blockpolicy = PFRULE_DROP;
66static int require_order = 1;
67
68enum {
69	PFCTL_STATE_NONE = 0,
70	PFCTL_STATE_OPTION = 1,
71	PFCTL_STATE_SCRUB = 2,
72	PFCTL_STATE_QUEUE = 3,
73	PFCTL_STATE_NAT = 4,
74	PFCTL_STATE_FILTER = 5
75};
76
77enum pfctl_iflookup_mode {
78	PFCTL_IFLOOKUP_HOST = 0,
79	PFCTL_IFLOOKUP_NET = 1,
80	PFCTL_IFLOOKUP_BCAST = 2
81};
82
83struct node_if {
84	char			 ifname[IFNAMSIZ];
85	u_int8_t		 not;
86	u_int			 ifa_flags;
87	struct node_if		*next;
88	struct node_if		*tail;
89};
90
91struct node_proto {
92	u_int8_t		 proto;
93	struct node_proto	*next;
94	struct node_proto	*tail;
95};
96
97struct node_host {
98	struct pf_addr_wrap	 addr;
99	struct pf_addr		 bcast;
100	sa_family_t		 af;
101	u_int8_t		 not;
102	u_int8_t		 noroute;
103	u_int32_t		 ifindex;	/* link-local IPv6 addrs */
104	char			*ifname;
105	u_int			 ifa_flags;
106	struct node_host	*next;
107	struct node_host	*tail;
108};
109
110struct node_port {
111	u_int16_t		 port[2];
112	u_int8_t		 op;
113	struct node_port	*next;
114	struct node_port	*tail;
115};
116
117struct node_uid {
118	uid_t			 uid[2];
119	u_int8_t		 op;
120	struct node_uid		*next;
121	struct node_uid		*tail;
122};
123
124struct node_gid {
125	gid_t			 gid[2];
126	u_int8_t		 op;
127	struct node_gid		*next;
128	struct node_gid		*tail;
129};
130
131struct node_icmp {
132	u_int8_t		 code;
133	u_int8_t		 type;
134	u_int8_t		 proto;
135	struct node_icmp	*next;
136	struct node_icmp	*tail;
137};
138
139enum	{ PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 };
140struct node_state_opt {
141	int			 type;
142	union {
143		u_int32_t	 max_states;
144		struct {
145			int		number;
146			u_int32_t	seconds;
147		}		 timeout;
148	}			 data;
149	struct node_state_opt	*next;
150	struct node_state_opt	*tail;
151};
152
153struct peer {
154	struct node_host	*host;
155	struct node_port	*port;
156};
157
158struct node_queue {
159	char			 queue[PF_QNAME_SIZE];
160	char			 parent[PF_QNAME_SIZE];
161	char			 ifname[IFNAMSIZ];
162	struct node_queue	*next;
163	struct node_queue	*tail;
164}	*queues = NULL;
165
166struct node_queue_opt {
167	int			 qtype;
168	union {	/* options for other schedulers will follow */
169		struct cbq_opts		 cbq_opts;
170	}			 data;
171};
172
173struct node_queue_bw {
174	u_int32_t	bw_absolute;
175	u_int16_t	bw_percent;
176};
177
178int	yyerror(char *, ...);
179int	rule_consistent(struct pf_rule *);
180int	nat_consistent(struct pf_nat *);
181int	rdr_consistent(struct pf_rdr *);
182int	yyparse(void);
183void	set_ipmask(struct node_host *, u_int8_t);
184void	expand_rdr(struct pf_rdr *, struct node_if *, struct node_proto *,
185	    struct node_host *, struct node_host *, struct node_host *);
186void	expand_nat(struct pf_nat *, struct node_if *, struct node_proto *,
187	    struct node_host *, struct node_port *,
188	    struct node_host *, struct node_port *, struct node_host *);
189void	expand_label_if(const char *, char *, const char *);
190void	expand_label_addr(const char *, char *, u_int8_t, struct node_host *);
191void	expand_label_port(const char *, char *, struct node_port *);
192void	expand_label_proto(const char *, char *, u_int8_t);
193void	expand_label_nr(const char *, char *);
194void	expand_label(char *, const char *, u_int8_t, struct node_host *,
195	    struct node_port *, struct node_host *, struct node_port *,
196	    u_int8_t);
197void	expand_rule(struct pf_rule *, struct node_if *, struct node_host *,
198	    struct node_proto *, struct node_host *, struct node_port *,
199	    struct node_host *, struct node_port *, struct node_uid *,
200	    struct node_gid *, struct node_icmp *);
201int	expand_altq(struct pf_altq *, struct node_if *, struct node_queue *);
202int	expand_queue(struct pf_altq *, struct node_queue *,
203	    struct node_queue_bw);
204int	check_rulestate(int);
205int	kw_cmp(const void *, const void *);
206int	lookup(char *);
207int	lgetc(FILE *);
208int	lungetc(int, FILE *);
209int	findeol(void);
210int	yylex(void);
211struct	node_host *host(char *, int);
212int	atoul(char *, u_long *);
213int	getservice(char *);
214
215struct sym {
216	struct sym *next;
217	int used;
218	char *nam;
219	char *val;
220};
221struct sym *symhead = NULL;
222
223int	symset(const char *, const char *);
224char *	symget(const char *);
225
226void	ifa_load(void);
227struct	node_host *ifa_exists(char *);
228struct	node_host *ifa_lookup(char *, enum pfctl_iflookup_mode);
229void	decide_address_family(struct node_host *, sa_family_t *);
230void	remove_invalid_hosts(struct node_host **, sa_family_t *);
231u_int16_t	parseicmpspec(char *, sa_family_t);
232
233typedef struct {
234	union {
235		u_int32_t		number;
236		int			i;
237		char			*string;
238		struct {
239			u_int8_t	b1;
240			u_int8_t	b2;
241			u_int16_t	w;
242			u_int16_t	w2;
243		}			b;
244		struct range {
245			int		a;
246			int		b;
247			int		t;
248		}			range;
249		struct node_if		*interface;
250		struct node_proto	*proto;
251		struct node_icmp	*icmp;
252		struct node_host	*host;
253		struct node_port	*port;
254		struct node_uid		*uid;
255		struct node_gid		*gid;
256		struct node_state_opt	*state_opt;
257		struct peer		peer;
258		struct {
259			struct peer	src, dst;
260		}			fromto;
261		struct pf_poolhashkey	*hashkey;
262		struct {
263			struct node_host	*host;
264			u_int8_t	rt;
265			u_int8_t	pool_opts;
266			sa_family_t	af;
267			struct pf_poolhashkey	*key;
268		}			route;
269		struct redirection {
270			struct node_host	*host;
271			struct range		 rport;
272		}			*redirection;
273		struct {
274			int		type;
275			struct pf_poolhashkey	*key;
276		}			pooltype;
277		struct {
278			int			 action;
279			struct node_state_opt	*options;
280		}			keep_state;
281		struct {
282			u_int8_t	log;
283			u_int8_t	quick;
284		}			logquick;
285		struct node_queue	*queue;
286		struct node_queue_opt	queue_options;
287		struct node_queue_bw	queue_bwspec;
288	} v;
289	int lineno;
290} YYSTYPE;
291
292%}
293
294%token	PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS
295%token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
296%token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
297%token	MINTTL ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO REPLYTO NO LABEL
298%token	NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP
299%token	FRAGNORM FRAGDROP FRAGCROP
300%token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY
301%token	REQUIREORDER YES
302%token	ANTISPOOF FOR
303%token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT
304%token	ALTQ SCHEDULER CBQ BANDWIDTH TBRSIZE
305%token	QUEUE PRIORITY QLIMIT
306%token	DEFAULT CONTROL BORROW RED ECN RIO
307%token	<v.string> STRING
308%token	<v.i>	PORTUNARY PORTBINARY
309%type	<v.interface>	interface if_list if_item_not if_item
310%type	<v.number>	number port icmptype icmp6type minttl uid gid maxmss
311%type	<v.number>	tos
312%type	<v.i>	no dir log af nodf allowopts fragment fragcache
313%type	<v.i>	staticport
314%type	<v.b>	action flag flags blockspec
315%type	<v.range>	dport rport
316%type	<v.hashkey>     hashkey
317%type	<v.pooltype>	pooltype
318%type	<v.proto>	proto proto_list proto_item
319%type	<v.icmp>	icmpspec icmp_list icmp6_list icmp_item icmp6_item
320%type	<v.fromto>	fromto
321%type	<v.peer>	ipportspec
322%type	<v.host>	ipspec xhost host address host_list
323%type	<v.host>	redir_host_list redirspec
324%type	<v.host>	route_host route_host_list routespec
325%type	<v.port>	portspec port_list port_item
326%type	<v.uid>		uids uid_list uid_item
327%type	<v.gid>		gids gid_list gid_item
328%type	<v.route>	route
329%type	<v.redirection>	redirection redirpool
330%type	<v.string>	label string
331%type	<v.keep_state>	keep
332%type	<v.state_opt>	state_opt_spec state_opt_list state_opt_item
333%type	<v.logquick>	logquick
334%type	<v.interface>	antispoof_ifspc antispoof_iflst
335%type	<v.number>	priority qlimit tbrsize
336%type	<v.string>	qname
337%type	<v.queue>	qassign qassign_list qassign_item
338%type	<v.queue_options>	schedtype
339%type	<v.number>	cbqflags_list cbqflags_item
340%type	<v.queue_bwspec>	bandwidth
341%%
342
343ruleset		: /* empty */
344		| ruleset '\n'
345		| ruleset option '\n'
346		| ruleset scrubrule '\n'
347		| ruleset natrule '\n'
348		| ruleset binatrule '\n'
349		| ruleset rdrrule '\n'
350		| ruleset pfrule '\n'
351		| ruleset altqif '\n'
352		| ruleset queuespec '\n'
353		| ruleset varset '\n'
354		| ruleset antispoof '\n'
355		| ruleset error '\n'		{ errors++; }
356		;
357
358option		: SET OPTIMIZATION STRING		{
359			if (pf->opts & PF_OPT_VERBOSE)
360				printf("set optimization %s\n", $3);
361			if (check_rulestate(PFCTL_STATE_OPTION))
362				YYERROR;
363			if (pfctl_set_optimization(pf, $3) != 0) {
364				yyerror("unknown optimization %s", $3);
365				YYERROR;
366			}
367		}
368		| SET TIMEOUT timeout_spec
369		| SET TIMEOUT '{' timeout_list '}'
370		| SET LIMIT limit_spec
371		| SET LIMIT '{' limit_list '}'
372		| SET LOGINTERFACE STRING		{
373			if (pf->opts & PF_OPT_VERBOSE)
374				printf("set loginterface %s\n", $3);
375			if (check_rulestate(PFCTL_STATE_OPTION))
376				YYERROR;
377			if (pfctl_set_logif(pf, $3) != 0) {
378				yyerror("error setting loginterface %s", $3);
379				YYERROR;
380			}
381		}
382		| SET BLOCKPOLICY DROP	{
383			if (pf->opts & PF_OPT_VERBOSE)
384				printf("set block-policy drop\n");
385			if (check_rulestate(PFCTL_STATE_OPTION))
386				YYERROR;
387			blockpolicy = PFRULE_DROP;
388		}
389		| SET BLOCKPOLICY RETURN {
390			if (pf->opts & PF_OPT_VERBOSE)
391				printf("set block-policy return\n");
392			if (check_rulestate(PFCTL_STATE_OPTION))
393				YYERROR;
394			blockpolicy = PFRULE_RETURN;
395		}
396		| SET REQUIREORDER YES {
397			if (pf->opts & PF_OPT_VERBOSE)
398				printf("set require-order yes\n");
399			require_order = 1;
400		}
401		| SET REQUIREORDER NO {
402			if (pf->opts & PF_OPT_VERBOSE)
403				printf("set require-order no\n");
404			require_order = 0;
405		}
406		;
407
408string		: string STRING				{
409			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
410				yyerror("asprintf failed");
411				YYERROR;
412			}
413			free($1);
414			free($2);
415		}
416		| STRING
417		;
418
419varset		: STRING PORTUNARY string		{
420			if (pf->opts & PF_OPT_VERBOSE)
421				printf("%s = %s\n", $1, $3);
422			if (symset($1, $3) == -1) {
423				yyerror("cannot store variable %s", $1);
424				YYERROR;
425			}
426		}
427		;
428
429scrubrule	: SCRUB dir interface af fromto nodf minttl maxmss fragcache
430		{
431			struct pf_rule r;
432
433			if (check_rulestate(PFCTL_STATE_SCRUB))
434				YYERROR;
435
436			memset(&r, 0, sizeof(r));
437
438			r.action = PF_SCRUB;
439			r.direction = $2;
440
441			if ($3) {
442				if ($3->not) {
443					yyerror("scrub rules do not support "
444					    "'! <if>'");
445					YYERROR;
446				}
447			}
448			r.af = $4;
449			if ($6)
450				r.rule_flag |= PFRULE_NODF;
451			if ($7)
452				r.min_ttl = $7;
453			if ($8)
454				r.max_mss = $8;
455			if ($9)
456				r.rule_flag |= $9;
457
458			expand_rule(&r, $3, NULL, NULL,
459			    $5.src.host, $5.src.port, $5.dst.host, $5.dst.port,
460			    NULL, NULL, NULL);
461		}
462		;
463
464antispoof	: ANTISPOOF logquick antispoof_ifspc af {
465			struct pf_rule r;
466			struct node_host *h = NULL;
467			struct node_if *i, *j;
468
469			if (check_rulestate(PFCTL_STATE_FILTER))
470				YYERROR;
471
472			for (i = $3; i; i = i->next) {
473				memset(&r, 0, sizeof(r));
474
475				r.action = PF_DROP;
476				r.direction = PF_IN;
477				r.log = $2.log;
478				r.quick = $2.quick;
479				r.af = $4;
480
481				j = calloc(1, sizeof(struct node_if));
482				if (j == NULL)
483					errx(1, "antispoof: calloc");
484				strlcpy(j->ifname, i->ifname, IFNAMSIZ);
485				j->not = 1;
486				h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET);
487
488				expand_rule(&r, j, NULL, NULL, h, NULL, NULL,
489				    NULL, NULL, NULL, NULL);
490
491				if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
492					memset(&r, 0, sizeof(r));
493
494					r.action = PF_DROP;
495					r.direction = PF_IN;
496					r.log = $2.log;
497					r.quick = $2.quick;
498					r.af = $4;
499
500					h = ifa_lookup(i->ifname,
501					    PFCTL_IFLOOKUP_HOST);
502
503					expand_rule(&r, NULL, NULL, NULL, h,
504					    NULL, NULL, NULL, NULL, NULL, NULL);
505				}
506			}
507		}
508		;
509
510antispoof_ifspc	: FOR if_item			{ $$ = $2; }
511		| FOR '{' antispoof_iflst '}'	{ $$ = $3; }
512		;
513
514antispoof_iflst	: if_item			{ $$ = $1; }
515		| antispoof_iflst comma if_item	{
516			$1->tail->next = $3;
517			$1->tail = $3;
518			$$ = $1;
519		}
520		;
521
522
523/* altq stuff */
524
525altqif		: ALTQ interface SCHEDULER schedtype bandwidth qlimit
526		  tbrsize QUEUE qassign	{
527			struct	pf_altq a;
528
529			if (check_rulestate(PFCTL_STATE_QUEUE))
530				YYERROR;
531
532			memset(&a, 0, sizeof(a));
533			if ($4.qtype == ALTQT_NONE) {
534				yyerror("no scheduler specified!");
535				YYERROR;
536			}
537			a.scheduler = $4.qtype;
538			a.pq_u.cbq_opts.flags = $4.data.cbq_opts.flags;
539			if ((a.ifbandwidth = $5.bw_absolute) == 0) {
540				yyerror("interface bandwidth must be absolute");
541				YYERROR;
542			}
543			a.qlimit = $6;
544			a.tbrsize = $7;
545			if ($9 == NULL) {
546				yyerror("no child queues specified");
547				YYERROR;
548			}
549			if (expand_altq(&a, $2, $9))
550				YYERROR;
551		}
552		;
553
554qassign		: /* empty */		{ $$ = NULL; }
555		| qassign_item		{ $$ = $1; }
556		| '{' qassign_list '}'	{ $$ = $2; }
557		;
558
559qassign_list	: qassign_item			{ $$ = $1; }
560		| qassign_list comma qassign_item	{
561			$1->tail->next = $3;
562			$1->tail = $3;
563			$$ = $1;
564		}
565		;
566
567qassign_item	: STRING			{
568			$$ = calloc(1, sizeof(struct node_queue));
569			if ($$ == NULL)
570				err(1, "queue_item: calloc");
571			strlcpy($$->queue, $1, PF_QNAME_SIZE);
572			$$->next = NULL;
573			$$->tail = $$;
574		}
575		;
576
577queuespec	: QUEUE STRING bandwidth priority qlimit schedtype qassign {
578			struct	pf_altq a;
579
580			if (check_rulestate(PFCTL_STATE_QUEUE))
581				YYERROR;
582
583			memset(&a, 0, sizeof(a));
584
585			if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
586			    PF_QNAME_SIZE) {
587				yyerror("queue name too long (max "
588				    "%d chars)", PF_QNAME_SIZE-1);
589				YYERROR;
590			}
591			if ($4 > 255) {
592				yyerror("priority out of range: max 255");
593				YYERROR;
594			}
595			a.priority = $4;
596			a.qlimit = $5;
597			a.scheduler = $6.qtype;
598			switch (a.scheduler) {
599			case ALTQT_CBQ:
600				a.pq_u.cbq_opts.flags = $6.data.cbq_opts.flags;
601			}
602			if (expand_queue(&a, $7, $3))
603				YYERROR;
604
605		}
606		;
607
608schedtype	: /* empty */			{ $$.qtype = ALTQT_NONE; }
609		| CBQ				{ $$.qtype = ALTQT_CBQ; }
610		| CBQ '(' cbqflags_list ')'	{
611			$$.qtype = ALTQT_CBQ;
612			$$.data.cbq_opts.flags = $3;
613		}
614		;
615
616cbqflags_list	: cbqflags_item				{ $$ |= $1; }
617		| cbqflags_list comma cbqflags_item	{ $$ |= $3; }
618		;
619
620
621cbqflags_item	: DEFAULT	{ $$ = CBQCLF_DEFCLASS; }
622		| CONTROL	{ $$ = CBQCLF_CTLCLASS; }
623		| BORROW	{ $$ = CBQCLF_BORROW; }
624		| RED		{ $$ = CBQCLF_RED; }
625		| ECN		{ $$ = CBQCLF_RED|CBQCLF_ECN; }
626		| RIO		{ $$ = CBQCLF_RIO; }
627		;
628
629bandwidth	: /* empty */		{
630			$$.bw_absolute = 0;
631			$$.bw_percent = 100;
632		}
633		| BANDWIDTH STRING {
634			double bps;
635			char *cp;
636
637			$$.bw_percent = 0;
638
639			bps = strtod($2, &cp);
640			if (cp != NULL) {
641				if (!strcmp(cp, "b"))
642					;
643				else if (!strcmp(cp, "Kb"))
644					bps *= 1000;
645				else if (!strcmp(cp, "Mb"))
646					bps *= 1000 * 1000;
647				else if (!strcmp(cp, "Gb"))
648					bps *= 1000 * 1000 * 1000;
649				else if (!strcmp(cp, "%")) {
650					if (bps < 0 || bps > 100) {
651						yyerror("bandwidth spec "
652						    "out of range");
653						YYERROR;
654					}
655					$$.bw_percent = bps;
656					bps = 0;
657				} else {
658					yyerror("unknown unit %s", cp);
659					YYERROR;
660				}
661			}
662			$$.bw_absolute = (u_int32_t)bps;
663		}
664		;
665
666priority	: /* empty */		{ $$ = DEFAULT_PRIORITY; }
667		| PRIORITY number	{
668			if ($2 > 255) {
669				yyerror("priority out of range: max 255");
670				YYERROR;
671			}
672			$$ = $2;
673		}
674		;
675
676qlimit		: /* empty */		{ $$ = DEFAULT_QLIMIT; }
677		| QLIMIT number		{
678			if ($2 > 65535) {
679				yyerror("qlimit out of range: max 65535");
680				YYERROR;
681			}
682			$$ = $2;
683		}
684		;
685
686
687tbrsize		: /* empty */		{ $$ = 0; }
688		| TBRSIZE number	{
689			if ($2 > 65535) {
690				yyerror("tbrsize too big: max 65535");
691				YYERROR;
692			}
693			$$ = $2;
694		}
695		;
696
697pfrule		: action dir logquick interface route af proto fromto
698		  uids gids flags icmpspec tos keep fragment allowopts label
699		  qname
700		{
701			struct pf_rule r;
702			struct node_state_opt *o;
703			struct node_proto *proto;
704
705			if (check_rulestate(PFCTL_STATE_FILTER))
706				YYERROR;
707
708			memset(&r, 0, sizeof(r));
709
710			r.action = $1.b1;
711			switch ($1.b2) {
712			case PFRULE_RETURNRST:
713				r.rule_flag |= PFRULE_RETURNRST;
714				r.return_ttl = $1.w;
715				break;
716			case PFRULE_RETURNICMP:
717				r.rule_flag |= PFRULE_RETURNICMP;
718				r.return_icmp = $1.w;
719				r.return_icmp6 = $1.w2;
720				break;
721			case PFRULE_RETURN:
722				r.rule_flag |= PFRULE_RETURN;
723				r.return_icmp = $1.w;
724				r.return_icmp6 = $1.w2;
725				break;
726			}
727			r.direction = $2;
728			r.log = $3.log;
729			r.quick = $3.quick;
730
731			r.af = $6;
732			r.flags = $11.b1;
733			r.flagset = $11.b2;
734
735			if ($11.b1 || $11.b2) {
736				for (proto = $7; proto != NULL &&
737				    proto->proto != IPPROTO_TCP;
738				    proto = proto->next)
739					;	/* nothing */
740				if (proto == NULL && $7 != NULL) {
741					yyerror("flags only apply to tcp");
742					YYERROR;
743				}
744			}
745
746			r.tos = $13;
747			r.keep_state = $14.action;
748			o = $14.options;
749			while (o) {
750				struct node_state_opt *p = o;
751
752				switch (o->type) {
753				case PF_STATE_OPT_MAX:
754					if (r.max_states) {
755						yyerror("state option 'max' "
756						    "multiple definitions");
757						YYERROR;
758					}
759					r.max_states = o->data.max_states;
760					break;
761				case PF_STATE_OPT_TIMEOUT:
762					if (r.timeout[o->data.timeout.number]) {
763						yyerror("state timeout %s "
764						    "multiple definitions",
765						    pf_timeouts[o->data.
766						    timeout.number].name);
767						YYERROR;
768					}
769					r.timeout[o->data.timeout.number] =
770					    o->data.timeout.seconds;
771				}
772				o = o->next;
773				free(p);
774			}
775
776			if ($15)
777				r.rule_flag |= PFRULE_FRAGMENT;
778			r.allow_opts = $16;
779
780			decide_address_family($8.src.host, &r.af);
781			decide_address_family($8.dst.host, &r.af);
782
783			if ($5.rt) {
784				r.rt = $5.rt;
785				r.rt_pool.opts = $5.pool_opts;
786			}
787			if (r.rt && r.rt != PF_FASTROUTE) {
788
789				decide_address_family($5.host, &r.af);
790				remove_invalid_hosts(&$5.host, &r.af);
791				if ($5.host == NULL) {
792					yyerror("$5.host == NULL");
793					YYERROR;
794				}
795				if ($5.host->next != NULL) {
796					if (r.rt_pool.opts == PF_POOL_NONE)
797						r.rt_pool.opts = PF_POOL_ROUNDROBIN;
798					if (r.rt_pool.opts != PF_POOL_ROUNDROBIN) {
799						yyerror("r.rt_pool.opts must be "
800						    "PF_POOL_ROUNDROBIN");
801						YYERROR;
802					}
803				}
804			}
805
806			if ($17) {
807				if (strlcpy(r.label, $17, sizeof(r.label)) >=
808				    PF_RULE_LABEL_SIZE) {
809					yyerror("rule label too long (max "
810					    "%d chars)", PF_RULE_LABEL_SIZE-1);
811					YYERROR;
812				}
813				free($17);
814			}
815
816			if ($18) {
817				if (strlcpy(r.qname, $18, sizeof(r.qname)) >=
818				    PF_QNAME_SIZE) {
819					yyerror("rule qname too long (max "
820					    "%d chars)", PF_QNAME_SIZE-1);
821					YYERROR;
822				}
823				free($18);
824			}
825
826			expand_rule(&r, $4, $5.host, $7,
827			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
828			    $9, $10, $12);
829		}
830		;
831
832action		: PASS			{ $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
833		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
834		;
835
836blockspec	: /* empty */		{
837			$$.b2 = blockpolicy;
838			$$.w = returnicmpdefault;
839			$$.w2 = returnicmp6default;
840		}
841		| DROP			{
842			$$.b2 = PFRULE_DROP;
843			$$.w = 0;
844			$$.w2 = 0;
845		}
846		| RETURNRST		{
847			$$.b2 = PFRULE_RETURNRST;
848			$$.w = 0;
849			$$.w2 = 0;
850		}
851		| RETURNRST '(' TTL number ')'	{
852			$$.b2 = PFRULE_RETURNRST;
853			$$.w = $4;
854			$$.w2 = 0;
855		}
856		| RETURNICMP		{
857			$$.b2 = PFRULE_RETURNICMP;
858			$$.w = returnicmpdefault;
859			$$.w2 = returnicmp6default;
860		}
861		| RETURNICMP6		{
862			$$.b2 = PFRULE_RETURNICMP;
863			$$.w = returnicmpdefault;
864			$$.w2 = returnicmp6default;
865		}
866		| RETURNICMP '(' STRING ')'	{
867			$$.b2 = PFRULE_RETURNICMP;
868			if (!($$.w = parseicmpspec($3, AF_INET)))
869				YYERROR;
870			$$.w2 = returnicmp6default;
871		}
872		| RETURNICMP6 '(' STRING ')'	{
873			$$.b2 = PFRULE_RETURNICMP;
874			$$.w = returnicmpdefault;
875			if (!($$.w2 = parseicmpspec($3, AF_INET6)))
876				YYERROR;
877		}
878		| RETURNICMP '(' STRING comma STRING ')' {
879			$$.b2 = PFRULE_RETURNICMP;
880			if (!($$.w = parseicmpspec($3, AF_INET)))
881				YYERROR;
882			if (!($$.w2 = parseicmpspec($5, AF_INET6)));
883		}
884		| RETURN {
885			$$.b2 = PFRULE_RETURN;
886			$$.w = returnicmpdefault;
887			$$.w2 = returnicmp6default;
888		}
889		;
890
891fragcache	: /* empty */		{ $$ = 0; }
892		| fragment FRAGNORM	{ $$ = 0; /* default */ }
893		| fragment FRAGCROP	{ $$ = PFRULE_FRAGCROP; }
894		| fragment FRAGDROP	{ $$ = PFRULE_FRAGDROP; }
895		;
896
897
898dir		: IN				{ $$ = PF_IN; }
899		| OUT				{ $$ = PF_OUT; }
900		;
901
902logquick	: /* empty */			{ $$.log = 0; $$.quick = 0; }
903		| log				{ $$.log = $1; $$.quick = 0; }
904		| QUICK				{ $$.log = 0; $$.quick = 1; }
905		| log QUICK			{ $$.log = $1; $$.quick = 1; }
906		| QUICK log			{ $$.log = $2; $$.quick = 1; }
907		;
908
909log		: LOG				{ $$ = 1; }
910		| LOGALL			{ $$ = 2; }
911		;
912
913interface	: /* empty */			{ $$ = NULL; }
914		| ON if_item_not		{ $$ = $2; }
915		| ON '{' if_list '}'		{ $$ = $3; }
916		;
917
918if_list		: if_item_not			{ $$ = $1; }
919		| if_list comma if_item_not	{
920			$1->tail->next = $3;
921			$1->tail = $3;
922			$$ = $1;
923		}
924		;
925
926if_item_not	: '!' if_item			{ $$ = $2; $$->not = 1; }
927		| if_item			{ $$ = $1; }
928
929if_item		: STRING			{
930			struct node_host *n;
931
932			if ((n = ifa_exists($1)) == NULL) {
933				yyerror("unknown interface %s", $1);
934				YYERROR;
935			}
936			$$ = calloc(1, sizeof(struct node_if));
937			if ($$ == NULL)
938				err(1, "if_item: calloc");
939			strlcpy($$->ifname, $1, IFNAMSIZ);
940			$$->ifa_flags = n->ifa_flags;
941			$$->not = 0;
942			$$->next = NULL;
943			$$->tail = $$;
944		}
945		;
946
947af		: /* empty */			{ $$ = 0; }
948		| INET				{ $$ = AF_INET; }
949		| INET6				{ $$ = AF_INET6; }
950
951proto		: /* empty */			{ $$ = NULL; }
952		| PROTO proto_item		{ $$ = $2; }
953		| PROTO '{' proto_list '}'	{ $$ = $3; }
954		;
955
956proto_list	: proto_item			{ $$ = $1; }
957		| proto_list comma proto_item	{
958			$1->tail->next = $3;
959			$1->tail = $3;
960			$$ = $1;
961		}
962		;
963
964proto_item	: STRING			{
965			u_int8_t pr;
966			u_long ulval;
967
968			if (atoul($1, &ulval) == 0) {
969				if (ulval > 255) {
970					yyerror("protocol outside range");
971					YYERROR;
972				}
973				pr = (u_int8_t)ulval;
974			} else {
975				struct protoent *p;
976
977				p = getprotobyname($1);
978				if (p == NULL) {
979					yyerror("unknown protocol %s", $1);
980					YYERROR;
981				}
982				pr = p->p_proto;
983			}
984			if (pr == 0) {
985				yyerror("proto 0 cannot be used");
986				YYERROR;
987			}
988			$$ = calloc(1, sizeof(struct node_proto));
989			if ($$ == NULL)
990				err(1, "proto_item: calloc");
991			$$->proto = pr;
992			$$->next = NULL;
993			$$->tail = $$;
994		}
995		;
996
997fromto		: ALL				{
998			$$.src.host = NULL;
999			$$.src.port = NULL;
1000			$$.dst.host = NULL;
1001			$$.dst.port = NULL;
1002		}
1003		| FROM ipportspec TO ipportspec	{
1004			$$.src = $2;
1005			$$.dst = $4;
1006		}
1007		;
1008
1009ipportspec	: ipspec			{ $$.host = $1; $$.port = NULL; }
1010		| ipspec PORT portspec		{
1011			$$.host = $1;
1012			$$.port = $3;
1013		}
1014		;
1015
1016ipspec		: ANY				{ $$ = NULL; }
1017		| xhost				{ $$ = $1; }
1018		| '{' host_list '}'		{ $$ = $2; }
1019		;
1020
1021host_list	: xhost				{ $$ = $1; }
1022		| host_list comma xhost		{
1023			/* $3 may be a list, so use its tail pointer */
1024			$1->tail->next = $3->tail;
1025			$1->tail = $3->tail;
1026			$$ = $1;
1027		}
1028		;
1029
1030xhost		: '!' host			{
1031			struct node_host *h;
1032			for (h = $2; h; h = h->next)
1033				h->not = 1;
1034			$$ = $2;
1035		}
1036		| host				{ $$ = $1; }
1037		| NOROUTE			{
1038			$$ = calloc(1, sizeof(struct node_host));
1039			if ($$ == NULL)
1040				err(1, "xhost: calloc");
1041			$$->noroute = 1;
1042			$$->next = NULL;
1043			$$->tail = $$;
1044		}
1045		;
1046
1047host		: address
1048		| STRING '/' number		{ $$ = host($1, $3); }
1049		;
1050
1051number		: STRING			{
1052			u_long ulval;
1053
1054			if (atoul($1, &ulval) == -1) {
1055				yyerror("%s is not a number", $1);
1056				YYERROR;
1057			} else
1058				$$ = ulval;
1059		}
1060		;
1061
1062address		: '(' STRING ')'		{
1063			$$ = calloc(1, sizeof(struct node_host));
1064			if ($$ == NULL)
1065				err(1, "address: calloc");
1066			$$->af = 0;
1067			set_ipmask($$, 128);
1068			$$->addr.addr_dyn = (struct pf_addr_dyn *)1;
1069			strncpy($$->addr.addr.pfa.ifname, $2,
1070			    sizeof($$->addr.addr.pfa.ifname));
1071			$$->next = NULL;
1072			$$->tail = $$;
1073		}
1074		| STRING			{ $$ = host($1, -1); }
1075		;
1076
1077portspec	: port_item			{ $$ = $1; }
1078		| '{' port_list '}'		{ $$ = $2; }
1079		;
1080
1081port_list	: port_item			{ $$ = $1; }
1082		| port_list comma port_item	{
1083			$1->tail->next = $3;
1084			$1->tail = $3;
1085			$$ = $1;
1086		}
1087		;
1088
1089port_item	: port				{
1090			$$ = calloc(1, sizeof(struct node_port));
1091			if ($$ == NULL)
1092				err(1, "port_item: calloc");
1093			$$->port[0] = $1;
1094			$$->port[1] = $1;
1095			$$->op = PF_OP_EQ;
1096			$$->next = NULL;
1097			$$->tail = $$;
1098		}
1099		| PORTUNARY port		{
1100			$$ = calloc(1, sizeof(struct node_port));
1101			if ($$ == NULL)
1102				err(1, "port_item: calloc");
1103			$$->port[0] = $2;
1104			$$->port[1] = $2;
1105			$$->op = $1;
1106			$$->next = NULL;
1107			$$->tail = $$;
1108		}
1109		| port PORTBINARY port		{
1110			$$ = calloc(1, sizeof(struct node_port));
1111			if ($$ == NULL)
1112				err(1, "port_item: calloc");
1113			$$->port[0] = $1;
1114			$$->port[1] = $3;
1115			$$->op = $2;
1116			$$->next = NULL;
1117			$$->tail = $$;
1118		}
1119		;
1120
1121port		: STRING			{
1122			struct servent *s = NULL;
1123			u_long ulval;
1124
1125			if (atoul($1, &ulval) == 0) {
1126				if (ulval > 65535) {
1127					yyerror("illegal port value %d", ulval);
1128					YYERROR;
1129				}
1130				$$ = htons(ulval);
1131			} else {
1132				s = getservbyname($1, "tcp");
1133				if (s == NULL)
1134					s = getservbyname($1, "udp");
1135				if (s == NULL) {
1136					yyerror("unknown port %s", $1);
1137					YYERROR;
1138				}
1139				$$ = s->s_port;
1140			}
1141		}
1142		;
1143
1144uids		: /* empty */			{ $$ = NULL; }
1145		| USER uid_item			{ $$ = $2; }
1146		| USER '{' uid_list '}'		{ $$ = $3; }
1147		;
1148
1149uid_list	: uid_item			{ $$ = $1; }
1150		| uid_list comma uid_item	{
1151			$1->tail->next = $3;
1152			$1->tail = $3;
1153			$$ = $1;
1154		}
1155		;
1156
1157uid_item	: uid				{
1158			$$ = calloc(1, sizeof(struct node_uid));
1159			if ($$ == NULL)
1160				err(1, "uid_item: calloc");
1161			$$->uid[0] = $1;
1162			$$->uid[1] = $1;
1163			$$->op = PF_OP_EQ;
1164			$$->next = NULL;
1165			$$->tail = $$;
1166		}
1167		| PORTUNARY uid			{
1168			if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
1169				yyerror("user unknown requires operator = or !=");
1170				YYERROR;
1171			}
1172			$$ = calloc(1, sizeof(struct node_uid));
1173			if ($$ == NULL)
1174				err(1, "uid_item: calloc");
1175			$$->uid[0] = $2;
1176			$$->uid[1] = $2;
1177			$$->op = $1;
1178			$$->next = NULL;
1179			$$->tail = $$;
1180		}
1181		| uid PORTBINARY uid		{
1182			if ($1 == UID_MAX || $3 == UID_MAX) {
1183				yyerror("user unknown requires operator = or !=");
1184				YYERROR;
1185			}
1186			$$ = calloc(1, sizeof(struct node_uid));
1187			if ($$ == NULL)
1188				err(1, "uid_item: calloc");
1189			$$->uid[0] = $1;
1190			$$->uid[1] = $3;
1191			$$->op = $2;
1192			$$->next = NULL;
1193			$$->tail = $$;
1194		}
1195		;
1196
1197uid		: STRING			{
1198			u_long ulval;
1199
1200			if (atoul($1, &ulval) == -1) {
1201				if (!strcmp($1, "unknown"))
1202					$$ = UID_MAX;
1203				else {
1204					struct passwd *pw;
1205
1206					if ((pw = getpwnam($1)) == NULL) {
1207						yyerror("unknown user %s", $1);
1208						YYERROR;
1209					}
1210					$$ = pw->pw_uid;
1211				}
1212			} else {
1213				if (ulval >= UID_MAX) {
1214					yyerror("illegal uid value %lu", ulval);
1215					YYERROR;
1216				}
1217				$$ = ulval;
1218			}
1219		}
1220		;
1221
1222gids		: /* empty */			{ $$ = NULL; }
1223		| GROUP gid_item		{ $$ = $2; }
1224		| GROUP '{' gid_list '}'	{ $$ = $3; }
1225		;
1226
1227gid_list	: gid_item			{ $$ = $1; }
1228		| gid_list comma gid_item	{
1229			$1->tail->next = $3;
1230			$1->tail = $3;
1231			$$ = $1;
1232		}
1233		;
1234
1235gid_item	: gid				{
1236			$$ = calloc(1, sizeof(struct node_gid));
1237			if ($$ == NULL)
1238				err(1, "gid_item: calloc");
1239			$$->gid[0] = $1;
1240			$$->gid[1] = $1;
1241			$$->op = PF_OP_EQ;
1242			$$->next = NULL;
1243			$$->tail = $$;
1244		}
1245		| PORTUNARY gid			{
1246			if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
1247				yyerror("group unknown requires operator = or !=");
1248				YYERROR;
1249			}
1250			$$ = calloc(1, sizeof(struct node_gid));
1251			if ($$ == NULL)
1252				err(1, "gid_item: calloc");
1253			$$->gid[0] = $2;
1254			$$->gid[1] = $2;
1255			$$->op = $1;
1256			$$->next = NULL;
1257			$$->tail = $$;
1258		}
1259		| gid PORTBINARY gid		{
1260			if ($1 == GID_MAX || $3 == GID_MAX) {
1261				yyerror("group unknown requires operator = or !=");
1262				YYERROR;
1263			}
1264			$$ = calloc(1, sizeof(struct node_gid));
1265			if ($$ == NULL)
1266				err(1, "gid_item: calloc");
1267			$$->gid[0] = $1;
1268			$$->gid[1] = $3;
1269			$$->op = $2;
1270			$$->next = NULL;
1271			$$->tail = $$;
1272		}
1273		;
1274
1275gid		: STRING			{
1276			u_long ulval;
1277
1278			if (atoul($1, &ulval) == -1) {
1279				if (!strcmp($1, "unknown"))
1280					$$ = GID_MAX;
1281				else {
1282					struct group *grp;
1283
1284					if ((grp = getgrnam($1)) == NULL) {
1285						yyerror("unknown group %s", $1);
1286						YYERROR;
1287					}
1288					$$ = grp->gr_gid;
1289				}
1290			} else {
1291				if (ulval >= GID_MAX) {
1292					yyerror("illegal gid value %lu", ulval);
1293					YYERROR;
1294				}
1295				$$ = ulval;
1296			}
1297		}
1298		;
1299
1300flag		: STRING			{
1301			int f;
1302
1303			if ((f = parse_flags($1)) < 0) {
1304				yyerror("bad flags %s", $1);
1305				YYERROR;
1306			}
1307			$$.b1 = f;
1308		}
1309		;
1310
1311flags		: /* empty */			{ $$.b1 = 0; $$.b2 = 0; }
1312		| FLAGS flag "/" flag		{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
1313		| FLAGS "/" flag		{ $$.b1 = 0; $$.b2 = $3.b1; }
1314		;
1315
1316icmpspec	: /* empty */			{ $$ = NULL; }
1317		| ICMPTYPE icmp_item		{ $$ = $2; }
1318		| ICMPTYPE '{' icmp_list '}'	{ $$ = $3; }
1319		| ICMP6TYPE icmp6_item		{ $$ = $2; }
1320		| ICMP6TYPE '{' icmp6_list '}'	{ $$ = $3; }
1321		;
1322
1323icmp_list	: icmp_item			{ $$ = $1; }
1324		| icmp_list comma icmp_item	{
1325			$1->tail->next = $3;
1326			$1->tail = $3;
1327			$$ = $1;
1328		}
1329		;
1330
1331icmp6_list	: icmp6_item			{ $$ = $1; }
1332		| icmp6_list comma icmp6_item	{
1333			$1->tail->next = $3;
1334			$1->tail = $3;
1335			$$ = $1;
1336		}
1337		;
1338
1339icmp_item	: icmptype		{
1340			$$ = calloc(1, sizeof(struct node_icmp));
1341			if ($$ == NULL)
1342				err(1, "icmp_item: calloc");
1343			$$->type = $1;
1344			$$->code = 0;
1345			$$->proto = IPPROTO_ICMP;
1346			$$->next = NULL;
1347			$$->tail = $$;
1348		}
1349		| icmptype CODE STRING	{
1350			const struct icmpcodeent *p;
1351			u_long ulval;
1352
1353			if (atoul($3, &ulval) == 0) {
1354				if (ulval > 255) {
1355					yyerror("illegal icmp-code %d", ulval);
1356					YYERROR;
1357				}
1358			} else {
1359				if ((p = geticmpcodebyname($1-1, $3,
1360				    AF_INET)) == NULL) {
1361					yyerror("unknown icmp-code %s", $3);
1362					YYERROR;
1363				}
1364				ulval = p->code;
1365			}
1366			$$ = calloc(1, sizeof(struct node_icmp));
1367			if ($$ == NULL)
1368				err(1, "icmp_item: calloc");
1369			$$->type = $1;
1370			$$->code = ulval + 1;
1371			$$->proto = IPPROTO_ICMP;
1372			$$->next = NULL;
1373			$$->tail = $$;
1374		}
1375		;
1376
1377icmp6_item	: icmp6type		{
1378			$$ = calloc(1, sizeof(struct node_icmp));
1379			if ($$ == NULL)
1380				err(1, "icmp_item: calloc");
1381			$$->type = $1;
1382			$$->code = 0;
1383			$$->proto = IPPROTO_ICMPV6;
1384			$$->next = NULL;
1385			$$->tail = $$;
1386		}
1387		| icmp6type CODE STRING	{
1388			const struct icmpcodeent *p;
1389			u_long ulval;
1390
1391			if (atoul($3, &ulval) == 0) {
1392				if (ulval > 255) {
1393					yyerror("illegal icmp6-code %ld", ulval);
1394					YYERROR;
1395				}
1396			} else {
1397				if ((p = geticmpcodebyname($1-1, $3,
1398				    AF_INET6)) == NULL) {
1399					yyerror("unknown icmp6-code %s", $3);
1400					YYERROR;
1401				}
1402				ulval = p->code;
1403			}
1404			$$ = calloc(1, sizeof(struct node_icmp));
1405			if ($$ == NULL)
1406				err(1, "icmp_item: calloc");
1407			$$->type = $1;
1408			$$->code = ulval + 1;
1409			$$->proto = IPPROTO_ICMPV6;
1410			$$->next = NULL;
1411			$$->tail = $$;
1412		}
1413		;
1414
1415icmptype	: STRING			{
1416			const struct icmptypeent *p;
1417			u_long ulval;
1418
1419			if (atoul($1, &ulval) == 0) {
1420				if (ulval > 255) {
1421					yyerror("illegal icmp-type %d", ulval);
1422					YYERROR;
1423				}
1424				$$ = ulval + 1;
1425			} else {
1426				if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
1427					yyerror("unknown icmp-type %s", $1);
1428					YYERROR;
1429				}
1430				$$ = p->type + 1;
1431			}
1432		}
1433		;
1434
1435icmp6type	: STRING			{
1436			const struct icmptypeent *p;
1437			u_long ulval;
1438
1439			if (atoul($1, &ulval) == 0) {
1440				if (ulval > 255) {
1441					yyerror("illegal icmp6-type %d", ulval);
1442					YYERROR;
1443				}
1444				$$ = ulval + 1;
1445			} else {
1446				if ((p = geticmptypebyname($1, AF_INET6)) == NULL) {
1447					yyerror("unknown ipv6-icmp-type %s", $1);
1448					YYERROR;
1449				}
1450				$$ = p->type + 1;
1451			}
1452		}
1453		;
1454
1455tos		: /* empty */			{ $$ = 0; }
1456		| TOS STRING			{
1457			if (!strcmp($2, "lowdelay"))
1458				$$ = IPTOS_LOWDELAY;
1459			else if (!strcmp($2, "throughput"))
1460				$$ = IPTOS_THROUGHPUT;
1461			else if (!strcmp($2, "reliability"))
1462				$$ = IPTOS_RELIABILITY;
1463			else if ($2[0] == '0' && $2[1] == 'x')
1464				$$ = strtoul($2, NULL, 16);
1465			else
1466				$$ = strtoul($2, NULL, 10);
1467			if (!$$ || $$ > 255) {
1468				yyerror("illegal tos value %s", $2);
1469				YYERROR;
1470			}
1471		}
1472		;
1473
1474keep		: /* empty */			{
1475			$$.action = 0;
1476			$$.options = NULL;
1477		}
1478		| KEEP STATE state_opt_spec	{
1479			$$.action = PF_STATE_NORMAL;
1480			$$.options = $3;
1481		}
1482		| MODULATE STATE state_opt_spec	{
1483			$$.action = PF_STATE_MODULATE;
1484			$$.options = $3;
1485		}
1486		;
1487
1488state_opt_spec	: /* empty */			{ $$ = NULL; }
1489		| '(' state_opt_list ')'	{ $$ = $2; }
1490		;
1491
1492state_opt_list	: state_opt_item		{ $$ = $1; }
1493		| state_opt_list comma state_opt_item {
1494			$1->tail->next = $3;
1495			$1->tail = $3;
1496			$$ = $1;
1497		}
1498		;
1499
1500state_opt_item	: MAXIMUM number		{
1501			if ($2 <= 0) {
1502				yyerror("illegal states max value %d", $2);
1503				YYERROR;
1504			}
1505			$$ = calloc(1, sizeof(struct node_state_opt));
1506			if ($$ == NULL)
1507				err(1, "state_opt_item: calloc");
1508			$$->type = PF_STATE_OPT_MAX;
1509			$$->data.max_states = $2;
1510			$$->next = NULL;
1511			$$->tail = $$;
1512		}
1513		| STRING number			{
1514			int i;
1515
1516			for (i = 0; pf_timeouts[i].name &&
1517			    strcmp(pf_timeouts[i].name, $1); ++i)
1518				;	/* nothing */
1519			if (!pf_timeouts[i].name) {
1520				yyerror("illegal timeout name %s", $1);
1521				YYERROR;
1522			}
1523			if (strchr(pf_timeouts[i].name, '.') == NULL) {
1524				yyerror("illegal state timeout %s", $1);
1525				YYERROR;
1526			}
1527			$$ = calloc(1, sizeof(struct node_state_opt));
1528			if ($$ == NULL)
1529				err(1, "state_opt_item: calloc");
1530			$$->type = PF_STATE_OPT_TIMEOUT;
1531			$$->data.timeout.number = pf_timeouts[i].timeout;
1532			$$->data.timeout.seconds = $2;
1533			$$->next = NULL;
1534			$$->tail = $$;
1535		}
1536		;
1537
1538fragment	: /* empty */			{ $$ = 0; }
1539		| FRAGMENT			{ $$ = 1; }
1540
1541minttl		: /* empty */			{ $$ = 0; }
1542		| MINTTL number			{
1543			if ($2 > 255) {
1544				yyerror("illegal min-ttl value %d", $2);
1545				YYERROR;
1546			}
1547			$$ = $2;
1548		}
1549		;
1550
1551nodf		: /* empty */			{ $$ = 0; }
1552		| NODF				{ $$ = 1; }
1553		;
1554
1555maxmss		: /* empty */			{ $$ = 0; }
1556		| MAXMSS number			{ $$ = $2; }
1557		;
1558
1559allowopts	: /* empty */			{ $$ = 0; }
1560		| ALLOWOPTS			{ $$ = 1; }
1561
1562label		: /* empty */			{ $$ = NULL; }
1563		| LABEL STRING			{
1564			if (($$ = strdup($2)) == NULL) {
1565				yyerror("rule label strdup() failed");
1566				YYERROR;
1567			}
1568		}
1569		;
1570qname		: /* empty */			{ $$ = NULL; }
1571		| QUEUE STRING			{
1572			if (($$ = strdup($2)) == NULL) {
1573				yyerror("qname strdup() failed");
1574				YYERROR;
1575			}
1576		}
1577		;
1578
1579no		: /* empty */			{ $$ = 0; }
1580		| NO				{ $$ = 1; }
1581		;
1582
1583rport		: STRING			{
1584			char *p = strchr($1, ':');
1585
1586			if (p == NULL) {
1587				if (($$.a = getservice($1)) == -1)
1588					YYERROR;
1589				$$.b = $$.t = 0;
1590			} else if (!strcmp(p+1, "*")) {
1591				*p = 0;
1592				if (($$.a = getservice($1)) == -1)
1593					YYERROR;
1594				$$.b = 0;
1595				$$.t = PF_RPORT_RANGE;
1596			} else {
1597				*p++ = 0;
1598				if (($$.a = getservice($1)) == -1 ||
1599				    ($$.b = getservice(p)) == -1)
1600					YYERROR;
1601				$$.t = PF_RPORT_RANGE;
1602			}
1603		}
1604		;
1605
1606redirspec	: host				{ $$ = $1; }
1607		| '{' redir_host_list '}'	{ $$ = $2; }
1608		;
1609
1610redir_host_list	: host				{ $$ = $1; }
1611		| redir_host_list comma host	{
1612			/* $3 may be a list, so use its tail pointer */
1613			$1->tail->next = $3->tail;
1614			$1->tail = $3->tail;
1615			$$ = $1;
1616		}
1617		;
1618
1619redirpool	: /* empty */			{ $$ = NULL; }
1620		| ARROW redirspec		{
1621			$$ = calloc(1, sizeof(struct redirection));
1622			if ($$ == NULL)
1623				err(1, "redirection: calloc");
1624			$$->host = $2;
1625			$$->rport.a = $$->rport.b = $$->rport.t = 0;
1626		}
1627		| ARROW redirspec PORT rport	{
1628			$$ = calloc(1, sizeof(struct redirection));
1629			if ($$ == NULL)
1630				err(1, "redirection: calloc");
1631			$$->host = $2;
1632			$$->rport = $4;
1633		}
1634		;
1635
1636hashkey		: /* empty */
1637		{
1638			$$ = malloc(sizeof(struct pf_poolhashkey));
1639			if ($$ == NULL)
1640				err(1, "pooltype: malloc");
1641			$$->key32[0] = arc4random();
1642			$$->key32[1] = arc4random();
1643			$$->key32[2] = arc4random();
1644			$$->key32[3] = arc4random();
1645		}
1646		| string
1647		{
1648			char buf[11] = "0x";
1649			int i;
1650
1651			if (!strncmp((char *)$1, "0x", 2)) {
1652				if (strlen((char *)$1) != 34) {
1653					yyerror("hex key must be 128 bits "
1654						"(32 hex digits) long");
1655					YYERROR;
1656				}
1657				$$ = calloc(1, sizeof(struct pf_poolhashkey));
1658				if ($$ == NULL)
1659					err(1, "hashkey: calloc");
1660
1661				/* convert to binary */
1662				for (i = 0; i < 4; i++) {
1663					strncpy((char *)(buf + 2),
1664					    (char *)($1 + 2 + (i * 8)), 8);
1665					if (atoul(buf,
1666					    (u_long *)&$$->key32[i]) == -1) {
1667						/* not hex */
1668						free($$);
1669						yyerror("invalid hex key");
1670						YYERROR;
1671					}
1672				}
1673			} else {
1674				MD5_CTX context;
1675
1676				$$ = calloc(1, sizeof(struct pf_poolhashkey));
1677				if ($$ == NULL)
1678					err(1, "hashkey: calloc");
1679				MD5Init(&context);
1680				MD5Update(&context, $1, strlen($1));
1681				MD5Final((unsigned char *)$$, &context);
1682			}
1683		}
1684		;
1685
1686pooltype	: /* empty */			{ $$.type = PF_POOL_NONE; }
1687		| BITMASK			{ $$.type = PF_POOL_BITMASK; }
1688		| RANDOM			{ $$.type = PF_POOL_RANDOM; }
1689		| SOURCEHASH hashkey
1690		{
1691			$$.type = PF_POOL_SRCHASH;
1692			$$.key = $2;
1693		}
1694		| ROUNDROBIN			{ $$.type = PF_POOL_ROUNDROBIN; }
1695		;
1696
1697staticport	: /* empty */			{ $$ = 0; }
1698		| STATICPORT			{ $$ = PF_POOL_STATICPORT; }
1699		;
1700
1701redirection	: /* empty */			{ $$ = NULL; }
1702		| ARROW host			{
1703			$$ = calloc(1, sizeof(struct redirection));
1704			if ($$ == NULL)
1705				err(1, "redirection: calloc");
1706			$$->host = $2;
1707			$$->rport.a = $$->rport.b = $$->rport.t = 0;
1708		}
1709		| ARROW host PORT rport	{
1710			$$ = calloc(1, sizeof(struct redirection));
1711			if ($$ == NULL)
1712				err(1, "redirection: calloc");
1713			$$->host = $2;
1714			$$->rport = $4;
1715		}
1716		;
1717
1718natrule		: no NAT interface af proto fromto redirpool pooltype staticport
1719		{
1720			struct pf_nat nat;
1721
1722			if (check_rulestate(PFCTL_STATE_NAT))
1723				YYERROR;
1724
1725			memset(&nat, 0, sizeof(nat));
1726
1727			nat.no = $1;
1728			nat.af = $4;
1729
1730			if (!nat.af) {
1731				if ($6.src.host && $6.src.host->af &&
1732				    !$6.src.host->ifindex)
1733					nat.af = $6.src.host->af;
1734				else if ($6.dst.host && $6.dst.host->af &&
1735				    !$6.dst.host->ifindex)
1736					nat.af = $6.dst.host->af;
1737			}
1738
1739			if (nat.no) {
1740				if ($7 != NULL) {
1741					yyerror("'no nat' rule does not need "
1742					    "'->'");
1743					YYERROR;
1744				}
1745			} else {
1746				if ($7 == NULL || $7->host == NULL) {
1747					yyerror("'nat' rule requires '-> "
1748					    "address'");
1749					YYERROR;
1750				}
1751				if (!nat.af && ! $7->host->ifindex)
1752					nat.af = $7->host->af;
1753
1754				remove_invalid_hosts(&$7->host, &nat.af);
1755				if ($7->host == NULL)
1756					YYERROR;
1757				nat.proxy_port[0] = ntohs($7->rport.a);
1758				nat.proxy_port[1] = ntohs($7->rport.b);
1759				if (!nat.proxy_port[0] && !nat.proxy_port[1]) {
1760					nat.proxy_port[0] =
1761					    PF_NAT_PROXY_PORT_LOW;
1762					nat.proxy_port[1] =
1763					    PF_NAT_PROXY_PORT_HIGH;
1764				} else if (!nat.proxy_port[1])
1765					nat.proxy_port[1] = nat.proxy_port[0];
1766
1767				if ($7->host->next) {
1768					nat.rpool.opts = $8.type;
1769					if (nat.rpool.opts == PF_POOL_NONE)
1770						nat.rpool.opts =
1771						    PF_POOL_ROUNDROBIN;
1772					if (nat.rpool.opts !=
1773					    PF_POOL_ROUNDROBIN) {
1774						yyerror("nat: only round-robin "
1775						    "valid for multiple "
1776						    "redirection addresses");
1777						YYERROR;
1778					}
1779				} else {
1780					if ((nat.af == AF_INET &&
1781					    unmask(&$7->host->addr.mask,
1782					    nat.af) == 32) ||
1783					    (nat.af == AF_INET6 &&
1784					    unmask(&$7->host->addr.mask,
1785					    nat.af) == 128)) {
1786						nat.rpool.opts = PF_POOL_NONE;
1787					} else {
1788						if ($8.type == PF_POOL_NONE)
1789							nat.rpool.opts =
1790							    PF_POOL_ROUNDROBIN;
1791						else
1792							nat.rpool.opts = $8.type;
1793					}
1794				}
1795			}
1796
1797			if ($8.key != NULL) {
1798				memcpy(&nat.rpool.key, $8.key,
1799				    sizeof(struct pf_poolhashkey));
1800			}
1801
1802			expand_nat(&nat, $3, $5, $6.src.host, $6.src.port,
1803			    $6.dst.host, $6.dst.port,
1804			    $7 == NULL ? NULL : $7->host);
1805			free($7);
1806		}
1807		;
1808
1809binatrule	: no BINAT interface af proto FROM host TO ipspec redirection
1810		{
1811			struct pf_binat binat;
1812
1813			if (check_rulestate(PFCTL_STATE_NAT))
1814				YYERROR;
1815
1816			memset(&binat, 0, sizeof(binat));
1817
1818			binat.no = $1;
1819			if ($3 != NULL) {
1820				memcpy(binat.ifname, $3->ifname,
1821				    sizeof(binat.ifname));
1822				free($3);
1823			}
1824			binat.af = $4;
1825			if ($5 != NULL) {
1826				binat.proto = $5->proto;
1827				free($5);
1828			}
1829			if ($7 != NULL && $9 != NULL && $7->af != $9->af) {
1830				yyerror("binat ip versions must match");
1831				YYERROR;
1832			}
1833			if ($7 != NULL) {
1834				if ($7->next) {
1835					yyerror("multiple binat ip addresses");
1836					YYERROR;
1837				}
1838				if ($7->addr.addr_dyn != NULL) {
1839					if (!binat.af) {
1840						yyerror("address family (inet/"
1841						    "inet6) undefined");
1842						YYERROR;
1843					}
1844					$7->af = binat.af;
1845				}
1846				if (binat.af && $7->af != binat.af) {
1847					yyerror("binat ip versions must match");
1848					YYERROR;
1849				}
1850				binat.af = $7->af;
1851				memcpy(&binat.saddr.addr, &$7->addr.addr,
1852				    sizeof(binat.saddr.addr));
1853				memcpy(&binat.saddr.mask, &$7->addr.mask,
1854				    sizeof(binat.saddr.mask));
1855				free($7);
1856			}
1857			if ($9 != NULL) {
1858				if ($9->next) {
1859					yyerror("multiple binat ip addresses");
1860					YYERROR;
1861				}
1862				if ($9->addr.addr_dyn != NULL) {
1863					if (!binat.af) {
1864						yyerror("address family (inet/"
1865						    "inet6) undefined");
1866						YYERROR;
1867					}
1868					$9->af = binat.af;
1869				}
1870				if (binat.af && $9->af != binat.af) {
1871					yyerror("binat ip versions must match");
1872					YYERROR;
1873				}
1874				binat.af = $9->af;
1875				memcpy(&binat.daddr.addr, &$9->addr.addr,
1876				    sizeof(binat.daddr.addr));
1877				memcpy(&binat.daddr.mask, &$9->addr.mask,
1878				    sizeof(binat.daddr.mask));
1879				binat.dnot  = $9->not;
1880				free($9);
1881			}
1882
1883			if (binat.no) {
1884				if ($10 != NULL) {
1885					yyerror("'no binat' rule does not need"
1886					    " '->'");
1887					YYERROR;
1888				}
1889			} else {
1890				if ($10 == NULL || $10->host == NULL) {
1891					yyerror("'binat' rule requires"
1892					    " '-> address'");
1893					YYERROR;
1894				}
1895
1896				remove_invalid_hosts(&$10->host, &binat.af);
1897				if ($10->host == NULL)
1898					YYERROR;
1899				if ($10->host->next != NULL) {
1900					yyerror("binat rule must redirect to a single "
1901					    "address");
1902					YYERROR;
1903				}
1904				memcpy(&binat.raddr.addr, &$10->host->addr.addr,
1905				    sizeof(binat.raddr.addr));
1906				memcpy(&binat.raddr.mask, &$10->host->addr.mask,
1907				    sizeof(binat.raddr.mask));
1908				if (!PF_AZERO(&binat.saddr.mask, binat.af) &&
1909				    !PF_AEQ(&binat.saddr.mask,
1910				    &binat.raddr.mask, binat.af)) {
1911					yyerror("'binat' source mask and "
1912					    "redirect mask must be the same");
1913					YYERROR;
1914				}
1915				free($10);
1916			}
1917
1918			pfctl_add_binat(pf, &binat);
1919		}
1920		;
1921
1922rdrrule		: no RDR interface af proto FROM ipspec TO ipspec dport redirpool pooltype
1923		{
1924			struct pf_rdr rdr;
1925
1926			if (check_rulestate(PFCTL_STATE_NAT))
1927				YYERROR;
1928
1929			memset(&rdr, 0, sizeof(rdr));
1930
1931			rdr.no = $1;
1932			rdr.af = $4;
1933			if ($7 != NULL) {
1934				memcpy(&rdr.saddr.addr, &$7->addr.addr,
1935				    sizeof(rdr.saddr.addr));
1936				memcpy(&rdr.saddr.mask, &$7->addr.mask,
1937				    sizeof(rdr.saddr.mask));
1938				rdr.snot  = $7->not;
1939				if (!rdr.af && !$7->ifindex)
1940					rdr.af = $7->af;
1941			}
1942			if ($9 != NULL) {
1943				memcpy(&rdr.daddr.addr, &$9->addr.addr,
1944				    sizeof(rdr.daddr.addr));
1945				memcpy(&rdr.daddr.mask, &$9->addr.mask,
1946				    sizeof(rdr.daddr.mask));
1947				rdr.dnot  = $9->not;
1948				if (!rdr.af && !$9->ifindex)
1949					rdr.af = $9->af;
1950			}
1951
1952			rdr.dport  = $10.a;
1953			rdr.dport2 = $10.b;
1954			rdr.opts  |= $10.t;
1955
1956			if ($12.type == PF_POOL_NONE)
1957				rdr.rpool.opts = PF_POOL_RANDOM;
1958			else
1959				rdr.rpool.opts = $12.type;
1960
1961			if (rdr.no) {
1962				if ($11 != NULL) {
1963					yyerror("'no rdr' rule does not need '->'");
1964					YYERROR;
1965				}
1966			} else {
1967				if ($11 == NULL || $11->host == NULL) {
1968					yyerror("'rdr' rule requires '-> "
1969					    "address'");
1970					YYERROR;
1971				}
1972				if (!rdr.af && !$11->host->ifindex)
1973					rdr.af = $11->host->af;
1974
1975				remove_invalid_hosts(&$11->host, &rdr.af);
1976				if ($11->host == NULL)
1977					YYERROR;
1978				rdr.rport  = $11->rport.a;
1979				rdr.opts  |= $11->rport.t;
1980
1981				if ($11->host->next) {
1982					rdr.rpool.opts = $12.type;
1983					if (rdr.rpool.opts == PF_POOL_NONE)
1984						rdr.rpool.opts =
1985						    PF_POOL_ROUNDROBIN;
1986					if (rdr.rpool.opts !=
1987					    PF_POOL_ROUNDROBIN) {
1988						yyerror("rdr: only round-robin "
1989						    "valid for multiple "
1990						    "redirection addresses");
1991						YYERROR;
1992					}
1993				} else {
1994					if ((rdr.af == AF_INET &&
1995					    unmask(&$11->host->addr.mask,
1996					    rdr.af) == 32) ||
1997					    (rdr.af == AF_INET6 &&
1998					    unmask(&$11->host->addr.mask,
1999					    rdr.af) == 128)) {
2000						rdr.rpool.opts = PF_POOL_NONE;
2001					} else {
2002						if ($12.type == PF_POOL_NONE)
2003							rdr.rpool.opts =
2004							    PF_POOL_ROUNDROBIN;
2005						else
2006							rdr.rpool.opts =
2007							    $12.type;
2008					}
2009				}
2010			}
2011
2012			if ($12.key != NULL) {
2013				memcpy(&rdr.rpool.key, $12.key,
2014				    sizeof(struct pf_poolhashkey));
2015			}
2016
2017			expand_rdr(&rdr, $3, $5, $7, $9,
2018			    $11 == NULL ? NULL : $11->host);
2019		}
2020		;
2021
2022dport		: /* empty */			{
2023			$$.a = $$.b = $$.t = 0;
2024		}
2025		| PORT STRING			{
2026			char *p = strchr($2, ':');
2027
2028			if (p == NULL) {
2029				if (($$.a = getservice($2)) == -1)
2030					YYERROR;
2031				$$.b = $$.t = 0;
2032			} else {
2033				*p++ = 0;
2034				if (($$.a = getservice($2)) == -1 ||
2035				    ($$.b = getservice(p)) == -1)
2036					YYERROR;
2037				$$.t = PF_DPORT_RANGE;
2038			}
2039		}
2040		;
2041
2042route_host	: STRING			{
2043			$$ = calloc(1, sizeof(struct node_host));
2044			if ($$ == NULL)
2045				err(1, "route_host: calloc");
2046			if (($$->ifname = strdup($1)) == NULL) {
2047				yyerror("routeto: strdup");
2048				YYERROR;
2049			}
2050			if (ifa_exists($$->ifname) == NULL) {
2051				yyerror("routeto: unknown interface %s",
2052				    $$->ifname);
2053				YYERROR;
2054			}
2055			$$->next = NULL;
2056			$$->tail = $$;
2057		}
2058		| '(' STRING host ')'		{
2059			$$ = $3;
2060			if (($$->ifname = strdup($2)) == NULL) {
2061				yyerror("routeto: strdup");
2062				YYERROR;
2063			}
2064			if (ifa_exists($$->ifname) == NULL) {
2065				yyerror("routeto: unknown interface %s",
2066				    $$->ifname);
2067				YYERROR;
2068			}
2069		}
2070		;
2071
2072route_host_list	: route_host				{ $$ = $1; }
2073		| route_host_list comma route_host	{
2074			if ($1->af == 0)
2075				$1->af = $3->af;
2076			if ($1->af != $3->af) {
2077				yyerror("all pool addresses must be in the "
2078				    "same address family");
2079				YYERROR;
2080			}
2081			/* $3 may be a list, so use its tail pointer */
2082			$1->tail->next = $3->tail;
2083			$1->tail = $3->tail;
2084			$$ = $1;
2085		}
2086		;
2087
2088routespec	: route_host			{ $$ = $1; }
2089		| '{' route_host_list '}'	{ $$ = $2; }
2090		;
2091
2092
2093route		: /* empty */			{
2094			$$.host = NULL;
2095			$$.rt = 0;
2096			$$.pool_opts = 0;
2097		}
2098		| FASTROUTE {
2099			$$.host = NULL;
2100			$$.rt = PF_FASTROUTE;
2101			$$.pool_opts = 0;
2102		}
2103		| ROUTETO routespec pooltype {
2104			$$.host = $2;
2105			$$.rt = PF_ROUTETO;
2106			if ($3.key != NULL)
2107				$$.key = $3.key;
2108		}
2109		| REPLYTO routespec pooltype {
2110			$$.host = $2;
2111			$$.rt = PF_REPLYTO;
2112			if ($3.key != NULL)
2113				$$.key = $3.key;
2114		}
2115		| DUPTO routespec pooltype {
2116			$$.host = $2;
2117			$$.rt = PF_DUPTO;
2118			if ($3.key != NULL)
2119				$$.key = $3.key;
2120		}
2121		;
2122
2123timeout_spec	: STRING number
2124		{
2125			if (pf->opts & PF_OPT_VERBOSE)
2126				printf("set timeout %s %us\n", $1, $2);
2127			if (check_rulestate(PFCTL_STATE_OPTION))
2128				YYERROR;
2129			if (pfctl_set_timeout(pf, $1, $2) != 0) {
2130				yyerror("unknown timeout %s", $1);
2131				YYERROR;
2132			}
2133		}
2134		;
2135
2136timeout_list	: timeout_list comma timeout_spec
2137		| timeout_spec
2138		;
2139
2140limit_spec	: STRING number
2141		{
2142			if (pf->opts & PF_OPT_VERBOSE)
2143				printf("set limit %s %u\n", $1, $2);
2144			if (check_rulestate(PFCTL_STATE_OPTION))
2145				YYERROR;
2146			if (pfctl_set_limit(pf, $1, $2) != 0) {
2147				yyerror("unable to set limit %s %u", $1, $2);
2148				YYERROR;
2149			}
2150		}
2151
2152limit_list	: limit_list comma limit_spec
2153		| limit_spec
2154		;
2155
2156comma		: ','
2157		| /* empty */
2158		;
2159
2160%%
2161
2162int
2163yyerror(char *fmt, ...)
2164{
2165	va_list ap;
2166	extern char *infile;
2167	errors = 1;
2168
2169	va_start(ap, fmt);
2170	fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
2171	vfprintf(stderr, fmt, ap);
2172	fprintf(stderr, "\n");
2173	va_end(ap);
2174	return (0);
2175}
2176
2177int
2178rule_consistent(struct pf_rule *r)
2179{
2180	int problems = 0;
2181
2182	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
2183	    (r->src.port_op || r->dst.port_op)) {
2184		yyerror("port only applies to tcp/udp");
2185		problems++;
2186	}
2187	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
2188	    (r->type || r->code)) {
2189		yyerror("icmp-type/code only applies to icmp");
2190		problems++;
2191	}
2192	if (!r->af && (r->type || r->code)) {
2193		yyerror("must indicate address family with icmp-type/code");
2194		problems++;
2195	}
2196	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
2197	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
2198		yyerror("icmp version does not match address family");
2199		problems++;
2200	}
2201	if (r->keep_state == PF_STATE_MODULATE && r->proto &&
2202	    r->proto != IPPROTO_TCP) {
2203		yyerror("modulate state can only be applied to TCP rules");
2204		problems++;
2205	}
2206	if (r->allow_opts && r->action != PF_PASS) {
2207		yyerror("allow-opts can only be specified for pass rules");
2208		problems++;
2209	}
2210	if (!r->af && (r->src.addr.addr_dyn != NULL ||
2211	    r->dst.addr.addr_dyn != NULL)) {
2212		yyerror("dynamic addresses require address family (inet/inet6)");
2213		problems++;
2214	}
2215	if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
2216	    r->dst.port_op || r->flagset || r->type || r->code)) {
2217		yyerror("fragments can be filtered only on IP header fields");
2218		problems++;
2219	}
2220	if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
2221		yyerror("return-rst can only be applied to TCP rules");
2222		problems++;
2223	}
2224	if (r->action == PF_DROP && r->keep_state) {
2225		yyerror("keep state on block rules doesn't make sense");
2226		problems++;
2227	}
2228	return (-problems);
2229}
2230
2231int
2232nat_consistent(struct pf_nat *r)
2233{
2234	int problems = 0;
2235	struct pf_pooladdr *pa;
2236
2237	if (!r->af) {
2238		TAILQ_FOREACH(pa, &r->rpool.list, entries) {
2239			if (pa->addr.addr_dyn != NULL) {
2240				yyerror("dynamic addresses require "
2241				    "address family (inet/inet6)");
2242				problems++;
2243				break;
2244			}
2245		}
2246	}
2247	return (-problems);
2248}
2249
2250int
2251rdr_consistent(struct pf_rdr *r)
2252{
2253	int problems = 0;
2254	struct pf_pooladdr *pa;
2255
2256	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
2257	    (r->dport || r->dport2 || r->rport)) {
2258		yyerror("port only applies to tcp/udp");
2259		problems++;
2260	}
2261	if (!r->af) {
2262		if (r->saddr.addr_dyn != NULL || r->daddr.addr_dyn != NULL) {
2263			yyerror("dynamic addresses require address family "
2264			    "(inet/inet6)");
2265			problems++;
2266		} else {
2267			TAILQ_FOREACH(pa, &r->rpool.list, entries) {
2268				if (pa->addr.addr_dyn != NULL) {
2269					yyerror("dynamic addresses require "
2270					    "address family (inet/inet6)");
2271					problems++;
2272					break;
2273				}
2274			}
2275		}
2276	}
2277	return (-problems);
2278}
2279
2280struct keywords {
2281	const char	*k_name;
2282	int	 k_val;
2283};
2284
2285/* macro gore, but you should've seen the prior indentation nightmare... */
2286
2287#define FREE_LIST(T,r) \
2288	do { \
2289		T *p, *n = r; \
2290		while (n != NULL) { \
2291			p = n; \
2292			n = n->next; \
2293			free(p); \
2294		} \
2295	} while (0)
2296
2297#define LOOP_THROUGH(T,n,r,C) \
2298	do { \
2299		T *n; \
2300		if (r == NULL) { \
2301			r = calloc(1, sizeof(T)); \
2302			if (r == NULL) \
2303				err(1, "LOOP: calloc"); \
2304			r->next = NULL; \
2305		} \
2306		n = r; \
2307		while (n != NULL) { \
2308			do { \
2309				C; \
2310			} while (0); \
2311			n = n->next; \
2312		} \
2313	} while (0)
2314
2315void
2316expand_label_if(const char *name, char *label, const char *ifname)
2317{
2318	char tmp[PF_RULE_LABEL_SIZE];
2319	char *p;
2320
2321	while ((p = strstr(label, name)) != NULL) {
2322		tmp[0] = 0;
2323		strlcat(tmp, label, p-label+1);
2324		if (!*ifname)
2325			strlcat(tmp, "any", PF_RULE_LABEL_SIZE);
2326		else
2327			strlcat(tmp, ifname, PF_RULE_LABEL_SIZE);
2328		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
2329		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2330	}
2331}
2332
2333void
2334expand_label_addr(const char *name, char *label, sa_family_t af,
2335    struct node_host *host)
2336{
2337	char tmp[PF_RULE_LABEL_SIZE];
2338	char *p;
2339
2340	while ((p = strstr(label, name)) != NULL) {
2341		tmp[0] = 0;
2342
2343		strlcat(tmp, label, p-label+1);
2344
2345		if (host->not)
2346			strlcat(tmp, "! ", PF_RULE_LABEL_SIZE);
2347		if (host->addr.addr_dyn != NULL) {
2348			strlcat(tmp, "(", PF_RULE_LABEL_SIZE);
2349			strlcat(tmp, host->addr.addr.pfa.ifname,
2350			    PF_RULE_LABEL_SIZE);
2351			strlcat(tmp, ")", PF_RULE_LABEL_SIZE);
2352		} else if (!af || (PF_AZERO(&host->addr.addr, af) &&
2353		    PF_AZERO(&host->addr.mask, af)))
2354			strlcat(tmp, "any", PF_RULE_LABEL_SIZE);
2355		else {
2356			char a[48];
2357			int bits;
2358
2359			if (inet_ntop(af, &host->addr.addr, a,
2360			    sizeof(a)) == NULL)
2361				strlcat(a, "?", sizeof(a));
2362			strlcat(tmp, a, PF_RULE_LABEL_SIZE);
2363			bits = unmask(&host->addr.mask, af);
2364			a[0] = 0;
2365			if ((af == AF_INET && bits < 32) ||
2366			    (af == AF_INET6 && bits < 128))
2367				snprintf(a, sizeof(a), "/%d", bits);
2368			strlcat(tmp, a, PF_RULE_LABEL_SIZE);
2369		}
2370		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
2371		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2372	}
2373}
2374
2375void
2376expand_label_port(const char *name, char *label, struct node_port *port)
2377{
2378	char tmp[PF_RULE_LABEL_SIZE];
2379	char *p;
2380	char a1[6], a2[6], op[13];
2381
2382	while ((p = strstr(label, name)) != NULL) {
2383		tmp[0] = 0;
2384
2385		strlcat(tmp, label, p-label+1);
2386
2387		snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
2388		snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
2389		if (!port->op)
2390			op[0] = 0;
2391		else if (port->op == PF_OP_IRG)
2392			snprintf(op, sizeof(op), "%s><%s", a1, a2);
2393		else if (port->op == PF_OP_XRG)
2394			snprintf(op, sizeof(op), "%s<>%s", a1, a2);
2395		else if (port->op == PF_OP_EQ)
2396			snprintf(op, sizeof(op), "%s", a1);
2397		else if (port->op == PF_OP_NE)
2398			snprintf(op, sizeof(op), "!=%s", a1);
2399		else if (port->op == PF_OP_LT)
2400			snprintf(op, sizeof(op), "<%s", a1);
2401		else if (port->op == PF_OP_LE)
2402			snprintf(op, sizeof(op), "<=%s", a1);
2403		else if (port->op == PF_OP_GT)
2404			snprintf(op, sizeof(op), ">%s", a1);
2405		else if (port->op == PF_OP_GE)
2406			snprintf(op, sizeof(op), ">=%s", a1);
2407		strlcat(tmp, op, PF_RULE_LABEL_SIZE);
2408		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
2409		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2410	}
2411}
2412
2413void
2414expand_label_proto(const char *name, char *label, u_int8_t proto)
2415{
2416	char tmp[PF_RULE_LABEL_SIZE];
2417	char *p;
2418	struct protoent *pe;
2419
2420	while ((p = strstr(label, name)) != NULL) {
2421		tmp[0] = 0;
2422		strlcat(tmp, label, p-label+1);
2423		pe = getprotobynumber(proto);
2424		if (pe != NULL)
2425		    strlcat(tmp, pe->p_name, PF_RULE_LABEL_SIZE);
2426		else
2427		    snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp),
2428			"%u", proto);
2429		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
2430		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2431	}
2432}
2433
2434void
2435expand_label_nr(const char *name, char *label)
2436{
2437	char tmp[PF_RULE_LABEL_SIZE];
2438	char *p;
2439
2440	while ((p = strstr(label, name)) != NULL) {
2441		tmp[0] = 0;
2442		strlcat(tmp, label, p-label+1);
2443		snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp),
2444		    "%u", pf->rule_nr);
2445		strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE);
2446		strncpy(label, tmp, PF_RULE_LABEL_SIZE);
2447	}
2448}
2449
2450void
2451expand_label(char *label, const char *ifname, sa_family_t af,
2452    struct node_host *src_host, struct node_port *src_port,
2453    struct node_host *dst_host, struct node_port *dst_port,
2454    u_int8_t proto)
2455{
2456	expand_label_if("$if", label, ifname);
2457	expand_label_addr("$srcaddr", label, af, src_host);
2458	expand_label_addr("$dstaddr", label, af, dst_host);
2459	expand_label_port("$srcport", label, src_port);
2460	expand_label_port("$dstport", label, dst_port);
2461	expand_label_proto("$proto", label, proto);
2462	expand_label_nr("$nr", label);
2463}
2464
2465int
2466expand_altq(struct pf_altq *a, struct node_if *interfaces,
2467    struct node_queue *nqueues)
2468{
2469	struct	pf_altq pa, pb;
2470	char	qname[PF_QNAME_SIZE];
2471	struct	node_queue *n;
2472	int	errors = 0;
2473
2474	LOOP_THROUGH(struct node_if, interface, interfaces,
2475		memcpy(&pa, a, sizeof(struct pf_altq));
2476		strlcpy(pa.ifname, interface->ifname, IFNAMSIZ);
2477
2478		if (interface->not) {
2479			yyerror("altq on ! <interface> is not supported");
2480			errors++;
2481		} else {
2482			if (eval_pfaltq(pf, &pa))
2483				errors++;
2484			else
2485				if (pfctl_add_altq(pf, &pa))
2486					errors++;
2487
2488			if (pf->opts & PF_OPT_VERBOSE) {
2489				print_altq(&pf->paltq->altq, 0);
2490				if (nqueues && nqueues->tail) {
2491					printf("queue { ");
2492					LOOP_THROUGH(struct node_queue, queue,
2493					    nqueues,
2494						printf("%s ",
2495						    queue->queue);
2496					);
2497					printf("}");
2498				}
2499				printf("\n");
2500			}
2501
2502			/* now create a root queue */
2503			memset(&pb, 0, sizeof(struct pf_altq));
2504			strlcpy(qname, "root_", sizeof(qname));
2505			strlcat(qname, interface->ifname, sizeof(qname));
2506			strlcpy(pb.qname, qname, PF_QNAME_SIZE);
2507			strlcpy(pb.ifname, interface->ifname, IFNAMSIZ);
2508			pb.qlimit = pa.qlimit;
2509			pb.scheduler = pa.scheduler;
2510			pb.pq_u.cbq_opts.flags = pa.pq_u.cbq_opts.flags;
2511			if (eval_pfqueue(pf, &pb, pa.ifbandwidth, 0))
2512				errors++;
2513			else
2514				if (pfctl_add_altq(pf, &pb))
2515					errors++;
2516
2517			LOOP_THROUGH(struct node_queue, queue, nqueues,
2518				n = calloc(1, sizeof(struct node_queue));
2519				if (n == NULL)
2520					err(1, "expand_altq: calloc");
2521				strlcpy(n->parent, qname, PF_QNAME_SIZE);
2522				strlcpy(n->queue, queue->queue, PF_QNAME_SIZE);
2523				strlcpy(n->ifname, interface->ifname, IFNAMSIZ);
2524				n->next = NULL;
2525				n->tail = n;
2526				if (queues == NULL)
2527					queues = n;
2528				else {
2529					queues->tail->next = n;
2530					queues->tail = n;
2531				}
2532			);
2533		}
2534	);
2535	FREE_LIST(struct node_if, interfaces);
2536	FREE_LIST(struct node_queue, nqueues);
2537
2538	return(errors);
2539}
2540
2541int
2542expand_queue(struct pf_altq *a, struct node_queue *nqueues,
2543    struct node_queue_bw bwspec)
2544{
2545	struct	node_queue *n;
2546	u_int8_t	added = 0;
2547
2548	LOOP_THROUGH(struct node_queue, tqueue, queues,
2549		if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE)) {
2550			/* found ourselve in queues */
2551			LOOP_THROUGH(struct node_queue, queue, nqueues,
2552				n = calloc(1, sizeof(struct node_queue));
2553				if (n == NULL)
2554					err(1, "expand_queue: calloc");
2555				strlcpy(n->parent, a->qname, PF_QNAME_SIZE);
2556				strlcpy(n->queue, queue->queue, PF_QNAME_SIZE);
2557				strlcpy(n->ifname, tqueue->ifname, IFNAMSIZ);
2558				n->next = NULL;
2559				n->tail = n;
2560				if (queues == NULL)
2561					queues = n;
2562				else {
2563					queues->tail->next = n;
2564					queues->tail = n;
2565				}
2566			);
2567			strlcpy(a->ifname, tqueue->ifname, IFNAMSIZ);
2568			strlcpy(a->parent, tqueue->parent, PF_QNAME_SIZE);
2569
2570			if (!eval_pfqueue(pf, a, bwspec.bw_absolute,
2571			    bwspec.bw_percent))
2572				if(!pfctl_add_altq(pf, a))
2573					added++;
2574
2575			if (pf->opts & PF_OPT_VERBOSE) {
2576				print_altq(&pf->paltq->altq, 0);
2577				if (nqueues && nqueues->tail) {
2578					printf("{ ");
2579					LOOP_THROUGH(struct node_queue, queue,
2580					    nqueues,
2581						printf("%s ", queue->queue);
2582					);
2583					printf("}");
2584				}
2585				printf("\n");
2586			}
2587			FREE_LIST(struct node_queue, nqueues);
2588		}
2589	);
2590
2591	if (!added) {
2592		yyerror("queue has no parent");
2593		return (1);
2594	} else
2595		return (0);
2596}
2597
2598void
2599expand_rule(struct pf_rule *r,
2600    struct node_if *interfaces, struct node_host *rt_pool_hosts,
2601    struct node_proto *protos, struct node_host *src_hosts,
2602    struct node_port *src_ports, struct node_host *dst_hosts,
2603    struct node_port *dst_ports, struct node_uid *uids,
2604    struct node_gid *gids, struct node_icmp *icmp_types)
2605{
2606	sa_family_t	af = r->af;
2607	int added = 0, error = 0;
2608	char	ifname[IF_NAMESIZE];
2609	char	label[PF_RULE_LABEL_SIZE];
2610	struct pf_pooladdr *pa;
2611	struct node_host *h;
2612	char	qname[PF_QNAME_SIZE];
2613	u_int8_t flags, flagset;
2614
2615	strlcpy(label, r->label, sizeof(label));
2616	strlcpy(qname, r->qname, sizeof(qname));
2617	flags = r->flags;
2618	flagset = r->flagset;
2619
2620	LOOP_THROUGH(struct node_if, interface, interfaces,
2621	LOOP_THROUGH(struct node_proto, proto, protos,
2622	LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
2623	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2624	LOOP_THROUGH(struct node_port, src_port, src_ports,
2625	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2626	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
2627	LOOP_THROUGH(struct node_uid, uid, uids,
2628	LOOP_THROUGH(struct node_gid, gid, gids,
2629
2630		r->af = af;
2631		/* for link-local IPv6 address, interface must match up */
2632		if ((r->af && src_host->af && r->af != src_host->af) ||
2633		    (r->af && dst_host->af && r->af != dst_host->af) ||
2634		    (src_host->af && dst_host->af &&
2635		    src_host->af != dst_host->af) ||
2636		    (src_host->ifindex && dst_host->ifindex &&
2637		    src_host->ifindex != dst_host->ifindex) ||
2638		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2639		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2640		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2641		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2642			continue;
2643		if (!r->af && src_host->af)
2644			r->af = src_host->af;
2645		else if (!r->af && dst_host->af)
2646			r->af = dst_host->af;
2647
2648		if (if_indextoname(src_host->ifindex, ifname))
2649			memcpy(r->ifname, ifname, sizeof(r->ifname));
2650		else if (if_indextoname(dst_host->ifindex, ifname))
2651			memcpy(r->ifname, ifname, sizeof(r->ifname));
2652		else
2653			memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
2654
2655		strlcpy(r->label, label, PF_RULE_LABEL_SIZE);
2656		expand_label(r->label, r->ifname, r->af, src_host, src_port,
2657		    dst_host, dst_port, proto->proto);
2658		strlcpy(r->qname, qname, PF_QNAME_SIZE);
2659		r->qid = qname_to_qid(qname, r->ifname);
2660		r->ifnot = interface->not;
2661		r->proto = proto->proto;
2662		r->src.addr = src_host->addr;
2663		r->src.noroute = src_host->noroute;
2664		r->src.not = src_host->not;
2665		r->src.port[0] = src_port->port[0];
2666		r->src.port[1] = src_port->port[1];
2667		r->src.port_op = src_port->op;
2668		r->dst.addr = dst_host->addr;
2669		r->dst.noroute = dst_host->noroute;
2670		r->dst.not = dst_host->not;
2671		r->dst.port[0] = dst_port->port[0];
2672		r->dst.port[1] = dst_port->port[1];
2673		r->dst.port_op = dst_port->op;
2674		r->uid.op = uid->op;
2675		r->uid.uid[0] = uid->uid[0];
2676		r->uid.uid[1] = uid->uid[1];
2677		r->gid.op = gid->op;
2678		r->gid.gid[0] = gid->gid[0];
2679		r->gid.gid[1] = gid->gid[1];
2680		r->type = icmp_type->type;
2681		r->code = icmp_type->code;
2682
2683		if (r->proto && r->proto != IPPROTO_TCP) {
2684			r->flags = 0;
2685			r->flagset = 0;
2686		} else {
2687			r->flags = flags;
2688			r->flagset = flagset;
2689		}
2690		if (icmp_type->proto && r->proto != icmp_type->proto) {
2691			yyerror("icmp-type mismatch");
2692			error++;
2693		}
2694
2695		TAILQ_INIT(&r->rt_pool.list);
2696		for (h = rt_pool_hosts; h != NULL; h = h->next) {
2697			pa = calloc(1, sizeof(struct pf_pooladdr));
2698			if (pa == NULL) {
2699				yyerror("calloc");
2700				error++;
2701			}
2702			pa->addr = h->addr;
2703			if (h->ifname != NULL)
2704				strncpy(pa->ifname, h->ifname, IFNAMSIZ);
2705			else
2706				pa->ifname[0] = 0;
2707			TAILQ_INSERT_TAIL(&r->rt_pool.list, pa, entries);
2708		}
2709
2710		if (rule_consistent(r) < 0 || error)
2711			yyerror("skipping filter rule due to errors");
2712		else {
2713			r->nr = pf->rule_nr++;
2714			pfctl_add_rule(pf, r);
2715			added++;
2716		}
2717
2718	)))))))));
2719
2720	FREE_LIST(struct node_if, interfaces);
2721	FREE_LIST(struct node_proto, protos);
2722	FREE_LIST(struct node_host, src_hosts);
2723	FREE_LIST(struct node_port, src_ports);
2724	FREE_LIST(struct node_host, dst_hosts);
2725	FREE_LIST(struct node_port, dst_ports);
2726	FREE_LIST(struct node_uid, uids);
2727	FREE_LIST(struct node_gid, gids);
2728	FREE_LIST(struct node_icmp, icmp_types);
2729	FREE_LIST(struct node_host, rt_pool_hosts);
2730
2731	if (!added)
2732		yyerror("rule expands to no valid combination");
2733}
2734
2735void
2736expand_nat(struct pf_nat *n,
2737    struct node_if *interfaces, struct node_proto *protos,
2738    struct node_host *src_hosts, struct node_port *src_ports,
2739    struct node_host *dst_hosts, struct node_port *dst_ports,
2740    struct node_host *rpool_hosts)
2741{
2742	char ifname[IF_NAMESIZE];
2743	struct pf_pooladdr *pa;
2744	struct node_host *h;
2745	sa_family_t af = n->af;
2746	int added = 0, error = 0;
2747
2748	LOOP_THROUGH(struct node_if, interface, interfaces,
2749	LOOP_THROUGH(struct node_proto, proto, protos,
2750	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2751	LOOP_THROUGH(struct node_port, src_port, src_ports,
2752	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2753	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
2754
2755		n->af = af;
2756		/* for link-local IPv6 address, interface must match up */
2757		if ((n->af && src_host->af && n->af != src_host->af) ||
2758		    (n->af && dst_host->af && n->af != dst_host->af) ||
2759		    (src_host->af && dst_host->af &&
2760		    src_host->af != dst_host->af) ||
2761		    (src_host->ifindex && dst_host->ifindex &&
2762		    src_host->ifindex != dst_host->ifindex) ||
2763		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2764		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2765		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2766		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2767			continue;
2768		if (!n->af && src_host->af)
2769			n->af = src_host->af;
2770		else if (!n->af && dst_host->af)
2771			n->af = dst_host->af;
2772
2773		if (if_indextoname(src_host->ifindex, ifname))
2774			memcpy(n->ifname, ifname, sizeof(n->ifname));
2775		else if (if_indextoname(dst_host->ifindex, ifname))
2776			memcpy(n->ifname, ifname, sizeof(n->ifname));
2777		else
2778			memcpy(n->ifname, interface->ifname, sizeof(n->ifname));
2779
2780		n->ifnot = interface->not;
2781		n->proto = proto->proto;
2782		n->src.addr = src_host->addr;
2783		n->src.noroute = src_host->noroute;
2784		n->src.not = src_host->not;
2785		n->src.port[0] = src_port->port[0];
2786		n->src.port[1] = src_port->port[1];
2787		n->src.port_op = src_port->op;
2788		n->dst.addr = dst_host->addr;
2789		n->dst.noroute = dst_host->noroute;
2790		n->dst.not = dst_host->not;
2791		n->dst.port[0] = dst_port->port[0];
2792		n->dst.port[1] = dst_port->port[1];
2793		n->dst.port_op = dst_port->op;
2794
2795		TAILQ_INIT(&n->rpool.list);
2796		for (h = rpool_hosts; h != NULL; h = h->next) {
2797			pa = calloc(1, sizeof(struct pf_pooladdr));
2798			if (pa == NULL) {
2799				yyerror("calloc");
2800				error++;
2801			}
2802			pa->addr = h->addr;
2803			pa->ifname[0] = 0;
2804			TAILQ_INSERT_TAIL(&n->rpool.list, pa, entries);
2805		}
2806
2807		if (nat_consistent(n) < 0 || error)
2808			yyerror("skipping nat rule due to errors");
2809		else {
2810			pfctl_add_nat(pf, n);
2811			added++;
2812		}
2813
2814	))))));
2815
2816	FREE_LIST(struct node_if, interfaces);
2817	FREE_LIST(struct node_proto, protos);
2818	FREE_LIST(struct node_host, src_hosts);
2819	FREE_LIST(struct node_port, src_ports);
2820	FREE_LIST(struct node_host, dst_hosts);
2821	FREE_LIST(struct node_port, dst_ports);
2822	FREE_LIST(struct node_host, rpool_hosts);
2823
2824	if (!added)
2825		yyerror("nat rule expands to no valid combinations");
2826}
2827
2828void
2829expand_rdr(struct pf_rdr *r, struct node_if *interfaces,
2830    struct node_proto *protos, struct node_host *src_hosts,
2831    struct node_host *dst_hosts, struct node_host *rpool_hosts)
2832{
2833	sa_family_t af = r->af;
2834	int added = 0, error = 0;
2835	char ifname[IF_NAMESIZE];
2836	struct pf_pooladdr *pa;
2837	struct node_host *h;
2838
2839	LOOP_THROUGH(struct node_if, interface, interfaces,
2840	LOOP_THROUGH(struct node_proto, proto, protos,
2841	LOOP_THROUGH(struct node_host, src_host, src_hosts,
2842	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
2843
2844		r->af = af;
2845		if ((r->af && src_host->af && r->af != src_host->af) ||
2846		    (r->af && dst_host->af && r->af != dst_host->af) ||
2847		    (src_host->af && dst_host->af &&
2848		    src_host->af != dst_host->af) ||
2849		    (src_host->ifindex && dst_host->ifindex &&
2850		    src_host->ifindex != dst_host->ifindex) ||
2851		    (src_host->ifindex && if_nametoindex(interface->ifname) &&
2852		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
2853		    (dst_host->ifindex && if_nametoindex(interface->ifname) &&
2854		    dst_host->ifindex != if_nametoindex(interface->ifname)))
2855			continue;
2856
2857		if (!r->af && src_host->af)
2858			r->af = src_host->af;
2859		else if (!r->af && dst_host->af)
2860			r->af = dst_host->af;
2861
2862		if (if_indextoname(src_host->ifindex, ifname))
2863			memcpy(r->ifname, ifname, sizeof(r->ifname));
2864		else if (if_indextoname(dst_host->ifindex, ifname))
2865			memcpy(r->ifname, ifname, sizeof(r->ifname));
2866		else
2867			memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
2868
2869		r->proto = proto->proto;
2870		r->ifnot = interface->not;
2871		r->saddr = src_host->addr;
2872		r->daddr = dst_host->addr;
2873
2874		TAILQ_INIT(&r->rpool.list);
2875		for (h = rpool_hosts; h != NULL; h = h->next) {
2876			pa = calloc(1, sizeof(struct pf_pooladdr));
2877			if (pa == NULL) {
2878				yyerror("calloc");
2879				error++;
2880			}
2881			pa->addr = h->addr;
2882			pa->ifname[0] = 0;
2883			TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
2884		}
2885
2886		if (rdr_consistent(r) < 0 || error)
2887			yyerror("skipping rdr rule due to errors");
2888		else {
2889			pfctl_add_rdr(pf, r);
2890			added++;
2891		}
2892
2893	))));
2894
2895	FREE_LIST(struct node_if, interfaces);
2896	FREE_LIST(struct node_proto, protos);
2897	FREE_LIST(struct node_host, src_hosts);
2898	FREE_LIST(struct node_host, dst_hosts);
2899	FREE_LIST(struct node_host, rpool_hosts);
2900
2901	if (!added)
2902		yyerror("rdr rule expands to no valid combination");
2903}
2904
2905#undef FREE_LIST
2906#undef LOOP_THROUGH
2907
2908int
2909check_rulestate(int desired_state)
2910{
2911	if (require_order && (rulestate > desired_state)) {
2912		yyerror("Rules must be in order: options, scrub, "
2913		    "queue, NAT, filter");
2914		return (1);
2915	}
2916	rulestate = desired_state;
2917	return (0);
2918}
2919
2920int
2921kw_cmp(const void *k, const void *e)
2922{
2923	return (strcmp(k, ((const struct keywords *)e)->k_name));
2924}
2925
2926int
2927lookup(char *s)
2928{
2929	/* this has to be sorted always */
2930	static const struct keywords keywords[] = {
2931		{ "all",	ALL},
2932		{ "allow-opts",	ALLOWOPTS},
2933		{ "altq",	ALTQ},
2934		{ "antispoof",	ANTISPOOF},
2935		{ "any",	ANY},
2936		{ "bandwidth",	BANDWIDTH},
2937		{ "binat",	BINAT},
2938		{ "bitmask",	BITMASK},
2939		{ "block",	BLOCK},
2940		{ "block-policy", BLOCKPOLICY},
2941		{ "borrow",	BORROW},
2942		{ "cbq",	CBQ},
2943		{ "code",	CODE},
2944		{ "control",	CONTROL},
2945		{ "crop",	FRAGCROP},
2946		{ "default",	DEFAULT},
2947		{ "drop",	DROP},
2948		{ "drop-ovl",	FRAGDROP},
2949		{ "dup-to",	DUPTO},
2950		{ "ecn",	ECN},
2951		{ "fastroute",	FASTROUTE},
2952		{ "flags",	FLAGS},
2953		{ "for",	FOR},
2954		{ "fragment",	FRAGMENT},
2955		{ "from",	FROM},
2956		{ "group",	GROUP},
2957		{ "icmp-type",	ICMPTYPE},
2958		{ "in",		IN},
2959		{ "inet",	INET},
2960		{ "inet6",	INET6},
2961		{ "ipv6-icmp-type", ICMP6TYPE},
2962		{ "keep",	KEEP},
2963		{ "label",	LABEL},
2964		{ "limit",	LIMIT},
2965		{ "log",	LOG},
2966		{ "log-all",	LOGALL},
2967		{ "loginterface", LOGINTERFACE},
2968		{ "max",	MAXIMUM},
2969		{ "max-mss",	MAXMSS},
2970		{ "min-ttl",	MINTTL},
2971		{ "modulate",	MODULATE},
2972		{ "nat",	NAT},
2973		{ "no",		NO},
2974		{ "no-df",	NODF},
2975		{ "no-route",	NOROUTE},
2976		{ "on",		ON},
2977		{ "optimization", OPTIMIZATION},
2978		{ "out",	OUT},
2979		{ "pass",	PASS},
2980		{ "port",	PORT},
2981		{ "priority",	PRIORITY},
2982		{ "proto",	PROTO},
2983		{ "qlimit",	QLIMIT},
2984		{ "queue",	QUEUE},
2985		{ "quick",	QUICK},
2986		{ "random",	RANDOM},
2987		{ "rdr",	RDR},
2988		{ "reassemble",	FRAGNORM},
2989		{ "red",	RED},
2990		{ "reply-to",	REPLYTO},
2991		{ "require-order", REQUIREORDER},
2992		{ "return",	RETURN},
2993		{ "return-icmp",RETURNICMP},
2994		{ "return-icmp6",RETURNICMP6},
2995		{ "return-rst",	RETURNRST},
2996		{ "rio",	RIO},
2997		{ "round-robin",ROUNDROBIN},
2998		{ "route-to",	ROUTETO},
2999		{ "scheduler",	SCHEDULER},
3000		{ "scrub",	SCRUB},
3001		{ "set",	SET},
3002		{ "source-hash",SOURCEHASH},
3003		{ "state",	STATE},
3004		{ "tbrsize",	TBRSIZE},
3005		{ "timeout",	TIMEOUT},
3006		{ "to",		TO},
3007		{ "tos",	TOS},
3008		{ "ttl",	TTL},
3009		{ "user",	USER},
3010		{ "yes",	YES},
3011	};
3012	const struct keywords *p;
3013
3014	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
3015	    sizeof(keywords[0]), kw_cmp);
3016
3017	if (p) {
3018		if (debug > 1)
3019			fprintf(stderr, "%s: %d\n", s, p->k_val);
3020		return (p->k_val);
3021	} else {
3022		if (debug > 1)
3023			fprintf(stderr, "string: %s\n", s);
3024		return (STRING);
3025	}
3026}
3027
3028#define MAXPUSHBACK	128
3029
3030char	*parsebuf;
3031int	parseindex;
3032char	pushback_buffer[MAXPUSHBACK];
3033int	pushback_index = 0;
3034
3035int
3036lgetc(FILE *fin)
3037{
3038	int c, next;
3039
3040	if (parsebuf) {
3041		/* Read character from the parsebuffer instead of input. */
3042		if (parseindex >= 0) {
3043			c = parsebuf[parseindex++];
3044			if (c != '\0')
3045				return (c);
3046			parsebuf = NULL;
3047		} else
3048			parseindex++;
3049	}
3050
3051	if (pushback_index)
3052		return (pushback_buffer[--pushback_index]);
3053
3054	while ((c = getc(fin)) == '\\') {
3055		next = getc(fin);
3056		if (next != '\n') {
3057			if (isspace(next))
3058				yyerror("whitespace after \\");
3059			ungetc(next, fin);
3060			break;
3061		}
3062		yylval.lineno = lineno;
3063		lineno++;
3064	}
3065	if (c == '\t' || c == ' ') {
3066		/* Compress blanks to a single space. */
3067		do {
3068			c = getc(fin);
3069		} while (c == '\t' || c == ' ');
3070		ungetc(c, fin);
3071		c = ' ';
3072	}
3073
3074	return (c);
3075}
3076
3077int
3078lungetc(int c, FILE *fin)
3079{
3080	if (c == EOF)
3081		return (EOF);
3082	if (parsebuf) {
3083		parseindex--;
3084		if (parseindex >= 0)
3085			return (c);
3086	}
3087	if (pushback_index < MAXPUSHBACK-1)
3088		return (pushback_buffer[pushback_index++] = c);
3089	else
3090		return (EOF);
3091}
3092
3093int
3094findeol(void)
3095{
3096	int c;
3097
3098	parsebuf = NULL;
3099	pushback_index = 0;
3100
3101	/* skip to either EOF or the first real EOL */
3102	while (1) {
3103		c = lgetc(fin);
3104		if (c == '\n') {
3105			lineno++;
3106			break;
3107		}
3108		if (c == EOF)
3109			break;
3110	}
3111	return (ERROR);
3112}
3113
3114int
3115yylex(void)
3116{
3117	char buf[8096], *p, *val;
3118	int endc, c, next;
3119	int token;
3120
3121top:
3122	p = buf;
3123	while ((c = lgetc(fin)) == ' ')
3124		;
3125
3126	yylval.lineno = lineno;
3127	if (c == '#')
3128		while ((c = lgetc(fin)) != '\n' && c != EOF)
3129			;
3130	if (c == '$' && parsebuf == NULL) {
3131		while (1) {
3132			if ((c = lgetc(fin)) == EOF)
3133				return (0);
3134
3135			if (p + 1 >= buf + sizeof(buf) - 1) {
3136				yyerror("string too long");
3137				return (findeol());
3138			}
3139			if (isalnum(c) || c == '_') {
3140				*p++ = (char)c;
3141				continue;
3142			}
3143			*p = '\0';
3144			lungetc(c, fin);
3145			break;
3146		}
3147		val = symget(buf);
3148		if (val == NULL) {
3149			yyerror("macro '%s' not defined", buf);
3150			return (findeol());
3151		}
3152		parsebuf = val;
3153		parseindex = 0;
3154		goto top;
3155	}
3156
3157	switch (c) {
3158	case '\'':
3159	case '"':
3160		endc = c;
3161		while (1) {
3162			if ((c = lgetc(fin)) == EOF)
3163				return (0);
3164			if (c == endc) {
3165				*p = '\0';
3166				break;
3167			}
3168			if (c == '\n') {
3169				lineno++;
3170				continue;
3171			}
3172			if (p + 1 >= buf + sizeof(buf) - 1) {
3173				yyerror("string too long");
3174				return (findeol());
3175			}
3176			*p++ = (char)c;
3177		}
3178		yylval.v.string = strdup(buf);
3179		if (yylval.v.string == NULL)
3180			err(1, "yylex: strdup");
3181		return (STRING);
3182	case '=':
3183		yylval.v.i = PF_OP_EQ;
3184		return (PORTUNARY);
3185	case '!':
3186		next = lgetc(fin);
3187		if (next == '=') {
3188			yylval.v.i = PF_OP_NE;
3189			return (PORTUNARY);
3190		}
3191		lungetc(next, fin);
3192		break;
3193	case '<':
3194		next = lgetc(fin);
3195		if (next == '>') {
3196			yylval.v.i = PF_OP_XRG;
3197			return (PORTBINARY);
3198		} else  if (next == '=') {
3199			yylval.v.i = PF_OP_LE;
3200		} else {
3201			yylval.v.i = PF_OP_LT;
3202			lungetc(next, fin);
3203		}
3204		return (PORTUNARY);
3205		break;
3206	case '>':
3207		next = lgetc(fin);
3208		if (next == '<') {
3209			yylval.v.i = PF_OP_IRG;
3210			return (PORTBINARY);
3211		} else  if (next == '=') {
3212			yylval.v.i = PF_OP_GE;
3213		} else {
3214			yylval.v.i = PF_OP_GT;
3215			lungetc(next, fin);
3216		}
3217		return (PORTUNARY);
3218		break;
3219	case '-':
3220		next = lgetc(fin);
3221		if (next == '>')
3222			return (ARROW);
3223		lungetc(next, fin);
3224		break;
3225	}
3226
3227#define allowed_in_string(x) \
3228	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
3229	x != '{' && x != '}' && x != '<' && x != '>' && \
3230	x != '!' && x != '=' && x != '/' && x != '#' && \
3231	x != ','))
3232
3233	if (isalnum(c) || c == ':') {
3234		do {
3235			*p++ = c;
3236			if ((unsigned)(p-buf) >= sizeof(buf)) {
3237				yyerror("string too long");
3238				return (findeol());
3239			}
3240		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
3241		lungetc(c, fin);
3242		*p = '\0';
3243		token = lookup(buf);
3244		yylval.v.string = strdup(buf);
3245		if (yylval.v.string == NULL)
3246			err(1, "yylex: strdup");
3247		return (token);
3248	}
3249	if (c == '\n') {
3250		yylval.lineno = lineno;
3251		lineno++;
3252	}
3253	if (c == EOF)
3254		return (0);
3255	return (c);
3256}
3257
3258int
3259parse_rules(FILE *input, struct pfctl *xpf)
3260{
3261	struct sym *sym;
3262
3263	fin = input;
3264	pf = xpf;
3265	lineno = 1;
3266	errors = 0;
3267	rulestate = PFCTL_STATE_NONE;
3268	yyparse();
3269
3270	/* Check which macros have not been used. */
3271	for (sym = symhead; sym; sym = sym->next)
3272		if (!sym->used)
3273			fprintf(stderr, "warning: macro '%s' not used\n",
3274			    sym->nam);
3275
3276	return (errors ? -1 : 0);
3277}
3278
3279void
3280set_ipmask(struct node_host *h, u_int8_t b)
3281{
3282	struct pf_addr *m, *n;
3283	int i, j = 0;
3284
3285	m = &h->addr.mask;
3286
3287	for (i = 0; i < 4; i++)
3288		m->addr32[i] = 0;
3289
3290	while (b >= 32) {
3291		m->addr32[j++] = 0xffffffff;
3292		b -= 32;
3293	}
3294	for (i = 31; i > 31-b; --i)
3295		m->addr32[j] |= (1 << i);
3296	if (b)
3297		m->addr32[j] = htonl(m->addr32[j]);
3298
3299	/* Mask off bits of the address that will never be used. */
3300	n = &h->addr.addr;
3301	for (i = 0; i < 4; i++)
3302		n->addr32[i] = n->addr32[i] & m->addr32[i];
3303}
3304
3305/*
3306 * Over-designed efficiency is a French and German concept, so how about
3307 * we wait until they discover this ugliness and make it all fancy.
3308 */
3309int
3310symset(const char *nam, const char *val)
3311{
3312	struct sym *sym;
3313
3314	sym = calloc(1, sizeof(*sym));
3315	if (sym == NULL)
3316		return (-1);
3317	sym->nam = strdup(nam);
3318	if (sym->nam == NULL) {
3319		free(sym);
3320		return (-1);
3321	}
3322	sym->val = strdup(val);
3323	if (sym->val == NULL) {
3324		free(sym->nam);
3325		free(sym);
3326		return (-1);
3327	}
3328	sym->next = symhead;
3329	sym->used = 0;
3330	symhead = sym;
3331	return (0);
3332}
3333
3334char *
3335symget(const char *nam)
3336{
3337	struct sym *sym;
3338
3339	for (sym = symhead; sym; sym = sym->next)
3340		if (strcmp(nam, sym->nam) == 0) {
3341			sym->used = 1;
3342			return (sym->val);
3343		}
3344	return (NULL);
3345}
3346
3347/* interface lookup routines */
3348
3349struct node_host *iftab;
3350
3351void
3352ifa_load(void)
3353{
3354	struct ifaddrs *ifap, *ifa;
3355	struct node_host *n = NULL, *h = NULL;
3356
3357	if (getifaddrs(&ifap) < 0)
3358		err(1, "getifaddrs");
3359
3360	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
3361		if (!(ifa->ifa_addr->sa_family == AF_INET ||
3362		    ifa->ifa_addr->sa_family == AF_INET6 ||
3363		    ifa->ifa_addr->sa_family == AF_LINK))
3364				continue;
3365		n = calloc(1, sizeof(struct node_host));
3366		if (n == NULL)
3367			err(1, "address: calloc");
3368		n->af = ifa->ifa_addr->sa_family;
3369		n->addr.addr_dyn = NULL;
3370		n->ifa_flags = ifa->ifa_flags;
3371#ifdef __KAME__
3372		if (n->af == AF_INET6 &&
3373		    IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr) &&
3374		    ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
3375			struct sockaddr_in6 *sin6;
3376
3377			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
3378			sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
3379			    sin6->sin6_addr.s6_addr[3];
3380			sin6->sin6_addr.s6_addr[2] = 0;
3381			sin6->sin6_addr.s6_addr[3] = 0;
3382		}
3383#endif
3384		n->ifindex = 0;
3385		if (n->af == AF_INET) {
3386			memcpy(&n->addr.addr, &((struct sockaddr_in *)
3387			    ifa->ifa_addr)->sin_addr.s_addr,
3388			    sizeof(struct in_addr));
3389			memcpy(&n->addr.mask, &((struct sockaddr_in *)
3390			    ifa->ifa_netmask)->sin_addr.s_addr,
3391			    sizeof(struct in_addr));
3392			if (ifa->ifa_broadaddr != NULL)
3393				memcpy(&n->bcast, &((struct sockaddr_in *)
3394				    ifa->ifa_broadaddr)->sin_addr.s_addr,
3395				    sizeof(struct in_addr));
3396		} else if (n->af == AF_INET6) {
3397			memcpy(&n->addr.addr, &((struct sockaddr_in6 *)
3398			    ifa->ifa_addr)->sin6_addr.s6_addr,
3399			    sizeof(struct in6_addr));
3400			memcpy(&n->addr.mask, &((struct sockaddr_in6 *)
3401			    ifa->ifa_netmask)->sin6_addr.s6_addr,
3402			    sizeof(struct in6_addr));
3403			if (ifa->ifa_broadaddr != NULL)
3404				memcpy(&n->bcast, &((struct sockaddr_in6 *)
3405				    ifa->ifa_broadaddr)->sin6_addr.s6_addr,
3406				    sizeof(struct in6_addr));
3407			n->ifindex = ((struct sockaddr_in6 *)
3408			    ifa->ifa_addr)->sin6_scope_id;
3409		}
3410		if ((n->ifname = strdup(ifa->ifa_name)) == NULL) {
3411			yyerror("strdup failed");
3412			exit(1);
3413		}
3414		n->next = NULL;
3415		n->tail = n;
3416		if (h == NULL)
3417			h = n;
3418		else {
3419			h->tail->next = n;
3420			h->tail = n;
3421		}
3422	}
3423	iftab = h;
3424	freeifaddrs(ifap);
3425}
3426
3427struct node_host *
3428ifa_exists(char *ifa_name)
3429{
3430	struct node_host *n;
3431
3432	if (iftab == NULL)
3433		ifa_load();
3434
3435	for (n = iftab; n; n = n->next) {
3436		if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
3437			return (n);
3438	}
3439	return (NULL);
3440}
3441
3442struct node_host *
3443ifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode)
3444{
3445	struct node_host *p = NULL, *h = NULL, *n = NULL;
3446	int return_all = 0;
3447
3448	if (!strncmp(ifa_name, "self", IFNAMSIZ))
3449		return_all = 1;
3450
3451	if (iftab == NULL)
3452		ifa_load();
3453
3454	for (p = iftab; p; p = p->next) {
3455		if (!((p->af == AF_INET || p->af == AF_INET6) &&
3456		    (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
3457			continue;
3458		if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
3459			continue;
3460		if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
3461			continue;
3462		n = calloc(1, sizeof(struct node_host));
3463		if (n == NULL)
3464			err(1, "address: calloc");
3465		n->af = p->af;
3466		n->addr.addr_dyn = NULL;
3467		if (mode == PFCTL_IFLOOKUP_BCAST) {
3468				memcpy(&n->addr.addr, &p->bcast,
3469				    sizeof(struct pf_addr));
3470		} else
3471			memcpy(&n->addr.addr, &p->addr.addr,
3472			    sizeof(struct pf_addr));
3473		if (mode == PFCTL_IFLOOKUP_NET)
3474			memcpy(&n->addr.mask, &p->addr.mask,
3475			    sizeof(struct pf_addr));
3476		else {
3477			if (n->af == AF_INET) {
3478				if (p->ifa_flags & IFF_LOOPBACK &&
3479				    p->ifa_flags & IFF_LINK1)
3480					memcpy(&n->addr.mask, &p->addr.mask,
3481					    sizeof(struct pf_addr));
3482				else
3483					set_ipmask(n, 32);
3484			} else
3485				set_ipmask(n, 128);
3486		}
3487		n->ifindex = p->ifindex;
3488
3489		n->next = NULL;
3490		n->tail = n;
3491		if (h == NULL)
3492			h = n;
3493		else {
3494			h->tail->next = n;
3495			h->tail = n;
3496		}
3497	}
3498	if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
3499		yyerror("no IP address found for %s", ifa_name);
3500	}
3501	return (h);
3502}
3503
3504void
3505decide_address_family(struct node_host *n, sa_family_t *af)
3506{
3507	sa_family_t target_af = 0;
3508
3509	while (!*af && n != NULL) {
3510		if (n->af) {
3511			if (target_af == 0)
3512				target_af = n->af;
3513			if (target_af != n->af)
3514				return;
3515		}
3516		n = n->next;
3517	}
3518	if (!*af && target_af)
3519		*af = target_af;
3520}
3521
3522void
3523remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
3524{
3525	struct node_host *n = *nh, *prev = NULL;
3526
3527	while (n != NULL) {
3528		if (*af && n->af && n->af != *af) {
3529			/* unlink and free n */
3530			struct node_host *next = n->next;
3531
3532			/* adjust tail pointer */
3533			if (n == (*nh)->tail)
3534				(*nh)->tail = prev;
3535			/* adjust previous node's next pointer */
3536			if (prev == NULL)
3537				*nh = next;
3538			else
3539				prev->next = next;
3540			/* free node */
3541			if (n->ifname != NULL)
3542				free(n->ifname);
3543			free(n);
3544			n = next;
3545		} else {
3546			if (n->af && !*af)
3547				*af = n->af;
3548			prev = n;
3549			n = n->next;
3550		}
3551	}
3552
3553	if (!*af)
3554		yyerror("address family not given and translation "
3555		    "address expands to multiple address families");
3556	else if (*nh == NULL)
3557		yyerror("no translation address with matching address family "
3558		    "found.");
3559}
3560
3561struct node_host *
3562host(char *s, int mask)
3563{
3564	struct node_host *h = NULL, *n;
3565	struct in_addr ina;
3566	struct addrinfo hints, *res0, *res;
3567	int bits, error, v4mask, v6mask;
3568	char *buf = NULL;
3569
3570	if (ifa_exists(s) || !strncmp(s, "self", IFNAMSIZ)) {
3571		/* interface with this name exists */
3572		h = ifa_lookup(s, PFCTL_IFLOOKUP_HOST);
3573		if (h != NULL && mask > -1)
3574			set_ipmask(h, mask);
3575		return (h);
3576	}
3577
3578	if (mask == -1) {
3579		if (asprintf(&buf, "%s", s) == -1)
3580			err(1, "host: asprintf");
3581		v4mask = 32;
3582		v6mask = 128;
3583	} else if (mask <= 128) {
3584		if (asprintf(&buf, "%s/%d", s, mask) == -1)
3585			err(1, "host: asprintf");
3586		v4mask = v6mask = mask;
3587	} else {
3588		yyerror("illegal mask");
3589		return (NULL);
3590	}
3591
3592	memset(&ina, 0, sizeof(struct in_addr));
3593	if ((bits = inet_net_pton(AF_INET, buf, &ina, sizeof(&ina))) > -1) {
3594		h = calloc(1, sizeof(struct node_host));
3595		if (h == NULL)
3596			err(1, "address: calloc");
3597		h->ifname = NULL;
3598		h->af = AF_INET;
3599		h->addr.addr_dyn = NULL;
3600		h->addr.addr.addr32[0] = ina.s_addr;
3601		set_ipmask(h, bits);
3602		h->next = NULL;
3603		h->tail = h;
3604		free(buf);
3605		return (h);
3606	}
3607	free(buf);
3608
3609	memset(&hints, 0, sizeof(hints));
3610	hints.ai_family = AF_INET6;
3611	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
3612	hints.ai_flags = AI_NUMERICHOST;
3613	if (getaddrinfo(s, "0", &hints, &res) == 0) {
3614		n = calloc(1, sizeof(struct node_host));
3615		if (n == NULL)
3616			err(1, "address: calloc");
3617		n->ifname = NULL;
3618		n->af = AF_INET6;
3619		n->addr.addr_dyn = NULL;
3620		memcpy(&n->addr.addr,
3621		    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
3622		    sizeof(n->addr.addr));
3623		n->ifindex = ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
3624		set_ipmask(n, v6mask);
3625		freeaddrinfo(res);
3626		n->next = NULL;
3627		n->tail = n;
3628		return (n);
3629	}
3630
3631	memset(&hints, 0, sizeof(hints));
3632	hints.ai_family = PF_UNSPEC;
3633	hints.ai_socktype = SOCK_STREAM; /* DUMMY */
3634	error = getaddrinfo(s, NULL, &hints, &res0);
3635	if (error) {
3636		yyerror("cannot resolve %s: %s",
3637		    s, gai_strerror(error));
3638		return (NULL);
3639	}
3640	for (res = res0; res; res = res->ai_next) {
3641		if (res->ai_family != AF_INET &&
3642		    res->ai_family != AF_INET6)
3643			continue;
3644		n = calloc(1, sizeof(struct node_host));
3645		if (n == NULL)
3646			err(1, "address: calloc");
3647		n->ifname = NULL;
3648		n->af = res->ai_family;
3649		n->addr.addr_dyn = NULL;
3650		if (res->ai_family == AF_INET) {
3651			memcpy(&n->addr.addr,
3652			    &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
3653			    sizeof(struct in_addr));
3654			set_ipmask(n, v4mask);
3655		} else {
3656			memcpy(&n->addr.addr,
3657			    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr,
3658			    sizeof(struct in6_addr));
3659			n->ifindex =
3660			    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
3661			set_ipmask(n, v6mask);
3662		}
3663		n->next = NULL;
3664		n->tail = n;
3665		if (h == NULL)
3666			h = n;
3667		else {
3668			h->tail->next = n;
3669			h->tail = n;
3670		}
3671	}
3672	freeaddrinfo(res0);
3673	if (h == NULL) {
3674		yyerror("no IP address found for %s", s);
3675		return (NULL);
3676	}
3677	return (h);
3678}
3679
3680int
3681atoul(char *s, u_long *ulvalp)
3682{
3683	u_long ulval;
3684	char *ep;
3685
3686	errno = 0;
3687	ulval = strtoul(s, &ep, 0);
3688	if (s[0] == '\0' || *ep != '\0')
3689		return (-1);
3690	if (errno == ERANGE && ulval == ULONG_MAX)
3691		return (-1);
3692	*ulvalp = ulval;
3693	return (0);
3694}
3695
3696int
3697getservice(char *n)
3698{
3699	struct servent *s;
3700	u_long ulval;
3701
3702	if (atoul(n, &ulval) == 0) {
3703		if (ulval > 65535) {
3704			yyerror("illegal port value %d", ulval);
3705			return (-1);
3706		}
3707		return (htons(ulval));
3708	} else {
3709		s = getservbyname(n, "tcp");
3710		if (s == NULL)
3711			s = getservbyname(n, "udp");
3712		if (s == NULL) {
3713			yyerror("unknown port %s", n);
3714			return (-1);
3715		}
3716		return (s->s_port);
3717	}
3718}
3719
3720u_int16_t
3721parseicmpspec(char *w, sa_family_t af)
3722{
3723	const struct icmpcodeent *p;
3724	u_long ulval;
3725	u_int8_t icmptype;
3726
3727	if (af == AF_INET)
3728		icmptype = returnicmpdefault >> 8;
3729	else
3730		icmptype = returnicmp6default >> 8;
3731
3732	if (atoul(w, &ulval) == -1) {
3733		if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
3734			yyerror("unknown icmp code %s", w);
3735			return (0);
3736		}
3737		ulval = p->code;
3738	}
3739	return (icmptype << 8 | ulval);
3740}
3741