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