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