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