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