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