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