1223637Sbz/*	$OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $	*/
2126353Smlaier
3126353Smlaier/*
4126353Smlaier * Copyright (c) 2001 Markus Friedl.  All rights reserved.
5126353Smlaier * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
6130617Smlaier * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
7130617Smlaier * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
8126353Smlaier *
9126353Smlaier * Redistribution and use in source and binary forms, with or without
10126353Smlaier * modification, are permitted provided that the following conditions
11126353Smlaier * are met:
12126353Smlaier * 1. Redistributions of source code must retain the above copyright
13126353Smlaier *    notice, this list of conditions and the following disclaimer.
14126353Smlaier * 2. Redistributions in binary form must reproduce the above copyright
15126353Smlaier *    notice, this list of conditions and the following disclaimer in the
16126353Smlaier *    documentation and/or other materials provided with the distribution.
17126353Smlaier *
18126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19126353Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20126353Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21126353Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22126353Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23126353Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24126353Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25126353Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26126353Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27126353Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28126353Smlaier */
29126353Smlaier%{
30127082Sobrien#include <sys/cdefs.h>
31127082Sobrien__FBSDID("$FreeBSD: stable/10/sbin/pfctl/parse.y 326414 2017-11-30 21:32:28Z kp $");
32127082Sobrien
33126353Smlaier#include <sys/types.h>
34126353Smlaier#include <sys/socket.h>
35223637Sbz#include <sys/stat.h>
36231852Sbz#ifdef __FreeBSD__
37231852Sbz#include <sys/sysctl.h>
38231852Sbz#endif
39126353Smlaier#include <net/if.h>
40126353Smlaier#include <netinet/in.h>
41126353Smlaier#include <netinet/in_systm.h>
42126353Smlaier#include <netinet/ip.h>
43126353Smlaier#include <netinet/ip_icmp.h>
44126353Smlaier#include <netinet/icmp6.h>
45126353Smlaier#include <net/pfvar.h>
46126353Smlaier#include <arpa/inet.h>
47126353Smlaier#include <altq/altq.h>
48126353Smlaier#include <altq/altq_cbq.h>
49298133Sloos#include <altq/altq_codel.h>
50126353Smlaier#include <altq/altq_priq.h>
51126353Smlaier#include <altq/altq_hfsc.h>
52298115Sloos#include <altq/altq_fairq.h>
53126353Smlaier
54126353Smlaier#include <stdio.h>
55223637Sbz#include <unistd.h>
56126353Smlaier#include <stdlib.h>
57126353Smlaier#include <netdb.h>
58126353Smlaier#include <stdarg.h>
59126353Smlaier#include <errno.h>
60126353Smlaier#include <string.h>
61126353Smlaier#include <ctype.h>
62145840Smlaier#include <math.h>
63126353Smlaier#include <err.h>
64127024Smlaier#include <limits.h>
65126353Smlaier#include <pwd.h>
66126353Smlaier#include <grp.h>
67126353Smlaier#include <md5.h>
68126353Smlaier
69126353Smlaier#include "pfctl_parser.h"
70126353Smlaier#include "pfctl.h"
71126353Smlaier
72126353Smlaierstatic struct pfctl	*pf = NULL;
73126353Smlaierstatic int		 debug = 0;
74126353Smlaierstatic int		 rulestate = 0;
75126353Smlaierstatic u_int16_t	 returnicmpdefault =
76126353Smlaier			    (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
77126353Smlaierstatic u_int16_t	 returnicmp6default =
78126353Smlaier			    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
79126353Smlaierstatic int		 blockpolicy = PFRULE_DROP;
80126353Smlaierstatic int		 require_order = 1;
81130617Smlaierstatic int		 default_statelock;
82126353Smlaier
83223637SbzTAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
84223637Sbzstatic struct file {
85223637Sbz	TAILQ_ENTRY(file)	 entry;
86223637Sbz	FILE			*stream;
87223637Sbz	char			*name;
88223637Sbz	int			 lineno;
89223637Sbz	int			 errors;
90223637Sbz} *file;
91223637Sbzstruct file	*pushfile(const char *, int);
92223637Sbzint		 popfile(void);
93223637Sbzint		 check_file_secrecy(int, const char *);
94223637Sbzint		 yyparse(void);
95223637Sbzint		 yylex(void);
96223637Sbzint		 yyerror(const char *, ...);
97223637Sbzint		 kw_cmp(const void *, const void *);
98223637Sbzint		 lookup(char *);
99223637Sbzint		 lgetc(int);
100223637Sbzint		 lungetc(int);
101223637Sbzint		 findeol(void);
102223637Sbz
103223637SbzTAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
104223637Sbzstruct sym {
105223637Sbz	TAILQ_ENTRY(sym)	 entry;
106223637Sbz	int			 used;
107223637Sbz	int			 persist;
108223637Sbz	char			*nam;
109223637Sbz	char			*val;
110223637Sbz};
111223637Sbzint		 symset(const char *, const char *, int);
112223637Sbzchar		*symget(const char *);
113223637Sbz
114223637Sbzint		 atoul(char *, u_long *);
115223637Sbz
116126353Smlaierenum {
117126353Smlaier	PFCTL_STATE_NONE,
118126353Smlaier	PFCTL_STATE_OPTION,
119126353Smlaier	PFCTL_STATE_SCRUB,
120126353Smlaier	PFCTL_STATE_QUEUE,
121126353Smlaier	PFCTL_STATE_NAT,
122126353Smlaier	PFCTL_STATE_FILTER
123126353Smlaier};
124126353Smlaier
125126353Smlaierstruct node_proto {
126126353Smlaier	u_int8_t		 proto;
127126353Smlaier	struct node_proto	*next;
128126353Smlaier	struct node_proto	*tail;
129126353Smlaier};
130126353Smlaier
131126353Smlaierstruct node_port {
132126353Smlaier	u_int16_t		 port[2];
133126353Smlaier	u_int8_t		 op;
134126353Smlaier	struct node_port	*next;
135126353Smlaier	struct node_port	*tail;
136126353Smlaier};
137126353Smlaier
138126353Smlaierstruct node_uid {
139126353Smlaier	uid_t			 uid[2];
140126353Smlaier	u_int8_t		 op;
141126353Smlaier	struct node_uid		*next;
142126353Smlaier	struct node_uid		*tail;
143126353Smlaier};
144126353Smlaier
145126353Smlaierstruct node_gid {
146126353Smlaier	gid_t			 gid[2];
147126353Smlaier	u_int8_t		 op;
148126353Smlaier	struct node_gid		*next;
149126353Smlaier	struct node_gid		*tail;
150126353Smlaier};
151126353Smlaier
152126353Smlaierstruct node_icmp {
153126353Smlaier	u_int8_t		 code;
154126353Smlaier	u_int8_t		 type;
155126353Smlaier	u_int8_t		 proto;
156126353Smlaier	struct node_icmp	*next;
157126353Smlaier	struct node_icmp	*tail;
158126353Smlaier};
159126353Smlaier
160130617Smlaierenum	{ PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
161145840Smlaier	    PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
162145840Smlaier	    PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
163145840Smlaier	    PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
164240233Sglebius	    PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
165130617Smlaier
166130617Smlaierenum	{ PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
167130617Smlaier
168126353Smlaierstruct node_state_opt {
169126353Smlaier	int			 type;
170126353Smlaier	union {
171126353Smlaier		u_int32_t	 max_states;
172130617Smlaier		u_int32_t	 max_src_states;
173145840Smlaier		u_int32_t	 max_src_conn;
174145840Smlaier		struct {
175145840Smlaier			u_int32_t	limit;
176145840Smlaier			u_int32_t	seconds;
177145840Smlaier		}		 max_src_conn_rate;
178145840Smlaier		struct {
179145840Smlaier			u_int8_t	flush;
180145840Smlaier			char		tblname[PF_TABLE_NAME_SIZE];
181145840Smlaier		}		 overload;
182130617Smlaier		u_int32_t	 max_src_nodes;
183130617Smlaier		u_int8_t	 src_track;
184130617Smlaier		u_int32_t	 statelock;
185126353Smlaier		struct {
186126353Smlaier			int		number;
187126353Smlaier			u_int32_t	seconds;
188126353Smlaier		}		 timeout;
189126353Smlaier	}			 data;
190126353Smlaier	struct node_state_opt	*next;
191126353Smlaier	struct node_state_opt	*tail;
192126353Smlaier};
193126353Smlaier
194126353Smlaierstruct peer {
195126353Smlaier	struct node_host	*host;
196126353Smlaier	struct node_port	*port;
197126353Smlaier};
198126353Smlaier
199126353Smlaierstruct node_queue {
200126353Smlaier	char			 queue[PF_QNAME_SIZE];
201126353Smlaier	char			 parent[PF_QNAME_SIZE];
202126353Smlaier	char			 ifname[IFNAMSIZ];
203126353Smlaier	int			 scheduler;
204126353Smlaier	struct node_queue	*next;
205126353Smlaier	struct node_queue	*tail;
206126353Smlaier}	*queues = NULL;
207126353Smlaier
208126353Smlaierstruct node_qassign {
209126353Smlaier	char		*qname;
210126353Smlaier	char		*pqname;
211126353Smlaier};
212126353Smlaier
213126353Smlaierstruct filter_opts {
214126353Smlaier	int			 marker;
215126353Smlaier#define FOM_FLAGS	0x01
216126353Smlaier#define FOM_ICMP	0x02
217126353Smlaier#define FOM_TOS		0x04
218126353Smlaier#define FOM_KEEP	0x08
219130617Smlaier#define FOM_SRCTRACK	0x10
220126353Smlaier	struct node_uid		*uid;
221126353Smlaier	struct node_gid		*gid;
222126353Smlaier	struct {
223126353Smlaier		u_int8_t	 b1;
224126353Smlaier		u_int8_t	 b2;
225126353Smlaier		u_int16_t	 w;
226126353Smlaier		u_int16_t	 w2;
227126353Smlaier	} flags;
228126353Smlaier	struct node_icmp	*icmpspec;
229126353Smlaier	u_int32_t		 tos;
230145840Smlaier	u_int32_t		 prob;
231126353Smlaier	struct {
232126353Smlaier		int			 action;
233126353Smlaier		struct node_state_opt	*options;
234126353Smlaier	} keep;
235126353Smlaier	int			 fragment;
236126353Smlaier	int			 allowopts;
237126353Smlaier	char			*label;
238126353Smlaier	struct node_qassign	 queues;
239126353Smlaier	char			*tag;
240126353Smlaier	char			*match_tag;
241126353Smlaier	u_int8_t		 match_tag_not;
242223637Sbz	u_int			 rtableid;
243223637Sbz	struct {
244223637Sbz		struct node_host	*addr;
245223637Sbz		u_int16_t		port;
246223637Sbz	}			 divert;
247126353Smlaier} filter_opts;
248126353Smlaier
249126353Smlaierstruct antispoof_opts {
250126353Smlaier	char			*label;
251223637Sbz	u_int			 rtableid;
252126353Smlaier} antispoof_opts;
253126353Smlaier
254126353Smlaierstruct scrub_opts {
255223637Sbz	int			 marker;
256126353Smlaier#define SOM_MINTTL	0x01
257126353Smlaier#define SOM_MAXMSS	0x02
258126353Smlaier#define SOM_FRAGCACHE	0x04
259223637Sbz#define SOM_SETTOS	0x08
260223637Sbz	int			 nodf;
261223637Sbz	int			 minttl;
262223637Sbz	int			 maxmss;
263223637Sbz	int			 settos;
264223637Sbz	int			 fragcache;
265223637Sbz	int			 randomid;
266223637Sbz	int			 reassemble_tcp;
267223637Sbz	char			*match_tag;
268223637Sbz	u_int8_t		 match_tag_not;
269223637Sbz	u_int			 rtableid;
270126353Smlaier} scrub_opts;
271126353Smlaier
272126353Smlaierstruct queue_opts {
273126353Smlaier	int			marker;
274126353Smlaier#define QOM_BWSPEC	0x01
275126353Smlaier#define QOM_SCHEDULER	0x02
276126353Smlaier#define QOM_PRIORITY	0x04
277126353Smlaier#define QOM_TBRSIZE	0x08
278126353Smlaier#define QOM_QLIMIT	0x10
279126353Smlaier	struct node_queue_bw	queue_bwspec;
280126353Smlaier	struct node_queue_opt	scheduler;
281126353Smlaier	int			priority;
282126353Smlaier	int			tbrsize;
283126353Smlaier	int			qlimit;
284126353Smlaier} queue_opts;
285126353Smlaier
286126353Smlaierstruct table_opts {
287126353Smlaier	int			flags;
288126353Smlaier	int			init_addr;
289126353Smlaier	struct node_tinithead	init_nodes;
290126353Smlaier} table_opts;
291126353Smlaier
292130617Smlaierstruct pool_opts {
293130617Smlaier	int			 marker;
294130617Smlaier#define POM_TYPE		0x01
295130617Smlaier#define POM_STICKYADDRESS	0x02
296130617Smlaier	u_int8_t		 opts;
297130617Smlaier	int			 type;
298130617Smlaier	int			 staticport;
299130617Smlaier	struct pf_poolhashkey	*key;
300130617Smlaier
301130617Smlaier} pool_opts;
302130617Smlaier
303298133Sloosstruct codel_opts	 codel_opts;
304223637Sbzstruct node_hfsc_opts	 hfsc_opts;
305298091Sloosstruct node_fairq_opts	 fairq_opts;
306223637Sbzstruct node_state_opt	*keep_state_defaults = NULL;
307126353Smlaier
308223637Sbzint		 disallow_table(struct node_host *, const char *);
309223637Sbzint		 disallow_urpf_failed(struct node_host *, const char *);
310223637Sbzint		 disallow_alias(struct node_host *, const char *);
311223637Sbzint		 rule_consistent(struct pf_rule *, int);
312223637Sbzint		 filter_consistent(struct pf_rule *, int);
313223637Sbzint		 nat_consistent(struct pf_rule *);
314223637Sbzint		 rdr_consistent(struct pf_rule *);
315223637Sbzint		 process_tabledef(char *, struct table_opts *);
316223637Sbzvoid		 expand_label_str(char *, size_t, const char *, const char *);
317223637Sbzvoid		 expand_label_if(const char *, char *, size_t, const char *);
318223637Sbzvoid		 expand_label_addr(const char *, char *, size_t, u_int8_t,
319223637Sbz		    struct node_host *);
320223637Sbzvoid		 expand_label_port(const char *, char *, size_t,
321223637Sbz		    struct node_port *);
322223637Sbzvoid		 expand_label_proto(const char *, char *, size_t, u_int8_t);
323223637Sbzvoid		 expand_label_nr(const char *, char *, size_t);
324223637Sbzvoid		 expand_label(char *, size_t, const char *, u_int8_t,
325223637Sbz		    struct node_host *, struct node_port *, struct node_host *,
326223637Sbz		    struct node_port *, u_int8_t);
327223637Sbzvoid		 expand_rule(struct pf_rule *, struct node_if *,
328223637Sbz		    struct node_host *, struct node_proto *, struct node_os *,
329223637Sbz		    struct node_host *, struct node_port *, struct node_host *,
330223637Sbz		    struct node_port *, struct node_uid *, struct node_gid *,
331223637Sbz		    struct node_icmp *, const char *);
332223637Sbzint		 expand_altq(struct pf_altq *, struct node_if *,
333223637Sbz		    struct node_queue *, struct node_queue_bw bwspec,
334223637Sbz		    struct node_queue_opt *);
335223637Sbzint		 expand_queue(struct pf_altq *, struct node_if *,
336223637Sbz		    struct node_queue *, struct node_queue_bw,
337223637Sbz		    struct node_queue_opt *);
338223637Sbzint		 expand_skip_interface(struct node_if *);
339126353Smlaier
340126353Smlaierint	 check_rulestate(int);
341126353Smlaierint	 getservice(char *);
342126353Smlaierint	 rule_label(struct pf_rule *, char *);
343231852Sbzint	 rt_tableid_max(void);
344126353Smlaier
345171172Smlaiervoid	 mv_rules(struct pf_ruleset *, struct pf_ruleset *);
346126353Smlaiervoid	 decide_address_family(struct node_host *, sa_family_t *);
347126353Smlaiervoid	 remove_invalid_hosts(struct node_host **, sa_family_t *);
348126353Smlaierint	 invalid_redirect(struct node_host *, sa_family_t);
349126353Smlaieru_int16_t parseicmpspec(char *, sa_family_t);
350126353Smlaier
351130617SmlaierTAILQ_HEAD(loadanchorshead, loadanchors)
352130617Smlaier    loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
353130617Smlaier
354126353Smlaierstruct loadanchors {
355126353Smlaier	TAILQ_ENTRY(loadanchors)	 entries;
356126353Smlaier	char				*anchorname;
357126353Smlaier	char				*filename;
358126353Smlaier};
359126353Smlaier
360126353Smlaiertypedef struct {
361126353Smlaier	union {
362223637Sbz		int64_t			 number;
363223637Sbz		double			 probability;
364126353Smlaier		int			 i;
365126353Smlaier		char			*string;
366223637Sbz		u_int			 rtableid;
367126353Smlaier		struct {
368126353Smlaier			u_int8_t	 b1;
369126353Smlaier			u_int8_t	 b2;
370126353Smlaier			u_int16_t	 w;
371126353Smlaier			u_int16_t	 w2;
372126353Smlaier		}			 b;
373126353Smlaier		struct range {
374126353Smlaier			int		 a;
375126353Smlaier			int		 b;
376126353Smlaier			int		 t;
377126353Smlaier		}			 range;
378126353Smlaier		struct node_if		*interface;
379126353Smlaier		struct node_proto	*proto;
380126353Smlaier		struct node_icmp	*icmp;
381126353Smlaier		struct node_host	*host;
382126353Smlaier		struct node_os		*os;
383126353Smlaier		struct node_port	*port;
384126353Smlaier		struct node_uid		*uid;
385126353Smlaier		struct node_gid		*gid;
386126353Smlaier		struct node_state_opt	*state_opt;
387126353Smlaier		struct peer		 peer;
388126353Smlaier		struct {
389126353Smlaier			struct peer	 src, dst;
390126353Smlaier			struct node_os	*src_os;
391126353Smlaier		}			 fromto;
392126353Smlaier		struct {
393126353Smlaier			struct node_host	*host;
394126353Smlaier			u_int8_t		 rt;
395126353Smlaier			u_int8_t		 pool_opts;
396126353Smlaier			sa_family_t		 af;
397126353Smlaier			struct pf_poolhashkey	*key;
398126353Smlaier		}			 route;
399126353Smlaier		struct redirection {
400126353Smlaier			struct node_host	*host;
401126353Smlaier			struct range		 rport;
402126353Smlaier		}			*redirection;
403126353Smlaier		struct {
404126353Smlaier			int			 action;
405126353Smlaier			struct node_state_opt	*options;
406126353Smlaier		}			 keep_state;
407126353Smlaier		struct {
408126353Smlaier			u_int8_t	 log;
409171172Smlaier			u_int8_t	 logif;
410126353Smlaier			u_int8_t	 quick;
411126353Smlaier		}			 logquick;
412145840Smlaier		struct {
413145840Smlaier			int		 neg;
414145840Smlaier			char		*name;
415145840Smlaier		}			 tagged;
416130617Smlaier		struct pf_poolhashkey	*hashkey;
417126353Smlaier		struct node_queue	*queue;
418126353Smlaier		struct node_queue_opt	 queue_options;
419126353Smlaier		struct node_queue_bw	 queue_bwspec;
420126353Smlaier		struct node_qassign	 qassign;
421126353Smlaier		struct filter_opts	 filter_opts;
422126353Smlaier		struct antispoof_opts	 antispoof_opts;
423126353Smlaier		struct queue_opts	 queue_opts;
424126353Smlaier		struct scrub_opts	 scrub_opts;
425126353Smlaier		struct table_opts	 table_opts;
426130617Smlaier		struct pool_opts	 pool_opts;
427126353Smlaier		struct node_hfsc_opts	 hfsc_opts;
428298091Sloos		struct node_fairq_opts	 fairq_opts;
429298133Sloos		struct codel_opts	 codel_opts;
430126353Smlaier	} v;
431126353Smlaier	int lineno;
432126353Smlaier} YYSTYPE;
433126353Smlaier
434223637Sbz#define PPORT_RANGE	1
435223637Sbz#define PPORT_STAR	2
436223637Sbzint	parseport(char *, struct range *r, int);
437223637Sbz
438130617Smlaier#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
439130617Smlaier	(!((addr).iflags & PFI_AFLAG_NOALIAS) ||		 \
440130617Smlaier	!isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
441130617Smlaier
442126353Smlaier%}
443126353Smlaier
444171172Smlaier%token	PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
445126353Smlaier%token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
446126353Smlaier%token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
447126353Smlaier%token	MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
448171172Smlaier%token	NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
449126353Smlaier%token	REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
450126353Smlaier%token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
451145840Smlaier%token	REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
452223637Sbz%token	ANTISPOOF FOR INCLUDE
453145840Smlaier%token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
454298133Sloos%token	ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
455298133Sloos%token	UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
456171172Smlaier%token	LOAD RULESET_OPTIMIZATION
457130617Smlaier%token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
458240233Sglebius%token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
459223637Sbz%token	TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
460223637Sbz%token	DIVERTTO DIVERTREPLY
461126353Smlaier%token	<v.string>		STRING
462223637Sbz%token	<v.number>		NUMBER
463126353Smlaier%token	<v.i>			PORTBINARY
464126353Smlaier%type	<v.interface>		interface if_list if_item_not if_item
465126353Smlaier%type	<v.number>		number icmptype icmp6type uid gid
466171172Smlaier%type	<v.number>		tos not yesno
467223637Sbz%type	<v.probability>		probability
468171172Smlaier%type	<v.i>			no dir af fragcache optimizer
469171172Smlaier%type	<v.i>			sourcetrack flush unaryop statelock
470223637Sbz%type	<v.b>			action nataction natpasslog scrubaction
471145840Smlaier%type	<v.b>			flags flag blockspec
472223637Sbz%type	<v.range>		portplain portstar portrange
473126353Smlaier%type	<v.hashkey>		hashkey
474126353Smlaier%type	<v.proto>		proto proto_list proto_item
475223637Sbz%type	<v.number>		protoval
476126353Smlaier%type	<v.icmp>		icmpspec
477126353Smlaier%type	<v.icmp>		icmp_list icmp_item
478126353Smlaier%type	<v.icmp>		icmp6_list icmp6_item
479223637Sbz%type	<v.number>		reticmpspec reticmp6spec
480126353Smlaier%type	<v.fromto>		fromto
481126353Smlaier%type	<v.peer>		ipportspec from to
482223637Sbz%type	<v.host>		ipspec toipspec xhost host dynaddr host_list
483126353Smlaier%type	<v.host>		redir_host_list redirspec
484126353Smlaier%type	<v.host>		route_host route_host_list routespec
485126353Smlaier%type	<v.os>			os xos os_list
486126353Smlaier%type	<v.port>		portspec port_list port_item
487126353Smlaier%type	<v.uid>			uids uid_list uid_item
488126353Smlaier%type	<v.gid>			gids gid_list gid_item
489126353Smlaier%type	<v.route>		route
490126353Smlaier%type	<v.redirection>		redirection redirpool
491223637Sbz%type	<v.string>		label stringall tag anchorname
492223637Sbz%type	<v.string>		string varstring numberstring
493126353Smlaier%type	<v.keep_state>		keep
494126353Smlaier%type	<v.state_opt>		state_opt_spec state_opt_list state_opt_item
495171172Smlaier%type	<v.logquick>		logquick quick log logopts logopt
496145840Smlaier%type	<v.interface>		antispoof_ifspc antispoof_iflst antispoof_if
497126353Smlaier%type	<v.qassign>		qname
498126353Smlaier%type	<v.queue>		qassign qassign_list qassign_item
499126353Smlaier%type	<v.queue_options>	scheduler
500126353Smlaier%type	<v.number>		cbqflags_list cbqflags_item
501126353Smlaier%type	<v.number>		priqflags_list priqflags_item
502126353Smlaier%type	<v.hfsc_opts>		hfscopts_list hfscopts_item hfsc_opts
503298091Sloos%type	<v.fairq_opts>		fairqopts_list fairqopts_item fairq_opts
504298133Sloos%type	<v.codel_opts>		codelopts_list codelopts_item codel_opts
505126353Smlaier%type	<v.queue_bwspec>	bandwidth
506126353Smlaier%type	<v.filter_opts>		filter_opts filter_opt filter_opts_l
507126353Smlaier%type	<v.antispoof_opts>	antispoof_opts antispoof_opt antispoof_opts_l
508126353Smlaier%type	<v.queue_opts>		queue_opts queue_opt queue_opts_l
509126353Smlaier%type	<v.scrub_opts>		scrub_opts scrub_opt scrub_opts_l
510126353Smlaier%type	<v.table_opts>		table_opts table_opt table_opts_l
511130617Smlaier%type	<v.pool_opts>		pool_opts pool_opt pool_opts_l
512145840Smlaier%type	<v.tagged>		tagged
513171172Smlaier%type	<v.rtableid>		rtable
514126353Smlaier%%
515126353Smlaier
516126353Smlaierruleset		: /* empty */
517223637Sbz		| ruleset include '\n'
518126353Smlaier		| ruleset '\n'
519126353Smlaier		| ruleset option '\n'
520126353Smlaier		| ruleset scrubrule '\n'
521126353Smlaier		| ruleset natrule '\n'
522126353Smlaier		| ruleset binatrule '\n'
523126353Smlaier		| ruleset pfrule '\n'
524126353Smlaier		| ruleset anchorrule '\n'
525126353Smlaier		| ruleset loadrule '\n'
526126353Smlaier		| ruleset altqif '\n'
527126353Smlaier		| ruleset queuespec '\n'
528126353Smlaier		| ruleset varset '\n'
529126353Smlaier		| ruleset antispoof '\n'
530126353Smlaier		| ruleset tabledef '\n'
531171172Smlaier		| '{' fakeanchor '}' '\n';
532223637Sbz		| ruleset error '\n'		{ file->errors++; }
533126353Smlaier		;
534126353Smlaier
535223637Sbzinclude		: INCLUDE STRING		{
536223637Sbz			struct file	*nfile;
537223637Sbz
538223637Sbz			if ((nfile = pushfile($2, 0)) == NULL) {
539223637Sbz				yyerror("failed to include file %s", $2);
540223637Sbz				free($2);
541223637Sbz				YYERROR;
542223637Sbz			}
543223637Sbz			free($2);
544223637Sbz
545223637Sbz			file = nfile;
546223637Sbz			lungetc('\n');
547223637Sbz		}
548223637Sbz		;
549223637Sbz
550171172Smlaier/*
551171172Smlaier * apply to previouslys specified rule: must be careful to note
552171172Smlaier * what that is: pf or nat or binat or rdr
553171172Smlaier */
554171172Smlaierfakeanchor	: fakeanchor '\n'
555171172Smlaier		| fakeanchor anchorrule '\n'
556171172Smlaier		| fakeanchor binatrule '\n'
557171172Smlaier		| fakeanchor natrule '\n'
558171172Smlaier		| fakeanchor pfrule '\n'
559171172Smlaier		| fakeanchor error '\n'
560171172Smlaier		;
561171172Smlaier
562171172Smlaieroptimizer	: string	{
563171172Smlaier			if (!strcmp($1, "none"))
564171172Smlaier				$$ = 0;
565171172Smlaier			else if (!strcmp($1, "basic"))
566171172Smlaier				$$ = PF_OPTIMIZE_BASIC;
567171172Smlaier			else if (!strcmp($1, "profile"))
568171172Smlaier				$$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
569171172Smlaier			else {
570223637Sbz				yyerror("unknown ruleset-optimization %s", $1);
571171172Smlaier				YYERROR;
572171172Smlaier			}
573171172Smlaier		}
574171172Smlaier		;
575171172Smlaier
576126353Smlaieroption		: SET OPTIMIZATION STRING		{
577130617Smlaier			if (check_rulestate(PFCTL_STATE_OPTION)) {
578130617Smlaier				free($3);
579126353Smlaier				YYERROR;
580130617Smlaier			}
581126353Smlaier			if (pfctl_set_optimization(pf, $3) != 0) {
582126353Smlaier				yyerror("unknown optimization %s", $3);
583130617Smlaier				free($3);
584126353Smlaier				YYERROR;
585126353Smlaier			}
586171172Smlaier			free($3);
587126353Smlaier		}
588171172Smlaier		| SET RULESET_OPTIMIZATION optimizer {
589171172Smlaier			if (!(pf->opts & PF_OPT_OPTIMIZE)) {
590171172Smlaier				pf->opts |= PF_OPT_OPTIMIZE;
591171172Smlaier				pf->optimize = $3;
592171172Smlaier			}
593171172Smlaier		}
594126353Smlaier		| SET TIMEOUT timeout_spec
595223637Sbz		| SET TIMEOUT '{' optnl timeout_list '}'
596126353Smlaier		| SET LIMIT limit_spec
597223637Sbz		| SET LIMIT '{' optnl limit_list '}'
598223637Sbz		| SET LOGINTERFACE stringall		{
599130617Smlaier			if (check_rulestate(PFCTL_STATE_OPTION)) {
600130617Smlaier				free($3);
601126353Smlaier				YYERROR;
602130617Smlaier			}
603126353Smlaier			if (pfctl_set_logif(pf, $3) != 0) {
604126353Smlaier				yyerror("error setting loginterface %s", $3);
605130617Smlaier				free($3);
606126353Smlaier				YYERROR;
607126353Smlaier			}
608130617Smlaier			free($3);
609126353Smlaier		}
610130617Smlaier		| SET HOSTID number {
611223637Sbz			if ($3 == 0 || $3 > UINT_MAX) {
612130617Smlaier				yyerror("hostid must be non-zero");
613130617Smlaier				YYERROR;
614130617Smlaier			}
615130617Smlaier			if (pfctl_set_hostid(pf, $3) != 0) {
616145840Smlaier				yyerror("error setting hostid %08x", $3);
617130617Smlaier				YYERROR;
618130617Smlaier			}
619130617Smlaier		}
620126353Smlaier		| SET BLOCKPOLICY DROP	{
621126353Smlaier			if (pf->opts & PF_OPT_VERBOSE)
622126353Smlaier				printf("set block-policy drop\n");
623126353Smlaier			if (check_rulestate(PFCTL_STATE_OPTION))
624126353Smlaier				YYERROR;
625126353Smlaier			blockpolicy = PFRULE_DROP;
626126353Smlaier		}
627126353Smlaier		| SET BLOCKPOLICY RETURN {
628126353Smlaier			if (pf->opts & PF_OPT_VERBOSE)
629126353Smlaier				printf("set block-policy return\n");
630126353Smlaier			if (check_rulestate(PFCTL_STATE_OPTION))
631126353Smlaier				YYERROR;
632126353Smlaier			blockpolicy = PFRULE_RETURN;
633126353Smlaier		}
634126353Smlaier		| SET REQUIREORDER yesno {
635126353Smlaier			if (pf->opts & PF_OPT_VERBOSE)
636126353Smlaier				printf("set require-order %s\n",
637126353Smlaier				    $3 == 1 ? "yes" : "no");
638126353Smlaier			require_order = $3;
639126353Smlaier		}
640126353Smlaier		| SET FINGERPRINTS STRING {
641126353Smlaier			if (pf->opts & PF_OPT_VERBOSE)
642171172Smlaier				printf("set fingerprints \"%s\"\n", $3);
643130617Smlaier			if (check_rulestate(PFCTL_STATE_OPTION)) {
644130617Smlaier				free($3);
645126353Smlaier				YYERROR;
646130617Smlaier			}
647171172Smlaier			if (!pf->anchor->name[0]) {
648145840Smlaier				if (pfctl_file_fingerprints(pf->dev,
649145840Smlaier				    pf->opts, $3)) {
650145840Smlaier					yyerror("error loading "
651145840Smlaier					    "fingerprints %s", $3);
652145840Smlaier					free($3);
653145840Smlaier					YYERROR;
654145840Smlaier				}
655126353Smlaier			}
656130617Smlaier			free($3);
657126353Smlaier		}
658130617Smlaier		| SET STATEPOLICY statelock {
659130617Smlaier			if (pf->opts & PF_OPT_VERBOSE)
660130617Smlaier				switch ($3) {
661130617Smlaier				case 0:
662130617Smlaier					printf("set state-policy floating\n");
663130617Smlaier					break;
664130617Smlaier				case PFRULE_IFBOUND:
665130617Smlaier					printf("set state-policy if-bound\n");
666130617Smlaier					break;
667130617Smlaier				}
668130617Smlaier			default_statelock = $3;
669130617Smlaier		}
670130617Smlaier		| SET DEBUG STRING {
671130617Smlaier			if (check_rulestate(PFCTL_STATE_OPTION)) {
672130617Smlaier				free($3);
673130617Smlaier				YYERROR;
674130617Smlaier			}
675130617Smlaier			if (pfctl_set_debug(pf, $3) != 0) {
676130617Smlaier				yyerror("error setting debuglevel %s", $3);
677130617Smlaier				free($3);
678130617Smlaier				YYERROR;
679130617Smlaier			}
680130617Smlaier			free($3);
681130617Smlaier		}
682145840Smlaier		| SET SKIP interface {
683145840Smlaier			if (expand_skip_interface($3) != 0) {
684145840Smlaier				yyerror("error setting skip interface(s)");
685145840Smlaier				YYERROR;
686145840Smlaier			}
687145840Smlaier		}
688223637Sbz		| SET STATEDEFAULTS state_opt_list {
689223637Sbz			if (keep_state_defaults != NULL) {
690223637Sbz				yyerror("cannot redefine state-defaults");
691223637Sbz				YYERROR;
692223637Sbz			}
693223637Sbz			keep_state_defaults = $3;
694223637Sbz		}
695126353Smlaier		;
696126353Smlaier
697223637Sbzstringall	: STRING	{ $$ = $1; }
698223637Sbz		| ALL		{
699223637Sbz			if (($$ = strdup("all")) == NULL) {
700223637Sbz				err(1, "stringall: strdup");
701223637Sbz			}
702223637Sbz		}
703223637Sbz		;
704223637Sbz
705223637Sbzstring		: STRING string				{
706126353Smlaier			if (asprintf(&$$, "%s %s", $1, $2) == -1)
707126353Smlaier				err(1, "string: asprintf");
708126353Smlaier			free($1);
709126353Smlaier			free($2);
710126353Smlaier		}
711126353Smlaier		| STRING
712126353Smlaier		;
713126353Smlaier
714223637Sbzvarstring	: numberstring varstring 		{
715223637Sbz			if (asprintf(&$$, "%s %s", $1, $2) == -1)
716223637Sbz				err(1, "string: asprintf");
717223637Sbz			free($1);
718223637Sbz			free($2);
719223637Sbz		}
720223637Sbz		| numberstring
721223637Sbz		;
722223637Sbz
723223637Sbznumberstring	: NUMBER				{
724223637Sbz			char	*s;
725223637Sbz			if (asprintf(&s, "%lld", (long long)$1) == -1) {
726223637Sbz				yyerror("string: asprintf");
727223637Sbz				YYERROR;
728223637Sbz			}
729223637Sbz			$$ = s;
730223637Sbz		}
731223637Sbz		| STRING
732223637Sbz		;
733223637Sbz
734223637Sbzvarset		: STRING '=' varstring	{
735126353Smlaier			if (pf->opts & PF_OPT_VERBOSE)
736126353Smlaier				printf("%s = \"%s\"\n", $1, $3);
737126353Smlaier			if (symset($1, $3, 0) == -1)
738126353Smlaier				err(1, "cannot store variable %s", $1);
739130617Smlaier			free($1);
740130617Smlaier			free($3);
741126353Smlaier		}
742126353Smlaier		;
743126353Smlaier
744171172Smlaieranchorname	: STRING			{ $$ = $1; }
745171172Smlaier		| /* empty */			{ $$ = NULL; }
746171172Smlaier		;
747171172Smlaier
748223637Sbzpfa_anchorlist	: /* empty */
749223637Sbz		| pfa_anchorlist '\n'
750223637Sbz		| pfa_anchorlist pfrule '\n'
751223637Sbz		| pfa_anchorlist anchorrule '\n'
752171172Smlaier		;
753171172Smlaier
754171172Smlaierpfa_anchor	: '{'
755171172Smlaier		{
756171172Smlaier			char ta[PF_ANCHOR_NAME_SIZE];
757171172Smlaier			struct pf_ruleset *rs;
758171172Smlaier
759171172Smlaier			/* steping into a brace anchor */
760171172Smlaier			pf->asd++;
761171172Smlaier			pf->bn++;
762171172Smlaier			pf->brace = 1;
763171172Smlaier
764171172Smlaier			/* create a holding ruleset in the root */
765171172Smlaier			snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
766171172Smlaier			rs = pf_find_or_create_ruleset(ta);
767171172Smlaier			if (rs == NULL)
768171172Smlaier				err(1, "pfa_anchor: pf_find_or_create_ruleset");
769171172Smlaier			pf->astack[pf->asd] = rs->anchor;
770171172Smlaier			pf->anchor = rs->anchor;
771171172Smlaier		} '\n' pfa_anchorlist '}'
772171172Smlaier		{
773171172Smlaier			pf->alast = pf->anchor;
774171172Smlaier			pf->asd--;
775171172Smlaier			pf->anchor = pf->astack[pf->asd];
776171172Smlaier		}
777171172Smlaier		| /* empty */
778171172Smlaier		;
779171172Smlaier
780171172Smlaieranchorrule	: ANCHOR anchorname dir quick interface af proto fromto
781171172Smlaier		    filter_opts pfa_anchor
782171172Smlaier		{
783126353Smlaier			struct pf_rule	r;
784223637Sbz			struct node_proto	*proto;
785126353Smlaier
786130617Smlaier			if (check_rulestate(PFCTL_STATE_FILTER)) {
787171172Smlaier				if ($2)
788171172Smlaier					free($2);
789171172Smlaier				YYERROR;
790171172Smlaier			}
791171172Smlaier
792171172Smlaier			if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
793130617Smlaier				free($2);
794171172Smlaier				yyerror("anchor names beginning with '_' "
795171172Smlaier				    "are reserved for internal use");
796126353Smlaier				YYERROR;
797130617Smlaier			}
798126353Smlaier
799145840Smlaier			memset(&r, 0, sizeof(r));
800171172Smlaier			if (pf->astack[pf->asd + 1]) {
801171172Smlaier				/* move inline rules into relative location */
802171172Smlaier				pf_anchor_setup(&r,
803171172Smlaier				    &pf->astack[pf->asd]->ruleset,
804171172Smlaier				    $2 ? $2 : pf->alast->name);
805171172Smlaier
806171172Smlaier				if (r.anchor == NULL)
807171172Smlaier					err(1, "anchorrule: unable to "
808171172Smlaier					    "create ruleset");
809171172Smlaier
810171172Smlaier				if (pf->alast != r.anchor) {
811171172Smlaier					if (r.anchor->match) {
812171172Smlaier						yyerror("inline anchor '%s' "
813171172Smlaier						    "already exists",
814171172Smlaier						    r.anchor->name);
815171172Smlaier						YYERROR;
816171172Smlaier					}
817171172Smlaier					mv_rules(&pf->alast->ruleset,
818171172Smlaier					    &r.anchor->ruleset);
819171172Smlaier				}
820171172Smlaier				pf_remove_if_empty_ruleset(&pf->alast->ruleset);
821171172Smlaier				pf->alast = r.anchor;
822171172Smlaier			} else {
823171172Smlaier				if (!$2) {
824171172Smlaier					yyerror("anchors without explicit "
825171172Smlaier					    "rules must specify a name");
826171172Smlaier					YYERROR;
827171172Smlaier				}
828171172Smlaier			}
829126353Smlaier			r.direction = $3;
830171172Smlaier			r.quick = $4.quick;
831171172Smlaier			r.af = $6;
832171172Smlaier			r.prob = $9.prob;
833171172Smlaier			r.rtableid = $9.rtableid;
834126353Smlaier
835223637Sbz			if ($9.tag)
836223637Sbz				if (strlcpy(r.tagname, $9.tag,
837223637Sbz				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
838223637Sbz					yyerror("tag too long, max %u chars",
839223637Sbz					    PF_TAG_NAME_SIZE - 1);
840223637Sbz					YYERROR;
841223637Sbz				}
842171172Smlaier			if ($9.match_tag)
843171172Smlaier				if (strlcpy(r.match_tagname, $9.match_tag,
844130617Smlaier				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
845130617Smlaier					yyerror("tag too long, max %u chars",
846130617Smlaier					    PF_TAG_NAME_SIZE - 1);
847130617Smlaier					YYERROR;
848130617Smlaier				}
849171172Smlaier			r.match_tag_not = $9.match_tag_not;
850223637Sbz			if (rule_label(&r, $9.label))
851223637Sbz				YYERROR;
852223637Sbz			free($9.label);
853223637Sbz			r.flags = $9.flags.b1;
854223637Sbz			r.flagset = $9.flags.b2;
855223637Sbz			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
856223637Sbz				yyerror("flags always false");
857223637Sbz				YYERROR;
858223637Sbz			}
859223637Sbz			if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
860223637Sbz				for (proto = $7; proto != NULL &&
861223637Sbz				    proto->proto != IPPROTO_TCP;
862223637Sbz				    proto = proto->next)
863223637Sbz					;	/* nothing */
864223637Sbz				if (proto == NULL && $7 != NULL) {
865223637Sbz					if ($9.flags.b1 || $9.flags.b2)
866223637Sbz						yyerror(
867223637Sbz						    "flags only apply to tcp");
868223637Sbz					if ($8.src_os)
869223637Sbz						yyerror(
870223637Sbz						    "OS fingerprinting only "
871223637Sbz						    "applies to tcp");
872223637Sbz					YYERROR;
873223637Sbz				}
874223637Sbz			}
875130617Smlaier
876223637Sbz			r.tos = $9.tos;
877223637Sbz
878223637Sbz			if ($9.keep.action) {
879223637Sbz				yyerror("cannot specify state handling "
880223637Sbz				    "on anchors");
881223637Sbz				YYERROR;
882223637Sbz			}
883223637Sbz
884223637Sbz			if ($9.match_tag)
885223637Sbz				if (strlcpy(r.match_tagname, $9.match_tag,
886223637Sbz				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
887223637Sbz					yyerror("tag too long, max %u chars",
888223637Sbz					    PF_TAG_NAME_SIZE - 1);
889223637Sbz					YYERROR;
890223637Sbz				}
891223637Sbz			r.match_tag_not = $9.match_tag_not;
892223637Sbz
893171172Smlaier			decide_address_family($8.src.host, &r.af);
894171172Smlaier			decide_address_family($8.dst.host, &r.af);
895126353Smlaier
896171172Smlaier			expand_rule(&r, $5, NULL, $7, $8.src_os,
897171172Smlaier			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
898223637Sbz			    $9.uid, $9.gid, $9.icmpspec,
899223637Sbz			    pf->astack[pf->asd + 1] ? pf->alast->name : $2);
900145840Smlaier			free($2);
901171172Smlaier			pf->astack[pf->asd + 1] = NULL;
902126353Smlaier		}
903171172Smlaier		| NATANCHOR string interface af proto fromto rtable {
904126353Smlaier			struct pf_rule	r;
905126353Smlaier
906130617Smlaier			if (check_rulestate(PFCTL_STATE_NAT)) {
907130617Smlaier				free($2);
908126353Smlaier				YYERROR;
909130617Smlaier			}
910126353Smlaier
911145840Smlaier			memset(&r, 0, sizeof(r));
912126353Smlaier			r.action = PF_NAT;
913126353Smlaier			r.af = $4;
914171172Smlaier			r.rtableid = $7;
915126353Smlaier
916126353Smlaier			decide_address_family($6.src.host, &r.af);
917126353Smlaier			decide_address_family($6.dst.host, &r.af);
918126353Smlaier
919126353Smlaier			expand_rule(&r, $3, NULL, $5, $6.src_os,
920126353Smlaier			    $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
921145840Smlaier			    0, 0, 0, $2);
922145840Smlaier			free($2);
923126353Smlaier		}
924171172Smlaier		| RDRANCHOR string interface af proto fromto rtable {
925126353Smlaier			struct pf_rule	r;
926126353Smlaier
927130617Smlaier			if (check_rulestate(PFCTL_STATE_NAT)) {
928130617Smlaier				free($2);
929126353Smlaier				YYERROR;
930130617Smlaier			}
931126353Smlaier
932145840Smlaier			memset(&r, 0, sizeof(r));
933126353Smlaier			r.action = PF_RDR;
934126353Smlaier			r.af = $4;
935171172Smlaier			r.rtableid = $7;
936126353Smlaier
937126353Smlaier			decide_address_family($6.src.host, &r.af);
938126353Smlaier			decide_address_family($6.dst.host, &r.af);
939126353Smlaier
940126353Smlaier			if ($6.src.port != NULL) {
941126353Smlaier				yyerror("source port parameter not supported"
942126353Smlaier				    " in rdr-anchor");
943126353Smlaier				YYERROR;
944126353Smlaier			}
945126353Smlaier			if ($6.dst.port != NULL) {
946126353Smlaier				if ($6.dst.port->next != NULL) {
947126353Smlaier					yyerror("destination port list "
948126353Smlaier					    "expansion not supported in "
949126353Smlaier					    "rdr-anchor");
950126353Smlaier					YYERROR;
951126353Smlaier				} else if ($6.dst.port->op != PF_OP_EQ) {
952126353Smlaier					yyerror("destination port operators"
953126353Smlaier					    " not supported in rdr-anchor");
954126353Smlaier					YYERROR;
955126353Smlaier				}
956126353Smlaier				r.dst.port[0] = $6.dst.port->port[0];
957126353Smlaier				r.dst.port[1] = $6.dst.port->port[1];
958126353Smlaier				r.dst.port_op = $6.dst.port->op;
959126353Smlaier			}
960126353Smlaier
961126353Smlaier			expand_rule(&r, $3, NULL, $5, $6.src_os,
962126353Smlaier			    $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
963145840Smlaier			    0, 0, 0, $2);
964145840Smlaier			free($2);
965126353Smlaier		}
966171172Smlaier		| BINATANCHOR string interface af proto fromto rtable {
967126353Smlaier			struct pf_rule	r;
968126353Smlaier
969130617Smlaier			if (check_rulestate(PFCTL_STATE_NAT)) {
970130617Smlaier				free($2);
971126353Smlaier				YYERROR;
972130617Smlaier			}
973126353Smlaier
974145840Smlaier			memset(&r, 0, sizeof(r));
975126353Smlaier			r.action = PF_BINAT;
976126353Smlaier			r.af = $4;
977171172Smlaier			r.rtableid = $7;
978126353Smlaier			if ($5 != NULL) {
979126353Smlaier				if ($5->next != NULL) {
980126353Smlaier					yyerror("proto list expansion"
981126353Smlaier					    " not supported in binat-anchor");
982126353Smlaier					YYERROR;
983126353Smlaier				}
984126353Smlaier				r.proto = $5->proto;
985126353Smlaier				free($5);
986126353Smlaier			}
987126353Smlaier
988126353Smlaier			if ($6.src.host != NULL || $6.src.port != NULL ||
989126353Smlaier			    $6.dst.host != NULL || $6.dst.port != NULL) {
990126353Smlaier				yyerror("fromto parameter not supported"
991126353Smlaier				    " in binat-anchor");
992126353Smlaier				YYERROR;
993126353Smlaier			}
994126353Smlaier
995126353Smlaier			decide_address_family($6.src.host, &r.af);
996126353Smlaier			decide_address_family($6.dst.host, &r.af);
997126353Smlaier
998145840Smlaier			pfctl_add_rule(pf, &r, $2);
999145840Smlaier			free($2);
1000126353Smlaier		}
1001126353Smlaier		;
1002126353Smlaier
1003126353Smlaierloadrule	: LOAD ANCHOR string FROM string	{
1004126353Smlaier			struct loadanchors	*loadanchor;
1005126353Smlaier
1006171172Smlaier			if (strlen(pf->anchor->name) + 1 +
1007171172Smlaier			    strlen($3) >= MAXPATHLEN) {
1008126353Smlaier				yyerror("anchorname %s too long, max %u\n",
1009145840Smlaier				    $3, MAXPATHLEN - 1);
1010145840Smlaier				free($3);
1011126353Smlaier				YYERROR;
1012126353Smlaier			}
1013126353Smlaier			loadanchor = calloc(1, sizeof(struct loadanchors));
1014126353Smlaier			if (loadanchor == NULL)
1015126353Smlaier				err(1, "loadrule: calloc");
1016171172Smlaier			if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
1017171172Smlaier			    NULL)
1018171172Smlaier				err(1, "loadrule: malloc");
1019171172Smlaier			if (pf->anchor->name[0])
1020171172Smlaier				snprintf(loadanchor->anchorname, MAXPATHLEN,
1021171172Smlaier				    "%s/%s", pf->anchor->name, $3);
1022171172Smlaier			else
1023171172Smlaier				strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
1024126353Smlaier			if ((loadanchor->filename = strdup($5)) == NULL)
1025126353Smlaier				err(1, "loadrule: strdup");
1026126353Smlaier
1027126353Smlaier			TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
1028126353Smlaier			    entries);
1029126353Smlaier
1030145840Smlaier			free($3);
1031126353Smlaier			free($5);
1032126353Smlaier		};
1033126353Smlaier
1034145840Smlaierscrubaction	: no SCRUB {
1035145840Smlaier			$$.b2 = $$.w = 0;
1036145840Smlaier			if ($1)
1037145840Smlaier				$$.b1 = PF_NOSCRUB;
1038145840Smlaier			else
1039145840Smlaier				$$.b1 = PF_SCRUB;
1040145840Smlaier		}
1041145840Smlaier		;
1042145840Smlaier
1043145840Smlaierscrubrule	: scrubaction dir logquick interface af proto fromto scrub_opts
1044126353Smlaier		{
1045126353Smlaier			struct pf_rule	r;
1046126353Smlaier
1047126353Smlaier			if (check_rulestate(PFCTL_STATE_SCRUB))
1048126353Smlaier				YYERROR;
1049126353Smlaier
1050126353Smlaier			memset(&r, 0, sizeof(r));
1051126353Smlaier
1052145840Smlaier			r.action = $1.b1;
1053126353Smlaier			r.direction = $2;
1054126353Smlaier
1055126353Smlaier			r.log = $3.log;
1056171172Smlaier			r.logif = $3.logif;
1057126353Smlaier			if ($3.quick) {
1058126353Smlaier				yyerror("scrub rules do not support 'quick'");
1059126353Smlaier				YYERROR;
1060126353Smlaier			}
1061126353Smlaier
1062126353Smlaier			r.af = $5;
1063126353Smlaier			if ($8.nodf)
1064126353Smlaier				r.rule_flag |= PFRULE_NODF;
1065126353Smlaier			if ($8.randomid)
1066126353Smlaier				r.rule_flag |= PFRULE_RANDOMID;
1067126353Smlaier			if ($8.reassemble_tcp) {
1068126353Smlaier				if (r.direction != PF_INOUT) {
1069126353Smlaier					yyerror("reassemble tcp rules can not "
1070126353Smlaier					    "specify direction");
1071126353Smlaier					YYERROR;
1072126353Smlaier				}
1073126353Smlaier				r.rule_flag |= PFRULE_REASSEMBLE_TCP;
1074126353Smlaier			}
1075126353Smlaier			if ($8.minttl)
1076126353Smlaier				r.min_ttl = $8.minttl;
1077126353Smlaier			if ($8.maxmss)
1078126353Smlaier				r.max_mss = $8.maxmss;
1079223637Sbz			if ($8.marker & SOM_SETTOS) {
1080223637Sbz				r.rule_flag |= PFRULE_SET_TOS;
1081223637Sbz				r.set_tos = $8.settos;
1082223637Sbz			}
1083126353Smlaier			if ($8.fragcache)
1084126353Smlaier				r.rule_flag |= $8.fragcache;
1085223637Sbz			if ($8.match_tag)
1086223637Sbz				if (strlcpy(r.match_tagname, $8.match_tag,
1087223637Sbz				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1088223637Sbz					yyerror("tag too long, max %u chars",
1089223637Sbz					    PF_TAG_NAME_SIZE - 1);
1090223637Sbz					YYERROR;
1091223637Sbz				}
1092223637Sbz			r.match_tag_not = $8.match_tag_not;
1093171172Smlaier			r.rtableid = $8.rtableid;
1094126353Smlaier
1095126353Smlaier			expand_rule(&r, $4, NULL, $6, $7.src_os,
1096126353Smlaier			    $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
1097145840Smlaier			    NULL, NULL, NULL, "");
1098126353Smlaier		}
1099126353Smlaier		;
1100126353Smlaier
1101126353Smlaierscrub_opts	:	{
1102171172Smlaier				bzero(&scrub_opts, sizeof scrub_opts);
1103171172Smlaier				scrub_opts.rtableid = -1;
1104171172Smlaier			}
1105130617Smlaier		    scrub_opts_l
1106126353Smlaier			{ $$ = scrub_opts; }
1107126353Smlaier		| /* empty */ {
1108126353Smlaier			bzero(&scrub_opts, sizeof scrub_opts);
1109171172Smlaier			scrub_opts.rtableid = -1;
1110126353Smlaier			$$ = scrub_opts;
1111126353Smlaier		}
1112126353Smlaier		;
1113126353Smlaier
1114126353Smlaierscrub_opts_l	: scrub_opts_l scrub_opt
1115126353Smlaier		| scrub_opt
1116126353Smlaier		;
1117126353Smlaier
1118126353Smlaierscrub_opt	: NODF	{
1119126353Smlaier			if (scrub_opts.nodf) {
1120126353Smlaier				yyerror("no-df cannot be respecified");
1121126353Smlaier				YYERROR;
1122126353Smlaier			}
1123126353Smlaier			scrub_opts.nodf = 1;
1124126353Smlaier		}
1125223637Sbz		| MINTTL NUMBER {
1126126353Smlaier			if (scrub_opts.marker & SOM_MINTTL) {
1127126353Smlaier				yyerror("min-ttl cannot be respecified");
1128126353Smlaier				YYERROR;
1129126353Smlaier			}
1130223637Sbz			if ($2 < 0 || $2 > 255) {
1131126353Smlaier				yyerror("illegal min-ttl value %d", $2);
1132126353Smlaier				YYERROR;
1133126353Smlaier			}
1134126353Smlaier			scrub_opts.marker |= SOM_MINTTL;
1135126353Smlaier			scrub_opts.minttl = $2;
1136126353Smlaier		}
1137223637Sbz		| MAXMSS NUMBER {
1138126353Smlaier			if (scrub_opts.marker & SOM_MAXMSS) {
1139126353Smlaier				yyerror("max-mss cannot be respecified");
1140126353Smlaier				YYERROR;
1141126353Smlaier			}
1142223637Sbz			if ($2 < 0 || $2 > 65535) {
1143126353Smlaier				yyerror("illegal max-mss value %d", $2);
1144126353Smlaier				YYERROR;
1145126353Smlaier			}
1146126353Smlaier			scrub_opts.marker |= SOM_MAXMSS;
1147126353Smlaier			scrub_opts.maxmss = $2;
1148126353Smlaier		}
1149223637Sbz		| SETTOS tos {
1150223637Sbz			if (scrub_opts.marker & SOM_SETTOS) {
1151223637Sbz				yyerror("set-tos cannot be respecified");
1152223637Sbz				YYERROR;
1153223637Sbz			}
1154223637Sbz			scrub_opts.marker |= SOM_SETTOS;
1155223637Sbz			scrub_opts.settos = $2;
1156223637Sbz		}
1157126353Smlaier		| fragcache {
1158126353Smlaier			if (scrub_opts.marker & SOM_FRAGCACHE) {
1159126353Smlaier				yyerror("fragcache cannot be respecified");
1160126353Smlaier				YYERROR;
1161126353Smlaier			}
1162126353Smlaier			scrub_opts.marker |= SOM_FRAGCACHE;
1163126353Smlaier			scrub_opts.fragcache = $1;
1164126353Smlaier		}
1165126353Smlaier		| REASSEMBLE STRING {
1166130617Smlaier			if (strcasecmp($2, "tcp") != 0) {
1167145840Smlaier				yyerror("scrub reassemble supports only tcp, "
1168145840Smlaier				    "not '%s'", $2);
1169130617Smlaier				free($2);
1170126353Smlaier				YYERROR;
1171130617Smlaier			}
1172130617Smlaier			free($2);
1173126353Smlaier			if (scrub_opts.reassemble_tcp) {
1174126353Smlaier				yyerror("reassemble tcp cannot be respecified");
1175126353Smlaier				YYERROR;
1176126353Smlaier			}
1177126353Smlaier			scrub_opts.reassemble_tcp = 1;
1178126353Smlaier		}
1179126353Smlaier		| RANDOMID {
1180126353Smlaier			if (scrub_opts.randomid) {
1181126353Smlaier				yyerror("random-id cannot be respecified");
1182126353Smlaier				YYERROR;
1183126353Smlaier			}
1184126353Smlaier			scrub_opts.randomid = 1;
1185126353Smlaier		}
1186223637Sbz		| RTABLE NUMBER				{
1187231852Sbz			if ($2 < 0 || $2 > rt_tableid_max()) {
1188171172Smlaier				yyerror("invalid rtable id");
1189171172Smlaier				YYERROR;
1190171172Smlaier			}
1191171172Smlaier			scrub_opts.rtableid = $2;
1192171172Smlaier		}
1193223637Sbz		| not TAGGED string			{
1194223637Sbz			scrub_opts.match_tag = $3;
1195223637Sbz			scrub_opts.match_tag_not = $1;
1196223637Sbz		}
1197126353Smlaier		;
1198126353Smlaier
1199126353Smlaierfragcache	: FRAGMENT REASSEMBLE	{ $$ = 0; /* default */ }
1200126353Smlaier		| FRAGMENT FRAGCROP	{ $$ = PFRULE_FRAGCROP; }
1201126353Smlaier		| FRAGMENT FRAGDROP	{ $$ = PFRULE_FRAGDROP; }
1202126353Smlaier		;
1203126353Smlaier
1204126353Smlaierantispoof	: ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
1205126353Smlaier			struct pf_rule		 r;
1206145840Smlaier			struct node_host	*h = NULL, *hh;
1207126353Smlaier			struct node_if		*i, *j;
1208126353Smlaier
1209126353Smlaier			if (check_rulestate(PFCTL_STATE_FILTER))
1210126353Smlaier				YYERROR;
1211126353Smlaier
1212126353Smlaier			for (i = $3; i; i = i->next) {
1213126353Smlaier				bzero(&r, sizeof(r));
1214126353Smlaier
1215126353Smlaier				r.action = PF_DROP;
1216126353Smlaier				r.direction = PF_IN;
1217126353Smlaier				r.log = $2.log;
1218171172Smlaier				r.logif = $2.logif;
1219126353Smlaier				r.quick = $2.quick;
1220126353Smlaier				r.af = $4;
1221126353Smlaier				if (rule_label(&r, $5.label))
1222126353Smlaier					YYERROR;
1223171172Smlaier				r.rtableid = $5.rtableid;
1224126353Smlaier				j = calloc(1, sizeof(struct node_if));
1225126353Smlaier				if (j == NULL)
1226126353Smlaier					err(1, "antispoof: calloc");
1227126353Smlaier				if (strlcpy(j->ifname, i->ifname,
1228126353Smlaier				    sizeof(j->ifname)) >= sizeof(j->ifname)) {
1229126353Smlaier					free(j);
1230126353Smlaier					yyerror("interface name too long");
1231126353Smlaier					YYERROR;
1232126353Smlaier				}
1233126353Smlaier				j->not = 1;
1234145840Smlaier				if (i->dynamic) {
1235145840Smlaier					h = calloc(1, sizeof(*h));
1236145840Smlaier					if (h == NULL)
1237145840Smlaier						err(1, "address: calloc");
1238145840Smlaier					h->addr.type = PF_ADDR_DYNIFTL;
1239145840Smlaier					set_ipmask(h, 128);
1240145840Smlaier					if (strlcpy(h->addr.v.ifname, i->ifname,
1241145840Smlaier					    sizeof(h->addr.v.ifname)) >=
1242145840Smlaier					    sizeof(h->addr.v.ifname)) {
1243145840Smlaier						free(h);
1244145840Smlaier						yyerror(
1245145840Smlaier						    "interface name too long");
1246145840Smlaier						YYERROR;
1247145840Smlaier					}
1248145840Smlaier					hh = malloc(sizeof(*hh));
1249145840Smlaier					if (hh == NULL)
1250145840Smlaier						 err(1, "address: malloc");
1251145840Smlaier					bcopy(h, hh, sizeof(*hh));
1252145840Smlaier					h->addr.iflags = PFI_AFLAG_NETWORK;
1253145840Smlaier				} else {
1254145840Smlaier					h = ifa_lookup(j->ifname,
1255145840Smlaier					    PFI_AFLAG_NETWORK);
1256145840Smlaier					hh = NULL;
1257145840Smlaier				}
1258126353Smlaier
1259130617Smlaier				if (h != NULL)
1260130617Smlaier					expand_rule(&r, j, NULL, NULL, NULL, h,
1261145840Smlaier					    NULL, NULL, NULL, NULL, NULL,
1262145840Smlaier					    NULL, "");
1263126353Smlaier
1264126353Smlaier				if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
1265126353Smlaier					bzero(&r, sizeof(r));
1266126353Smlaier
1267126353Smlaier					r.action = PF_DROP;
1268126353Smlaier					r.direction = PF_IN;
1269126353Smlaier					r.log = $2.log;
1270223637Sbz					r.logif = $2.logif;
1271126353Smlaier					r.quick = $2.quick;
1272126353Smlaier					r.af = $4;
1273126353Smlaier					if (rule_label(&r, $5.label))
1274126353Smlaier						YYERROR;
1275171172Smlaier					r.rtableid = $5.rtableid;
1276145840Smlaier					if (hh != NULL)
1277145840Smlaier						h = hh;
1278145840Smlaier					else
1279145840Smlaier						h = ifa_lookup(i->ifname, 0);
1280130617Smlaier					if (h != NULL)
1281130617Smlaier						expand_rule(&r, NULL, NULL,
1282130617Smlaier						    NULL, NULL, h, NULL, NULL,
1283145840Smlaier						    NULL, NULL, NULL, NULL, "");
1284145840Smlaier				} else
1285145840Smlaier					free(hh);
1286126353Smlaier			}
1287126353Smlaier			free($5.label);
1288126353Smlaier		}
1289126353Smlaier		;
1290126353Smlaier
1291223637Sbzantispoof_ifspc	: FOR antispoof_if			{ $$ = $2; }
1292223637Sbz		| FOR '{' optnl antispoof_iflst '}'	{ $$ = $4; }
1293126353Smlaier		;
1294126353Smlaier
1295223637Sbzantispoof_iflst	: antispoof_if optnl			{ $$ = $1; }
1296223637Sbz		| antispoof_iflst comma antispoof_if optnl {
1297126353Smlaier			$1->tail->next = $3;
1298126353Smlaier			$1->tail = $3;
1299126353Smlaier			$$ = $1;
1300126353Smlaier		}
1301126353Smlaier		;
1302126353Smlaier
1303223637Sbzantispoof_if	: if_item				{ $$ = $1; }
1304223637Sbz		| '(' if_item ')'			{
1305145840Smlaier			$2->dynamic = 1;
1306145840Smlaier			$$ = $2;
1307145840Smlaier		}
1308145840Smlaier		;
1309145840Smlaier
1310171172Smlaierantispoof_opts	:	{
1311171172Smlaier				bzero(&antispoof_opts, sizeof antispoof_opts);
1312171172Smlaier				antispoof_opts.rtableid = -1;
1313171172Smlaier			}
1314130617Smlaier		    antispoof_opts_l
1315126353Smlaier			{ $$ = antispoof_opts; }
1316126353Smlaier		| /* empty */	{
1317126353Smlaier			bzero(&antispoof_opts, sizeof antispoof_opts);
1318171172Smlaier			antispoof_opts.rtableid = -1;
1319126353Smlaier			$$ = antispoof_opts;
1320126353Smlaier		}
1321126353Smlaier		;
1322126353Smlaier
1323126353Smlaierantispoof_opts_l	: antispoof_opts_l antispoof_opt
1324126353Smlaier			| antispoof_opt
1325126353Smlaier			;
1326126353Smlaier
1327126353Smlaierantispoof_opt	: label	{
1328126353Smlaier			if (antispoof_opts.label) {
1329126353Smlaier				yyerror("label cannot be redefined");
1330126353Smlaier				YYERROR;
1331126353Smlaier			}
1332126353Smlaier			antispoof_opts.label = $1;
1333126353Smlaier		}
1334223637Sbz		| RTABLE NUMBER				{
1335231852Sbz			if ($2 < 0 || $2 > rt_tableid_max()) {
1336171172Smlaier				yyerror("invalid rtable id");
1337171172Smlaier				YYERROR;
1338171172Smlaier			}
1339171172Smlaier			antispoof_opts.rtableid = $2;
1340171172Smlaier		}
1341126353Smlaier		;
1342126353Smlaier
1343126353Smlaiernot		: '!'		{ $$ = 1; }
1344126353Smlaier		| /* empty */	{ $$ = 0; }
1345130617Smlaier		;
1346126353Smlaier
1347126353Smlaiertabledef	: TABLE '<' STRING '>' table_opts {
1348126353Smlaier			struct node_host	 *h, *nh;
1349126353Smlaier			struct node_tinit	 *ti, *nti;
1350126353Smlaier
1351126353Smlaier			if (strlen($3) >= PF_TABLE_NAME_SIZE) {
1352126353Smlaier				yyerror("table name too long, max %d chars",
1353126353Smlaier				    PF_TABLE_NAME_SIZE - 1);
1354130617Smlaier				free($3);
1355126353Smlaier				YYERROR;
1356126353Smlaier			}
1357126353Smlaier			if (pf->loadopt & PFCTL_FLAG_TABLE)
1358130617Smlaier				if (process_tabledef($3, &$5)) {
1359130617Smlaier					free($3);
1360126353Smlaier					YYERROR;
1361130617Smlaier				}
1362130617Smlaier			free($3);
1363126353Smlaier			for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
1364126353Smlaier			    ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
1365126353Smlaier				if (ti->file)
1366126353Smlaier					free(ti->file);
1367126353Smlaier				for (h = ti->host; h != NULL; h = nh) {
1368126353Smlaier					nh = h->next;
1369126353Smlaier					free(h);
1370126353Smlaier				}
1371126353Smlaier				nti = SIMPLEQ_NEXT(ti, entries);
1372130617Smlaier				free(ti);
1373126353Smlaier			}
1374126353Smlaier		}
1375126353Smlaier		;
1376126353Smlaier
1377126353Smlaiertable_opts	:	{
1378126353Smlaier			bzero(&table_opts, sizeof table_opts);
1379126353Smlaier			SIMPLEQ_INIT(&table_opts.init_nodes);
1380126353Smlaier		}
1381130617Smlaier		    table_opts_l
1382126353Smlaier			{ $$ = table_opts; }
1383126353Smlaier		| /* empty */
1384126353Smlaier			{
1385126353Smlaier			bzero(&table_opts, sizeof table_opts);
1386126353Smlaier			SIMPLEQ_INIT(&table_opts.init_nodes);
1387126353Smlaier			$$ = table_opts;
1388126353Smlaier		}
1389126353Smlaier		;
1390126353Smlaier
1391126353Smlaiertable_opts_l	: table_opts_l table_opt
1392126353Smlaier		| table_opt
1393126353Smlaier		;
1394126353Smlaier
1395126353Smlaiertable_opt	: STRING		{
1396126353Smlaier			if (!strcmp($1, "const"))
1397126353Smlaier				table_opts.flags |= PFR_TFLAG_CONST;
1398126353Smlaier			else if (!strcmp($1, "persist"))
1399126353Smlaier				table_opts.flags |= PFR_TFLAG_PERSIST;
1400223637Sbz			else if (!strcmp($1, "counters"))
1401223637Sbz				table_opts.flags |= PFR_TFLAG_COUNTERS;
1402130617Smlaier			else {
1403145840Smlaier				yyerror("invalid table option '%s'", $1);
1404130617Smlaier				free($1);
1405126353Smlaier				YYERROR;
1406130617Smlaier			}
1407130617Smlaier			free($1);
1408126353Smlaier		}
1409223637Sbz		| '{' optnl '}'		{ table_opts.init_addr = 1; }
1410223637Sbz		| '{' optnl host_list '}'	{
1411126353Smlaier			struct node_host	*n;
1412126353Smlaier			struct node_tinit	*ti;
1413126353Smlaier
1414223637Sbz			for (n = $3; n != NULL; n = n->next) {
1415130617Smlaier				switch (n->addr.type) {
1416126353Smlaier				case PF_ADDR_ADDRMASK:
1417126353Smlaier					continue; /* ok */
1418223637Sbz				case PF_ADDR_RANGE:
1419223637Sbz					yyerror("address ranges are not "
1420223637Sbz					    "permitted inside tables");
1421223637Sbz					break;
1422126353Smlaier				case PF_ADDR_DYNIFTL:
1423126353Smlaier					yyerror("dynamic addresses are not "
1424126353Smlaier					    "permitted inside tables");
1425126353Smlaier					break;
1426126353Smlaier				case PF_ADDR_TABLE:
1427126353Smlaier					yyerror("tables cannot contain tables");
1428126353Smlaier					break;
1429126353Smlaier				case PF_ADDR_NOROUTE:
1430126353Smlaier					yyerror("\"no-route\" is not permitted "
1431126353Smlaier					    "inside tables");
1432126353Smlaier					break;
1433171172Smlaier				case PF_ADDR_URPFFAILED:
1434171172Smlaier					yyerror("\"urpf-failed\" is not "
1435171172Smlaier					    "permitted inside tables");
1436171172Smlaier					break;
1437126353Smlaier				default:
1438126353Smlaier					yyerror("unknown address type %d",
1439126353Smlaier					    n->addr.type);
1440126353Smlaier				}
1441126353Smlaier				YYERROR;
1442126353Smlaier			}
1443126353Smlaier			if (!(ti = calloc(1, sizeof(*ti))))
1444126353Smlaier				err(1, "table_opt: calloc");
1445223637Sbz			ti->host = $3;
1446126353Smlaier			SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1447126353Smlaier			    entries);
1448126353Smlaier			table_opts.init_addr = 1;
1449126353Smlaier		}
1450126353Smlaier		| FILENAME STRING	{
1451126353Smlaier			struct node_tinit	*ti;
1452126353Smlaier
1453126353Smlaier			if (!(ti = calloc(1, sizeof(*ti))))
1454126353Smlaier				err(1, "table_opt: calloc");
1455126353Smlaier			ti->file = $2;
1456126353Smlaier			SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1457126353Smlaier			    entries);
1458126353Smlaier			table_opts.init_addr = 1;
1459126353Smlaier		}
1460126353Smlaier		;
1461126353Smlaier
1462126353Smlaieraltqif		: ALTQ interface queue_opts QUEUE qassign {
1463126353Smlaier			struct pf_altq	a;
1464126353Smlaier
1465126353Smlaier			if (check_rulestate(PFCTL_STATE_QUEUE))
1466126353Smlaier				YYERROR;
1467126353Smlaier
1468126353Smlaier			memset(&a, 0, sizeof(a));
1469126353Smlaier			if ($3.scheduler.qtype == ALTQT_NONE) {
1470126353Smlaier				yyerror("no scheduler specified!");
1471126353Smlaier				YYERROR;
1472126353Smlaier			}
1473126353Smlaier			a.scheduler = $3.scheduler.qtype;
1474126353Smlaier			a.qlimit = $3.qlimit;
1475126353Smlaier			a.tbrsize = $3.tbrsize;
1476298133Sloos			if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
1477126353Smlaier				yyerror("no child queues specified");
1478126353Smlaier				YYERROR;
1479126353Smlaier			}
1480126353Smlaier			if (expand_altq(&a, $2, $5, $3.queue_bwspec,
1481126353Smlaier			    &$3.scheduler))
1482126353Smlaier				YYERROR;
1483126353Smlaier		}
1484126353Smlaier		;
1485126353Smlaier
1486126353Smlaierqueuespec	: QUEUE STRING interface queue_opts qassign {
1487126353Smlaier			struct pf_altq	a;
1488126353Smlaier
1489130617Smlaier			if (check_rulestate(PFCTL_STATE_QUEUE)) {
1490130617Smlaier				free($2);
1491126353Smlaier				YYERROR;
1492130617Smlaier			}
1493126353Smlaier
1494126353Smlaier			memset(&a, 0, sizeof(a));
1495126353Smlaier
1496126353Smlaier			if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
1497126353Smlaier			    sizeof(a.qname)) {
1498126353Smlaier				yyerror("queue name too long (max "
1499126353Smlaier				    "%d chars)", PF_QNAME_SIZE-1);
1500130617Smlaier				free($2);
1501126353Smlaier				YYERROR;
1502126353Smlaier			}
1503130617Smlaier			free($2);
1504126353Smlaier			if ($4.tbrsize) {
1505126353Smlaier				yyerror("cannot specify tbrsize for queue");
1506126353Smlaier				YYERROR;
1507126353Smlaier			}
1508126353Smlaier			if ($4.priority > 255) {
1509126353Smlaier				yyerror("priority out of range: max 255");
1510126353Smlaier				YYERROR;
1511126353Smlaier			}
1512126353Smlaier			a.priority = $4.priority;
1513126353Smlaier			a.qlimit = $4.qlimit;
1514126353Smlaier			a.scheduler = $4.scheduler.qtype;
1515126353Smlaier			if (expand_queue(&a, $3, $5, $4.queue_bwspec,
1516126353Smlaier			    &$4.scheduler)) {
1517126353Smlaier				yyerror("errors in queue definition");
1518126353Smlaier				YYERROR;
1519126353Smlaier			}
1520126353Smlaier		}
1521126353Smlaier		;
1522126353Smlaier
1523126353Smlaierqueue_opts	:	{
1524126353Smlaier			bzero(&queue_opts, sizeof queue_opts);
1525126353Smlaier			queue_opts.priority = DEFAULT_PRIORITY;
1526126353Smlaier			queue_opts.qlimit = DEFAULT_QLIMIT;
1527126353Smlaier			queue_opts.scheduler.qtype = ALTQT_NONE;
1528126353Smlaier			queue_opts.queue_bwspec.bw_percent = 100;
1529126353Smlaier		}
1530130617Smlaier		    queue_opts_l
1531126353Smlaier			{ $$ = queue_opts; }
1532126353Smlaier		| /* empty */ {
1533126353Smlaier			bzero(&queue_opts, sizeof queue_opts);
1534126353Smlaier			queue_opts.priority = DEFAULT_PRIORITY;
1535126353Smlaier			queue_opts.qlimit = DEFAULT_QLIMIT;
1536126353Smlaier			queue_opts.scheduler.qtype = ALTQT_NONE;
1537126353Smlaier			queue_opts.queue_bwspec.bw_percent = 100;
1538126353Smlaier			$$ = queue_opts;
1539126353Smlaier		}
1540126353Smlaier		;
1541126353Smlaier
1542126353Smlaierqueue_opts_l	: queue_opts_l queue_opt
1543126353Smlaier		| queue_opt
1544126353Smlaier		;
1545126353Smlaier
1546126353Smlaierqueue_opt	: BANDWIDTH bandwidth	{
1547126353Smlaier			if (queue_opts.marker & QOM_BWSPEC) {
1548126353Smlaier				yyerror("bandwidth cannot be respecified");
1549126353Smlaier				YYERROR;
1550126353Smlaier			}
1551126353Smlaier			queue_opts.marker |= QOM_BWSPEC;
1552126353Smlaier			queue_opts.queue_bwspec = $2;
1553126353Smlaier		}
1554223637Sbz		| PRIORITY NUMBER	{
1555126353Smlaier			if (queue_opts.marker & QOM_PRIORITY) {
1556126353Smlaier				yyerror("priority cannot be respecified");
1557126353Smlaier				YYERROR;
1558126353Smlaier			}
1559223637Sbz			if ($2 < 0 || $2 > 255) {
1560126353Smlaier				yyerror("priority out of range: max 255");
1561126353Smlaier				YYERROR;
1562126353Smlaier			}
1563126353Smlaier			queue_opts.marker |= QOM_PRIORITY;
1564126353Smlaier			queue_opts.priority = $2;
1565126353Smlaier		}
1566223637Sbz		| QLIMIT NUMBER	{
1567126353Smlaier			if (queue_opts.marker & QOM_QLIMIT) {
1568126353Smlaier				yyerror("qlimit cannot be respecified");
1569126353Smlaier				YYERROR;
1570126353Smlaier			}
1571223637Sbz			if ($2 < 0 || $2 > 65535) {
1572126353Smlaier				yyerror("qlimit out of range: max 65535");
1573126353Smlaier				YYERROR;
1574126353Smlaier			}
1575126353Smlaier			queue_opts.marker |= QOM_QLIMIT;
1576126353Smlaier			queue_opts.qlimit = $2;
1577126353Smlaier		}
1578126353Smlaier		| scheduler	{
1579126353Smlaier			if (queue_opts.marker & QOM_SCHEDULER) {
1580126353Smlaier				yyerror("scheduler cannot be respecified");
1581126353Smlaier				YYERROR;
1582126353Smlaier			}
1583126353Smlaier			queue_opts.marker |= QOM_SCHEDULER;
1584126353Smlaier			queue_opts.scheduler = $1;
1585126353Smlaier		}
1586223637Sbz		| TBRSIZE NUMBER	{
1587126353Smlaier			if (queue_opts.marker & QOM_TBRSIZE) {
1588126353Smlaier				yyerror("tbrsize cannot be respecified");
1589126353Smlaier				YYERROR;
1590126353Smlaier			}
1591223637Sbz			if ($2 < 0 || $2 > 65535) {
1592126353Smlaier				yyerror("tbrsize too big: max 65535");
1593126353Smlaier				YYERROR;
1594126353Smlaier			}
1595126353Smlaier			queue_opts.marker |= QOM_TBRSIZE;
1596126353Smlaier			queue_opts.tbrsize = $2;
1597126353Smlaier		}
1598126353Smlaier		;
1599126353Smlaier
1600126353Smlaierbandwidth	: STRING {
1601126353Smlaier			double	 bps;
1602126353Smlaier			char	*cp;
1603126353Smlaier
1604126353Smlaier			$$.bw_percent = 0;
1605126353Smlaier
1606126353Smlaier			bps = strtod($1, &cp);
1607126353Smlaier			if (cp != NULL) {
1608300514Sloos				if (strlen(cp) > 1) {
1609300514Sloos					char *cu = cp + 1;
1610300514Sloos					if (!strcmp(cu, "Bit") ||
1611300514Sloos					    !strcmp(cu, "B") ||
1612300514Sloos					    !strcmp(cu, "bit") ||
1613300514Sloos					    !strcmp(cu, "b")) {
1614300514Sloos						*cu = 0;
1615300514Sloos					}
1616300514Sloos				}
1617126353Smlaier				if (!strcmp(cp, "b"))
1618126353Smlaier					; /* nothing */
1619300514Sloos				else if (!strcmp(cp, "K"))
1620126353Smlaier					bps *= 1000;
1621300514Sloos				else if (!strcmp(cp, "M"))
1622126353Smlaier					bps *= 1000 * 1000;
1623300514Sloos				else if (!strcmp(cp, "G"))
1624126353Smlaier					bps *= 1000 * 1000 * 1000;
1625126353Smlaier				else if (!strcmp(cp, "%")) {
1626126353Smlaier					if (bps < 0 || bps > 100) {
1627126353Smlaier						yyerror("bandwidth spec "
1628126353Smlaier						    "out of range");
1629130617Smlaier						free($1);
1630126353Smlaier						YYERROR;
1631126353Smlaier					}
1632126353Smlaier					$$.bw_percent = bps;
1633126353Smlaier					bps = 0;
1634126353Smlaier				} else {
1635126353Smlaier					yyerror("unknown unit %s", cp);
1636130617Smlaier					free($1);
1637126353Smlaier					YYERROR;
1638126353Smlaier				}
1639126353Smlaier			}
1640130617Smlaier			free($1);
1641126353Smlaier			$$.bw_absolute = (u_int32_t)bps;
1642126353Smlaier		}
1643223637Sbz		| NUMBER {
1644223637Sbz			if ($1 < 0 || $1 > UINT_MAX) {
1645223637Sbz				yyerror("bandwidth number too big");
1646223637Sbz				YYERROR;
1647223637Sbz			}
1648223637Sbz			$$.bw_percent = 0;
1649223637Sbz			$$.bw_absolute = $1;
1650223637Sbz		}
1651130617Smlaier		;
1652126353Smlaier
1653126353Smlaierscheduler	: CBQ				{
1654126353Smlaier			$$.qtype = ALTQT_CBQ;
1655126353Smlaier			$$.data.cbq_opts.flags = 0;
1656126353Smlaier		}
1657126353Smlaier		| CBQ '(' cbqflags_list ')'	{
1658126353Smlaier			$$.qtype = ALTQT_CBQ;
1659126353Smlaier			$$.data.cbq_opts.flags = $3;
1660126353Smlaier		}
1661126353Smlaier		| PRIQ				{
1662126353Smlaier			$$.qtype = ALTQT_PRIQ;
1663126353Smlaier			$$.data.priq_opts.flags = 0;
1664126353Smlaier		}
1665126353Smlaier		| PRIQ '(' priqflags_list ')'	{
1666126353Smlaier			$$.qtype = ALTQT_PRIQ;
1667126353Smlaier			$$.data.priq_opts.flags = $3;
1668126353Smlaier		}
1669126353Smlaier		| HFSC				{
1670126353Smlaier			$$.qtype = ALTQT_HFSC;
1671126353Smlaier			bzero(&$$.data.hfsc_opts,
1672126353Smlaier			    sizeof(struct node_hfsc_opts));
1673126353Smlaier		}
1674126353Smlaier		| HFSC '(' hfsc_opts ')'	{
1675126353Smlaier			$$.qtype = ALTQT_HFSC;
1676126353Smlaier			$$.data.hfsc_opts = $3;
1677126353Smlaier		}
1678298091Sloos		| FAIRQ				{
1679298091Sloos			$$.qtype = ALTQT_FAIRQ;
1680298091Sloos			bzero(&$$.data.fairq_opts,
1681298091Sloos				sizeof(struct node_fairq_opts));
1682298091Sloos		}
1683298091Sloos		| FAIRQ '(' fairq_opts ')'      {
1684298091Sloos			$$.qtype = ALTQT_FAIRQ;
1685298091Sloos			$$.data.fairq_opts = $3;
1686298091Sloos		}
1687298133Sloos		| CODEL				{
1688298133Sloos			$$.qtype = ALTQT_CODEL;
1689298133Sloos			bzero(&$$.data.codel_opts,
1690298133Sloos				sizeof(struct codel_opts));
1691298133Sloos		}
1692298133Sloos		| CODEL '(' codel_opts ')'	{
1693298133Sloos			$$.qtype = ALTQT_CODEL;
1694298133Sloos			$$.data.codel_opts = $3;
1695298133Sloos		}
1696126353Smlaier		;
1697126353Smlaier
1698126353Smlaiercbqflags_list	: cbqflags_item				{ $$ |= $1; }
1699126353Smlaier		| cbqflags_list comma cbqflags_item	{ $$ |= $3; }
1700126353Smlaier		;
1701126353Smlaier
1702126353Smlaiercbqflags_item	: STRING	{
1703126353Smlaier			if (!strcmp($1, "default"))
1704126353Smlaier				$$ = CBQCLF_DEFCLASS;
1705126353Smlaier			else if (!strcmp($1, "borrow"))
1706126353Smlaier				$$ = CBQCLF_BORROW;
1707126353Smlaier			else if (!strcmp($1, "red"))
1708126353Smlaier				$$ = CBQCLF_RED;
1709126353Smlaier			else if (!strcmp($1, "ecn"))
1710126353Smlaier				$$ = CBQCLF_RED|CBQCLF_ECN;
1711126353Smlaier			else if (!strcmp($1, "rio"))
1712126353Smlaier				$$ = CBQCLF_RIO;
1713298133Sloos			else if (!strcmp($1, "codel"))
1714298133Sloos				$$ = CBQCLF_CODEL;
1715126353Smlaier			else {
1716126353Smlaier				yyerror("unknown cbq flag \"%s\"", $1);
1717130617Smlaier				free($1);
1718126353Smlaier				YYERROR;
1719126353Smlaier			}
1720130617Smlaier			free($1);
1721126353Smlaier		}
1722126353Smlaier		;
1723126353Smlaier
1724126353Smlaierpriqflags_list	: priqflags_item			{ $$ |= $1; }
1725126353Smlaier		| priqflags_list comma priqflags_item	{ $$ |= $3; }
1726126353Smlaier		;
1727126353Smlaier
1728126353Smlaierpriqflags_item	: STRING	{
1729126353Smlaier			if (!strcmp($1, "default"))
1730126353Smlaier				$$ = PRCF_DEFAULTCLASS;
1731126353Smlaier			else if (!strcmp($1, "red"))
1732126353Smlaier				$$ = PRCF_RED;
1733126353Smlaier			else if (!strcmp($1, "ecn"))
1734126353Smlaier				$$ = PRCF_RED|PRCF_ECN;
1735126353Smlaier			else if (!strcmp($1, "rio"))
1736126353Smlaier				$$ = PRCF_RIO;
1737298133Sloos			else if (!strcmp($1, "codel"))
1738298133Sloos				$$ = PRCF_CODEL;
1739126353Smlaier			else {
1740126353Smlaier				yyerror("unknown priq flag \"%s\"", $1);
1741130617Smlaier				free($1);
1742126353Smlaier				YYERROR;
1743126353Smlaier			}
1744130617Smlaier			free($1);
1745126353Smlaier		}
1746126353Smlaier		;
1747126353Smlaier
1748126353Smlaierhfsc_opts	:	{
1749126353Smlaier				bzero(&hfsc_opts,
1750126353Smlaier				    sizeof(struct node_hfsc_opts));
1751126353Smlaier			}
1752130617Smlaier		    hfscopts_list				{
1753126353Smlaier			$$ = hfsc_opts;
1754126353Smlaier		}
1755126353Smlaier		;
1756126353Smlaier
1757126353Smlaierhfscopts_list	: hfscopts_item
1758126353Smlaier		| hfscopts_list comma hfscopts_item
1759126353Smlaier		;
1760126353Smlaier
1761126353Smlaierhfscopts_item	: LINKSHARE bandwidth				{
1762126353Smlaier			if (hfsc_opts.linkshare.used) {
1763126353Smlaier				yyerror("linkshare already specified");
1764126353Smlaier				YYERROR;
1765126353Smlaier			}
1766126353Smlaier			hfsc_opts.linkshare.m2 = $2;
1767126353Smlaier			hfsc_opts.linkshare.used = 1;
1768126353Smlaier		}
1769223637Sbz		| LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'
1770145840Smlaier		    {
1771223637Sbz			if ($5 < 0 || $5 > INT_MAX) {
1772223637Sbz				yyerror("timing in curve out of range");
1773223637Sbz				YYERROR;
1774223637Sbz			}
1775126353Smlaier			if (hfsc_opts.linkshare.used) {
1776126353Smlaier				yyerror("linkshare already specified");
1777126353Smlaier				YYERROR;
1778126353Smlaier			}
1779126353Smlaier			hfsc_opts.linkshare.m1 = $3;
1780145840Smlaier			hfsc_opts.linkshare.d = $5;
1781145840Smlaier			hfsc_opts.linkshare.m2 = $7;
1782126353Smlaier			hfsc_opts.linkshare.used = 1;
1783126353Smlaier		}
1784126353Smlaier		| REALTIME bandwidth				{
1785126353Smlaier			if (hfsc_opts.realtime.used) {
1786126353Smlaier				yyerror("realtime already specified");
1787126353Smlaier				YYERROR;
1788126353Smlaier			}
1789126353Smlaier			hfsc_opts.realtime.m2 = $2;
1790126353Smlaier			hfsc_opts.realtime.used = 1;
1791126353Smlaier		}
1792223637Sbz		| REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'
1793145840Smlaier		    {
1794223637Sbz			if ($5 < 0 || $5 > INT_MAX) {
1795223637Sbz				yyerror("timing in curve out of range");
1796223637Sbz				YYERROR;
1797223637Sbz			}
1798126353Smlaier			if (hfsc_opts.realtime.used) {
1799126353Smlaier				yyerror("realtime already specified");
1800126353Smlaier				YYERROR;
1801126353Smlaier			}
1802126353Smlaier			hfsc_opts.realtime.m1 = $3;
1803145840Smlaier			hfsc_opts.realtime.d = $5;
1804145840Smlaier			hfsc_opts.realtime.m2 = $7;
1805126353Smlaier			hfsc_opts.realtime.used = 1;
1806126353Smlaier		}
1807126353Smlaier		| UPPERLIMIT bandwidth				{
1808126353Smlaier			if (hfsc_opts.upperlimit.used) {
1809126353Smlaier				yyerror("upperlimit already specified");
1810126353Smlaier				YYERROR;
1811126353Smlaier			}
1812126353Smlaier			hfsc_opts.upperlimit.m2 = $2;
1813126353Smlaier			hfsc_opts.upperlimit.used = 1;
1814126353Smlaier		}
1815223637Sbz		| UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'
1816145840Smlaier		    {
1817223637Sbz			if ($5 < 0 || $5 > INT_MAX) {
1818223637Sbz				yyerror("timing in curve out of range");
1819223637Sbz				YYERROR;
1820223637Sbz			}
1821126353Smlaier			if (hfsc_opts.upperlimit.used) {
1822126353Smlaier				yyerror("upperlimit already specified");
1823126353Smlaier				YYERROR;
1824126353Smlaier			}
1825126353Smlaier			hfsc_opts.upperlimit.m1 = $3;
1826145840Smlaier			hfsc_opts.upperlimit.d = $5;
1827145840Smlaier			hfsc_opts.upperlimit.m2 = $7;
1828126353Smlaier			hfsc_opts.upperlimit.used = 1;
1829126353Smlaier		}
1830126353Smlaier		| STRING	{
1831126353Smlaier			if (!strcmp($1, "default"))
1832126353Smlaier				hfsc_opts.flags |= HFCF_DEFAULTCLASS;
1833126353Smlaier			else if (!strcmp($1, "red"))
1834126353Smlaier				hfsc_opts.flags |= HFCF_RED;
1835126353Smlaier			else if (!strcmp($1, "ecn"))
1836126353Smlaier				hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
1837126353Smlaier			else if (!strcmp($1, "rio"))
1838126353Smlaier				hfsc_opts.flags |= HFCF_RIO;
1839298133Sloos			else if (!strcmp($1, "codel"))
1840298133Sloos				hfsc_opts.flags |= HFCF_CODEL;
1841126353Smlaier			else {
1842126353Smlaier				yyerror("unknown hfsc flag \"%s\"", $1);
1843130617Smlaier				free($1);
1844126353Smlaier				YYERROR;
1845126353Smlaier			}
1846130617Smlaier			free($1);
1847126353Smlaier		}
1848126353Smlaier		;
1849126353Smlaier
1850298091Sloosfairq_opts	:	{
1851298091Sloos				bzero(&fairq_opts,
1852298091Sloos				    sizeof(struct node_fairq_opts));
1853298091Sloos			}
1854298091Sloos		    fairqopts_list				{
1855298091Sloos			$$ = fairq_opts;
1856298091Sloos		}
1857298091Sloos		;
1858298091Sloos
1859298091Sloosfairqopts_list	: fairqopts_item
1860298091Sloos		| fairqopts_list comma fairqopts_item
1861298091Sloos		;
1862298091Sloos
1863298091Sloosfairqopts_item	: LINKSHARE bandwidth				{
1864298091Sloos			if (fairq_opts.linkshare.used) {
1865298091Sloos				yyerror("linkshare already specified");
1866298091Sloos				YYERROR;
1867298091Sloos			}
1868298091Sloos			fairq_opts.linkshare.m2 = $2;
1869298091Sloos			fairq_opts.linkshare.used = 1;
1870298091Sloos		}
1871298091Sloos		| LINKSHARE '(' bandwidth number bandwidth ')'	{
1872298091Sloos			if (fairq_opts.linkshare.used) {
1873298091Sloos				yyerror("linkshare already specified");
1874298091Sloos				YYERROR;
1875298091Sloos			}
1876298091Sloos			fairq_opts.linkshare.m1 = $3;
1877298091Sloos			fairq_opts.linkshare.d = $4;
1878298091Sloos			fairq_opts.linkshare.m2 = $5;
1879298091Sloos			fairq_opts.linkshare.used = 1;
1880298091Sloos		}
1881298091Sloos		| HOGS bandwidth {
1882298091Sloos			fairq_opts.hogs_bw = $2;
1883298091Sloos		}
1884298091Sloos		| BUCKETS number {
1885298091Sloos			fairq_opts.nbuckets = $2;
1886298091Sloos		}
1887298091Sloos		| STRING	{
1888298091Sloos			if (!strcmp($1, "default"))
1889298091Sloos				fairq_opts.flags |= FARF_DEFAULTCLASS;
1890298091Sloos			else if (!strcmp($1, "red"))
1891298091Sloos				fairq_opts.flags |= FARF_RED;
1892298091Sloos			else if (!strcmp($1, "ecn"))
1893298091Sloos				fairq_opts.flags |= FARF_RED|FARF_ECN;
1894298091Sloos			else if (!strcmp($1, "rio"))
1895298091Sloos				fairq_opts.flags |= FARF_RIO;
1896298133Sloos			else if (!strcmp($1, "codel"))
1897298133Sloos				fairq_opts.flags |= FARF_CODEL;
1898298091Sloos			else {
1899298091Sloos				yyerror("unknown fairq flag \"%s\"", $1);
1900298091Sloos				free($1);
1901298091Sloos				YYERROR;
1902298091Sloos			}
1903298091Sloos			free($1);
1904298091Sloos		}
1905298091Sloos		;
1906298091Sloos
1907298133Slooscodel_opts	:	{
1908298133Sloos				bzero(&codel_opts,
1909298133Sloos				    sizeof(struct codel_opts));
1910298133Sloos			}
1911298133Sloos		    codelopts_list				{
1912298133Sloos			$$ = codel_opts;
1913298133Sloos		}
1914298133Sloos		;
1915298133Sloos
1916298133Slooscodelopts_list	: codelopts_item
1917298133Sloos		| codelopts_list comma codelopts_item
1918298133Sloos		;
1919298133Sloos
1920298133Slooscodelopts_item	: INTERVAL number				{
1921298133Sloos			if (codel_opts.interval) {
1922298133Sloos				yyerror("interval already specified");
1923298133Sloos				YYERROR;
1924298133Sloos			}
1925298133Sloos			codel_opts.interval = $2;
1926298133Sloos		}
1927298133Sloos		| TARGET number					{
1928298133Sloos			if (codel_opts.target) {
1929298133Sloos				yyerror("target already specified");
1930298133Sloos				YYERROR;
1931298133Sloos			}
1932298133Sloos			codel_opts.target = $2;
1933298133Sloos		}
1934298133Sloos		| STRING					{
1935298133Sloos			if (!strcmp($1, "ecn"))
1936298133Sloos				codel_opts.ecn = 1;
1937298133Sloos			else {
1938298133Sloos				yyerror("unknown codel option \"%s\"", $1);
1939298133Sloos				free($1);
1940298133Sloos				YYERROR;
1941298133Sloos			}
1942298133Sloos			free($1);
1943298133Sloos		}
1944298133Sloos		;
1945298133Sloos
1946126353Smlaierqassign		: /* empty */		{ $$ = NULL; }
1947126353Smlaier		| qassign_item		{ $$ = $1; }
1948223637Sbz		| '{' optnl qassign_list '}'	{ $$ = $3; }
1949126353Smlaier		;
1950126353Smlaier
1951223637Sbzqassign_list	: qassign_item optnl		{ $$ = $1; }
1952223637Sbz		| qassign_list comma qassign_item optnl	{
1953126353Smlaier			$1->tail->next = $3;
1954126353Smlaier			$1->tail = $3;
1955126353Smlaier			$$ = $1;
1956126353Smlaier		}
1957126353Smlaier		;
1958126353Smlaier
1959126353Smlaierqassign_item	: STRING			{
1960126353Smlaier			$$ = calloc(1, sizeof(struct node_queue));
1961126353Smlaier			if ($$ == NULL)
1962126353Smlaier				err(1, "qassign_item: calloc");
1963126353Smlaier			if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
1964126353Smlaier			    sizeof($$->queue)) {
1965126353Smlaier				yyerror("queue name '%s' too long (max "
1966126353Smlaier				    "%d chars)", $1, sizeof($$->queue)-1);
1967130617Smlaier				free($1);
1968130617Smlaier				free($$);
1969126353Smlaier				YYERROR;
1970126353Smlaier			}
1971130617Smlaier			free($1);
1972126353Smlaier			$$->next = NULL;
1973126353Smlaier			$$->tail = $$;
1974126353Smlaier		}
1975126353Smlaier		;
1976126353Smlaier
1977126353Smlaierpfrule		: action dir logquick interface route af proto fromto
1978130617Smlaier		    filter_opts
1979126353Smlaier		{
1980126353Smlaier			struct pf_rule		 r;
1981126353Smlaier			struct node_state_opt	*o;
1982126353Smlaier			struct node_proto	*proto;
1983130617Smlaier			int			 srctrack = 0;
1984130617Smlaier			int			 statelock = 0;
1985171172Smlaier			int			 adaptive = 0;
1986223637Sbz			int			 defaults = 0;
1987126353Smlaier
1988126353Smlaier			if (check_rulestate(PFCTL_STATE_FILTER))
1989126353Smlaier				YYERROR;
1990126353Smlaier
1991126353Smlaier			memset(&r, 0, sizeof(r));
1992126353Smlaier
1993126353Smlaier			r.action = $1.b1;
1994126353Smlaier			switch ($1.b2) {
1995126353Smlaier			case PFRULE_RETURNRST:
1996126353Smlaier				r.rule_flag |= PFRULE_RETURNRST;
1997126353Smlaier				r.return_ttl = $1.w;
1998126353Smlaier				break;
1999126353Smlaier			case PFRULE_RETURNICMP:
2000126353Smlaier				r.rule_flag |= PFRULE_RETURNICMP;
2001126353Smlaier				r.return_icmp = $1.w;
2002126353Smlaier				r.return_icmp6 = $1.w2;
2003126353Smlaier				break;
2004126353Smlaier			case PFRULE_RETURN:
2005126353Smlaier				r.rule_flag |= PFRULE_RETURN;
2006126353Smlaier				r.return_icmp = $1.w;
2007126353Smlaier				r.return_icmp6 = $1.w2;
2008126353Smlaier				break;
2009126353Smlaier			}
2010126353Smlaier			r.direction = $2;
2011126353Smlaier			r.log = $3.log;
2012171172Smlaier			r.logif = $3.logif;
2013126353Smlaier			r.quick = $3.quick;
2014145840Smlaier			r.prob = $9.prob;
2015171172Smlaier			r.rtableid = $9.rtableid;
2016126353Smlaier
2017126353Smlaier			r.af = $6;
2018126353Smlaier			if ($9.tag)
2019126353Smlaier				if (strlcpy(r.tagname, $9.tag,
2020130617Smlaier				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
2021126353Smlaier					yyerror("tag too long, max %u chars",
2022126353Smlaier					    PF_TAG_NAME_SIZE - 1);
2023126353Smlaier					YYERROR;
2024126353Smlaier				}
2025126353Smlaier			if ($9.match_tag)
2026126353Smlaier				if (strlcpy(r.match_tagname, $9.match_tag,
2027130617Smlaier				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
2028126353Smlaier					yyerror("tag too long, max %u chars",
2029126353Smlaier					    PF_TAG_NAME_SIZE - 1);
2030126353Smlaier					YYERROR;
2031126353Smlaier				}
2032126353Smlaier			r.match_tag_not = $9.match_tag_not;
2033171172Smlaier			if (rule_label(&r, $9.label))
2034171172Smlaier				YYERROR;
2035171172Smlaier			free($9.label);
2036126353Smlaier			r.flags = $9.flags.b1;
2037126353Smlaier			r.flagset = $9.flags.b2;
2038171172Smlaier			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
2039171172Smlaier				yyerror("flags always false");
2040126353Smlaier				YYERROR;
2041171172Smlaier			}
2042126353Smlaier			if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
2043126353Smlaier				for (proto = $7; proto != NULL &&
2044126353Smlaier				    proto->proto != IPPROTO_TCP;
2045126353Smlaier				    proto = proto->next)
2046126353Smlaier					;	/* nothing */
2047126353Smlaier				if (proto == NULL && $7 != NULL) {
2048126353Smlaier					if ($9.flags.b1 || $9.flags.b2)
2049126353Smlaier						yyerror(
2050126353Smlaier						    "flags only apply to tcp");
2051126353Smlaier					if ($8.src_os)
2052126353Smlaier						yyerror(
2053126353Smlaier						    "OS fingerprinting only "
2054126353Smlaier						    "apply to tcp");
2055126353Smlaier					YYERROR;
2056126353Smlaier				}
2057126353Smlaier#if 0
2058126353Smlaier				if (($9.flags.b1 & parse_flags("S")) == 0 &&
2059126353Smlaier				    $8.src_os) {
2060126353Smlaier					yyerror("OS fingerprinting requires "
2061130617Smlaier					    "the SYN TCP flag (flags S/SA)");
2062126353Smlaier					YYERROR;
2063126353Smlaier				}
2064126353Smlaier#endif
2065126353Smlaier			}
2066126353Smlaier
2067126353Smlaier			r.tos = $9.tos;
2068126353Smlaier			r.keep_state = $9.keep.action;
2069223637Sbz			o = $9.keep.options;
2070171172Smlaier
2071171172Smlaier			/* 'keep state' by default on pass rules. */
2072171172Smlaier			if (!r.keep_state && !r.action &&
2073223637Sbz			    !($9.marker & FOM_KEEP)) {
2074171172Smlaier				r.keep_state = PF_STATE_NORMAL;
2075223637Sbz				o = keep_state_defaults;
2076223637Sbz				defaults = 1;
2077223637Sbz			}
2078171172Smlaier
2079126353Smlaier			while (o) {
2080126353Smlaier				struct node_state_opt	*p = o;
2081126353Smlaier
2082126353Smlaier				switch (o->type) {
2083126353Smlaier				case PF_STATE_OPT_MAX:
2084126353Smlaier					if (r.max_states) {
2085126353Smlaier						yyerror("state option 'max' "
2086126353Smlaier						    "multiple definitions");
2087126353Smlaier						YYERROR;
2088126353Smlaier					}
2089126353Smlaier					r.max_states = o->data.max_states;
2090126353Smlaier					break;
2091130617Smlaier				case PF_STATE_OPT_NOSYNC:
2092130617Smlaier					if (r.rule_flag & PFRULE_NOSYNC) {
2093130617Smlaier						yyerror("state option 'sync' "
2094130617Smlaier						    "multiple definitions");
2095130617Smlaier						YYERROR;
2096130617Smlaier					}
2097130617Smlaier					r.rule_flag |= PFRULE_NOSYNC;
2098130617Smlaier					break;
2099130617Smlaier				case PF_STATE_OPT_SRCTRACK:
2100130617Smlaier					if (srctrack) {
2101130617Smlaier						yyerror("state option "
2102130617Smlaier						    "'source-track' "
2103130617Smlaier						    "multiple definitions");
2104130617Smlaier						YYERROR;
2105130617Smlaier					}
2106130617Smlaier					srctrack =  o->data.src_track;
2107145840Smlaier					r.rule_flag |= PFRULE_SRCTRACK;
2108130617Smlaier					break;
2109130617Smlaier				case PF_STATE_OPT_MAX_SRC_STATES:
2110130617Smlaier					if (r.max_src_states) {
2111130617Smlaier						yyerror("state option "
2112130617Smlaier						    "'max-src-states' "
2113130617Smlaier						    "multiple definitions");
2114130617Smlaier						YYERROR;
2115130617Smlaier					}
2116145840Smlaier					if (o->data.max_src_states == 0) {
2117130617Smlaier						yyerror("'max-src-states' must "
2118130617Smlaier						    "be > 0");
2119130617Smlaier						YYERROR;
2120130617Smlaier					}
2121130617Smlaier					r.max_src_states =
2122130617Smlaier					    o->data.max_src_states;
2123130617Smlaier					r.rule_flag |= PFRULE_SRCTRACK;
2124130617Smlaier					break;
2125145840Smlaier				case PF_STATE_OPT_OVERLOAD:
2126145840Smlaier					if (r.overload_tblname[0]) {
2127145840Smlaier						yyerror("multiple 'overload' "
2128145840Smlaier						    "table definitions");
2129145840Smlaier						YYERROR;
2130145840Smlaier					}
2131145840Smlaier					if (strlcpy(r.overload_tblname,
2132145840Smlaier					    o->data.overload.tblname,
2133145840Smlaier					    PF_TABLE_NAME_SIZE) >=
2134145840Smlaier					    PF_TABLE_NAME_SIZE) {
2135145840Smlaier						yyerror("state option: "
2136145840Smlaier						    "strlcpy");
2137145840Smlaier						YYERROR;
2138145840Smlaier					}
2139145840Smlaier					r.flush = o->data.overload.flush;
2140145840Smlaier					break;
2141145840Smlaier				case PF_STATE_OPT_MAX_SRC_CONN:
2142145840Smlaier					if (r.max_src_conn) {
2143145840Smlaier						yyerror("state option "
2144145840Smlaier						    "'max-src-conn' "
2145145840Smlaier						    "multiple definitions");
2146145840Smlaier						YYERROR;
2147145840Smlaier					}
2148145840Smlaier					if (o->data.max_src_conn == 0) {
2149145840Smlaier						yyerror("'max-src-conn' "
2150145840Smlaier						    "must be > 0");
2151145840Smlaier						YYERROR;
2152145840Smlaier					}
2153145840Smlaier					r.max_src_conn =
2154145840Smlaier					    o->data.max_src_conn;
2155145840Smlaier					r.rule_flag |= PFRULE_SRCTRACK |
2156145840Smlaier					    PFRULE_RULESRCTRACK;
2157145840Smlaier					break;
2158145840Smlaier				case PF_STATE_OPT_MAX_SRC_CONN_RATE:
2159145840Smlaier					if (r.max_src_conn_rate.limit) {
2160145840Smlaier						yyerror("state option "
2161145840Smlaier						    "'max-src-conn-rate' "
2162145840Smlaier						    "multiple definitions");
2163145840Smlaier						YYERROR;
2164145840Smlaier					}
2165145840Smlaier					if (!o->data.max_src_conn_rate.limit ||
2166145840Smlaier					    !o->data.max_src_conn_rate.seconds) {
2167145840Smlaier						yyerror("'max-src-conn-rate' "
2168145840Smlaier						    "values must be > 0");
2169145840Smlaier						YYERROR;
2170145840Smlaier					}
2171145840Smlaier					if (o->data.max_src_conn_rate.limit >
2172145840Smlaier					    PF_THRESHOLD_MAX) {
2173145840Smlaier						yyerror("'max-src-conn-rate' "
2174171172Smlaier						    "maximum rate must be < %u",
2175171172Smlaier						    PF_THRESHOLD_MAX);
2176145840Smlaier						YYERROR;
2177145840Smlaier					}
2178145840Smlaier					r.max_src_conn_rate.limit =
2179145840Smlaier					    o->data.max_src_conn_rate.limit;
2180145840Smlaier					r.max_src_conn_rate.seconds =
2181145840Smlaier					    o->data.max_src_conn_rate.seconds;
2182145840Smlaier					r.rule_flag |= PFRULE_SRCTRACK |
2183145840Smlaier					    PFRULE_RULESRCTRACK;
2184145840Smlaier					break;
2185130617Smlaier				case PF_STATE_OPT_MAX_SRC_NODES:
2186130617Smlaier					if (r.max_src_nodes) {
2187130617Smlaier						yyerror("state option "
2188130617Smlaier						    "'max-src-nodes' "
2189130617Smlaier						    "multiple definitions");
2190130617Smlaier						YYERROR;
2191130617Smlaier					}
2192130617Smlaier					if (o->data.max_src_nodes == 0) {
2193130617Smlaier						yyerror("'max-src-nodes' must "
2194130617Smlaier						    "be > 0");
2195130617Smlaier						YYERROR;
2196130617Smlaier					}
2197130617Smlaier					r.max_src_nodes =
2198130617Smlaier					    o->data.max_src_nodes;
2199130617Smlaier					r.rule_flag |= PFRULE_SRCTRACK |
2200130617Smlaier					    PFRULE_RULESRCTRACK;
2201130617Smlaier					break;
2202130617Smlaier				case PF_STATE_OPT_STATELOCK:
2203130617Smlaier					if (statelock) {
2204130617Smlaier						yyerror("state locking option: "
2205130617Smlaier						    "multiple definitions");
2206130617Smlaier						YYERROR;
2207130617Smlaier					}
2208130617Smlaier					statelock = 1;
2209130617Smlaier					r.rule_flag |= o->data.statelock;
2210130617Smlaier					break;
2211200930Sdelphij				case PF_STATE_OPT_SLOPPY:
2212200930Sdelphij					if (r.rule_flag & PFRULE_STATESLOPPY) {
2213200930Sdelphij						yyerror("state sloppy option: "
2214200930Sdelphij						    "multiple definitions");
2215200930Sdelphij						YYERROR;
2216200930Sdelphij					}
2217200930Sdelphij					r.rule_flag |= PFRULE_STATESLOPPY;
2218200930Sdelphij					break;
2219126353Smlaier				case PF_STATE_OPT_TIMEOUT:
2220171172Smlaier					if (o->data.timeout.number ==
2221171172Smlaier					    PFTM_ADAPTIVE_START ||
2222171172Smlaier					    o->data.timeout.number ==
2223171172Smlaier					    PFTM_ADAPTIVE_END)
2224171172Smlaier						adaptive = 1;
2225126353Smlaier					if (r.timeout[o->data.timeout.number]) {
2226126353Smlaier						yyerror("state timeout %s "
2227126353Smlaier						    "multiple definitions",
2228126353Smlaier						    pf_timeouts[o->data.
2229126353Smlaier						    timeout.number].name);
2230126353Smlaier						YYERROR;
2231126353Smlaier					}
2232126353Smlaier					r.timeout[o->data.timeout.number] =
2233126353Smlaier					    o->data.timeout.seconds;
2234126353Smlaier				}
2235126353Smlaier				o = o->next;
2236223637Sbz				if (!defaults)
2237223637Sbz					free(p);
2238126353Smlaier			}
2239171172Smlaier
2240171172Smlaier			/* 'flags S/SA' by default on stateful rules */
2241171172Smlaier			if (!r.action && !r.flags && !r.flagset &&
2242171172Smlaier			    !$9.fragment && !($9.marker & FOM_FLAGS) &&
2243171172Smlaier			    r.keep_state) {
2244171172Smlaier				r.flags = parse_flags("S");
2245171172Smlaier				r.flagset =  parse_flags("SA");
2246171172Smlaier			}
2247171172Smlaier			if (!adaptive && r.max_states) {
2248171172Smlaier				r.timeout[PFTM_ADAPTIVE_START] =
2249171172Smlaier				    (r.max_states / 10) * 6;
2250171172Smlaier				r.timeout[PFTM_ADAPTIVE_END] =
2251171172Smlaier				    (r.max_states / 10) * 12;
2252171172Smlaier			}
2253145840Smlaier			if (r.rule_flag & PFRULE_SRCTRACK) {
2254130617Smlaier				if (srctrack == PF_SRCTRACK_GLOBAL &&
2255130617Smlaier				    r.max_src_nodes) {
2256130617Smlaier					yyerror("'max-src-nodes' is "
2257130617Smlaier					    "incompatible with "
2258130617Smlaier					    "'source-track global'");
2259130617Smlaier					YYERROR;
2260130617Smlaier				}
2261145840Smlaier				if (srctrack == PF_SRCTRACK_GLOBAL &&
2262145840Smlaier				    r.max_src_conn) {
2263145840Smlaier					yyerror("'max-src-conn' is "
2264145840Smlaier					    "incompatible with "
2265145840Smlaier					    "'source-track global'");
2266145840Smlaier					YYERROR;
2267145840Smlaier				}
2268145840Smlaier				if (srctrack == PF_SRCTRACK_GLOBAL &&
2269145840Smlaier				    r.max_src_conn_rate.seconds) {
2270145840Smlaier					yyerror("'max-src-conn-rate' is "
2271145840Smlaier					    "incompatible with "
2272145840Smlaier					    "'source-track global'");
2273145840Smlaier					YYERROR;
2274145840Smlaier				}
2275145840Smlaier				if (r.timeout[PFTM_SRC_NODE] <
2276145840Smlaier				    r.max_src_conn_rate.seconds)
2277145840Smlaier					r.timeout[PFTM_SRC_NODE] =
2278145840Smlaier					    r.max_src_conn_rate.seconds;
2279130617Smlaier				r.rule_flag |= PFRULE_SRCTRACK;
2280130617Smlaier				if (srctrack == PF_SRCTRACK_RULE)
2281130617Smlaier					r.rule_flag |= PFRULE_RULESRCTRACK;
2282130617Smlaier			}
2283130617Smlaier			if (r.keep_state && !statelock)
2284130617Smlaier				r.rule_flag |= default_statelock;
2285126353Smlaier
2286126353Smlaier			if ($9.fragment)
2287126353Smlaier				r.rule_flag |= PFRULE_FRAGMENT;
2288126353Smlaier			r.allow_opts = $9.allowopts;
2289126353Smlaier
2290126353Smlaier			decide_address_family($8.src.host, &r.af);
2291126353Smlaier			decide_address_family($8.dst.host, &r.af);
2292126353Smlaier
2293126353Smlaier			if ($5.rt) {
2294126353Smlaier				if (!r.direction) {
2295126353Smlaier					yyerror("direction must be explicit "
2296126353Smlaier					    "with rules that specify routing");
2297126353Smlaier					YYERROR;
2298126353Smlaier				}
2299126353Smlaier				r.rt = $5.rt;
2300126353Smlaier				r.rpool.opts = $5.pool_opts;
2301126353Smlaier				if ($5.key != NULL)
2302126353Smlaier					memcpy(&r.rpool.key, $5.key,
2303126353Smlaier					    sizeof(struct pf_poolhashkey));
2304126353Smlaier			}
2305126353Smlaier			if (r.rt && r.rt != PF_FASTROUTE) {
2306126353Smlaier				decide_address_family($5.host, &r.af);
2307126353Smlaier				remove_invalid_hosts(&$5.host, &r.af);
2308126353Smlaier				if ($5.host == NULL) {
2309126353Smlaier					yyerror("no routing address with "
2310126353Smlaier					    "matching address family found.");
2311126353Smlaier					YYERROR;
2312126353Smlaier				}
2313130617Smlaier				if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
2314130617Smlaier				    PF_POOL_NONE && ($5.host->next != NULL ||
2315130617Smlaier				    $5.host->addr.type == PF_ADDR_TABLE ||
2316130617Smlaier				    DYNIF_MULTIADDR($5.host->addr)))
2317130617Smlaier					r.rpool.opts |= PF_POOL_ROUNDROBIN;
2318130617Smlaier				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
2319130617Smlaier				    PF_POOL_ROUNDROBIN &&
2320130617Smlaier				    disallow_table($5.host, "tables are only "
2321130617Smlaier				    "supported in round-robin routing pools"))
2322130617Smlaier					YYERROR;
2323130617Smlaier				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
2324130617Smlaier				    PF_POOL_ROUNDROBIN &&
2325130617Smlaier				    disallow_alias($5.host, "interface (%s) "
2326130617Smlaier				    "is only supported in round-robin "
2327130617Smlaier				    "routing pools"))
2328130617Smlaier					YYERROR;
2329126353Smlaier				if ($5.host->next != NULL) {
2330130617Smlaier					if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
2331126353Smlaier					    PF_POOL_ROUNDROBIN) {
2332126353Smlaier						yyerror("r.rpool.opts must "
2333126353Smlaier						    "be PF_POOL_ROUNDROBIN");
2334126353Smlaier						YYERROR;
2335126353Smlaier					}
2336126353Smlaier				}
2337126353Smlaier			}
2338126353Smlaier			if ($9.queues.qname != NULL) {
2339126353Smlaier				if (strlcpy(r.qname, $9.queues.qname,
2340126353Smlaier				    sizeof(r.qname)) >= sizeof(r.qname)) {
2341126353Smlaier					yyerror("rule qname too long (max "
2342126353Smlaier					    "%d chars)", sizeof(r.qname)-1);
2343126353Smlaier					YYERROR;
2344126353Smlaier				}
2345126353Smlaier				free($9.queues.qname);
2346126353Smlaier			}
2347126353Smlaier			if ($9.queues.pqname != NULL) {
2348126353Smlaier				if (strlcpy(r.pqname, $9.queues.pqname,
2349126353Smlaier				    sizeof(r.pqname)) >= sizeof(r.pqname)) {
2350126353Smlaier					yyerror("rule pqname too long (max "
2351126353Smlaier					    "%d chars)", sizeof(r.pqname)-1);
2352126353Smlaier					YYERROR;
2353126353Smlaier				}
2354126353Smlaier				free($9.queues.pqname);
2355126353Smlaier			}
2356223637Sbz#ifdef __FreeBSD__
2357223637Sbz			r.divert.port = $9.divert.port;
2358223637Sbz#else
2359223637Sbz			if ((r.divert.port = $9.divert.port)) {
2360223637Sbz				if (r.direction == PF_OUT) {
2361223637Sbz					if ($9.divert.addr) {
2362223637Sbz						yyerror("address specified "
2363223637Sbz						    "for outgoing divert");
2364223637Sbz						YYERROR;
2365223637Sbz					}
2366223637Sbz					bzero(&r.divert.addr,
2367223637Sbz					    sizeof(r.divert.addr));
2368223637Sbz				} else {
2369223637Sbz					if (!$9.divert.addr) {
2370223637Sbz						yyerror("no address specified "
2371223637Sbz						    "for incoming divert");
2372223637Sbz						YYERROR;
2373223637Sbz					}
2374223637Sbz					if ($9.divert.addr->af != r.af) {
2375223637Sbz						yyerror("address family "
2376223637Sbz						    "mismatch for divert");
2377223637Sbz						YYERROR;
2378223637Sbz					}
2379223637Sbz					r.divert.addr =
2380223637Sbz					    $9.divert.addr->addr.v.a.addr;
2381223637Sbz				}
2382223637Sbz			}
2383223637Sbz#endif
2384126353Smlaier
2385126353Smlaier			expand_rule(&r, $4, $5.host, $7, $8.src_os,
2386126353Smlaier			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
2387145840Smlaier			    $9.uid, $9.gid, $9.icmpspec, "");
2388126353Smlaier		}
2389126353Smlaier		;
2390126353Smlaier
2391171172Smlaierfilter_opts	:	{
2392171172Smlaier				bzero(&filter_opts, sizeof filter_opts);
2393171172Smlaier				filter_opts.rtableid = -1;
2394171172Smlaier			}
2395130617Smlaier		    filter_opts_l
2396126353Smlaier			{ $$ = filter_opts; }
2397126353Smlaier		| /* empty */	{
2398126353Smlaier			bzero(&filter_opts, sizeof filter_opts);
2399171172Smlaier			filter_opts.rtableid = -1;
2400126353Smlaier			$$ = filter_opts;
2401126353Smlaier		}
2402126353Smlaier		;
2403126353Smlaier
2404126353Smlaierfilter_opts_l	: filter_opts_l filter_opt
2405126353Smlaier		| filter_opt
2406126353Smlaier		;
2407126353Smlaier
2408126353Smlaierfilter_opt	: USER uids {
2409126353Smlaier			if (filter_opts.uid)
2410126353Smlaier				$2->tail->next = filter_opts.uid;
2411126353Smlaier			filter_opts.uid = $2;
2412126353Smlaier		}
2413126353Smlaier		| GROUP gids {
2414126353Smlaier			if (filter_opts.gid)
2415126353Smlaier				$2->tail->next = filter_opts.gid;
2416126353Smlaier			filter_opts.gid = $2;
2417126353Smlaier		}
2418126353Smlaier		| flags {
2419126353Smlaier			if (filter_opts.marker & FOM_FLAGS) {
2420126353Smlaier				yyerror("flags cannot be redefined");
2421126353Smlaier				YYERROR;
2422126353Smlaier			}
2423126353Smlaier			filter_opts.marker |= FOM_FLAGS;
2424126353Smlaier			filter_opts.flags.b1 |= $1.b1;
2425126353Smlaier			filter_opts.flags.b2 |= $1.b2;
2426126353Smlaier			filter_opts.flags.w |= $1.w;
2427126353Smlaier			filter_opts.flags.w2 |= $1.w2;
2428126353Smlaier		}
2429126353Smlaier		| icmpspec {
2430126353Smlaier			if (filter_opts.marker & FOM_ICMP) {
2431126353Smlaier				yyerror("icmp-type cannot be redefined");
2432126353Smlaier				YYERROR;
2433126353Smlaier			}
2434126353Smlaier			filter_opts.marker |= FOM_ICMP;
2435126353Smlaier			filter_opts.icmpspec = $1;
2436126353Smlaier		}
2437223637Sbz		| TOS tos {
2438126353Smlaier			if (filter_opts.marker & FOM_TOS) {
2439126353Smlaier				yyerror("tos cannot be redefined");
2440126353Smlaier				YYERROR;
2441126353Smlaier			}
2442126353Smlaier			filter_opts.marker |= FOM_TOS;
2443223637Sbz			filter_opts.tos = $2;
2444126353Smlaier		}
2445126353Smlaier		| keep {
2446126353Smlaier			if (filter_opts.marker & FOM_KEEP) {
2447126353Smlaier				yyerror("modulate or keep cannot be redefined");
2448126353Smlaier				YYERROR;
2449126353Smlaier			}
2450126353Smlaier			filter_opts.marker |= FOM_KEEP;
2451126353Smlaier			filter_opts.keep.action = $1.action;
2452126353Smlaier			filter_opts.keep.options = $1.options;
2453126353Smlaier		}
2454126353Smlaier		| FRAGMENT {
2455126353Smlaier			filter_opts.fragment = 1;
2456126353Smlaier		}
2457126353Smlaier		| ALLOWOPTS {
2458126353Smlaier			filter_opts.allowopts = 1;
2459126353Smlaier		}
2460126353Smlaier		| label	{
2461126353Smlaier			if (filter_opts.label) {
2462126353Smlaier				yyerror("label cannot be redefined");
2463126353Smlaier				YYERROR;
2464126353Smlaier			}
2465126353Smlaier			filter_opts.label = $1;
2466126353Smlaier		}
2467126353Smlaier		| qname	{
2468126353Smlaier			if (filter_opts.queues.qname) {
2469126353Smlaier				yyerror("queue cannot be redefined");
2470126353Smlaier				YYERROR;
2471126353Smlaier			}
2472126353Smlaier			filter_opts.queues = $1;
2473126353Smlaier		}
2474126353Smlaier		| TAG string				{
2475126353Smlaier			filter_opts.tag = $2;
2476126353Smlaier		}
2477126353Smlaier		| not TAGGED string			{
2478126353Smlaier			filter_opts.match_tag = $3;
2479126353Smlaier			filter_opts.match_tag_not = $1;
2480126353Smlaier		}
2481223637Sbz		| PROBABILITY probability		{
2482223637Sbz			double	p;
2483145840Smlaier
2484223637Sbz			p = floor($2 * UINT_MAX + 0.5);
2485223637Sbz			if (p < 0.0 || p > UINT_MAX) {
2486223637Sbz				yyerror("invalid probability: %lf", p);
2487223637Sbz				YYERROR;
2488145840Smlaier			}
2489223637Sbz			filter_opts.prob = (u_int32_t)p;
2490223637Sbz			if (filter_opts.prob == 0)
2491223637Sbz				filter_opts.prob = 1;
2492223637Sbz		}
2493223637Sbz		| RTABLE NUMBER				{
2494231852Sbz			if ($2 < 0 || $2 > rt_tableid_max()) {
2495223637Sbz				yyerror("invalid rtable id");
2496145840Smlaier				YYERROR;
2497145840Smlaier			}
2498223637Sbz			filter_opts.rtableid = $2;
2499223637Sbz		}
2500223637Sbz		| DIVERTTO portplain {
2501223637Sbz#ifdef __FreeBSD__
2502223637Sbz			filter_opts.divert.port = $2.a;
2503223637Sbz			if (!filter_opts.divert.port) {
2504223637Sbz				yyerror("invalid divert port: %u", ntohs($2.a));
2505145840Smlaier				YYERROR;
2506145840Smlaier			}
2507223637Sbz#endif
2508145840Smlaier		}
2509223637Sbz		| DIVERTTO STRING PORT portplain {
2510178894Sjulian#ifndef __FreeBSD__
2511223637Sbz			if ((filter_opts.divert.addr = host($2)) == NULL) {
2512223637Sbz				yyerror("could not parse divert address: %s",
2513223637Sbz				    $2);
2514223637Sbz				free($2);
2515171172Smlaier				YYERROR;
2516171172Smlaier			}
2517223637Sbz#else
2518223637Sbz			if ($2)
2519178894Sjulian#endif
2520223637Sbz			free($2);
2521223637Sbz			filter_opts.divert.port = $4.a;
2522223637Sbz			if (!filter_opts.divert.port) {
2523223637Sbz				yyerror("invalid divert port: %u", ntohs($4.a));
2524223637Sbz				YYERROR;
2525223637Sbz			}
2526171172Smlaier		}
2527223637Sbz		| DIVERTREPLY {
2528223637Sbz#ifdef __FreeBSD__
2529223637Sbz			yyerror("divert-reply has no meaning in FreeBSD pf(4)");
2530223637Sbz			YYERROR;
2531223637Sbz#else
2532223637Sbz			filter_opts.divert.port = 1;	/* some random value */
2533223637Sbz#endif
2534223637Sbz		}
2535126353Smlaier		;
2536126353Smlaier
2537223637Sbzprobability	: STRING				{
2538223637Sbz			char	*e;
2539223637Sbz			double	 p = strtod($1, &e);
2540223637Sbz
2541223637Sbz			if (*e == '%') {
2542223637Sbz				p *= 0.01;
2543223637Sbz				e++;
2544223637Sbz			}
2545223637Sbz			if (*e) {
2546223637Sbz				yyerror("invalid probability: %s", $1);
2547223637Sbz				free($1);
2548223637Sbz				YYERROR;
2549223637Sbz			}
2550223637Sbz			free($1);
2551223637Sbz			$$ = p;
2552223637Sbz		}
2553223637Sbz		| NUMBER				{
2554223637Sbz			$$ = (double)$1;
2555223637Sbz		}
2556223637Sbz		;
2557223637Sbz
2558223637Sbz
2559126353Smlaieraction		: PASS			{ $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
2560126353Smlaier		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
2561126353Smlaier		;
2562126353Smlaier
2563126353Smlaierblockspec	: /* empty */		{
2564126353Smlaier			$$.b2 = blockpolicy;
2565126353Smlaier			$$.w = returnicmpdefault;
2566126353Smlaier			$$.w2 = returnicmp6default;
2567126353Smlaier		}
2568126353Smlaier		| DROP			{
2569126353Smlaier			$$.b2 = PFRULE_DROP;
2570126353Smlaier			$$.w = 0;
2571126353Smlaier			$$.w2 = 0;
2572126353Smlaier		}
2573126353Smlaier		| RETURNRST		{
2574126353Smlaier			$$.b2 = PFRULE_RETURNRST;
2575126353Smlaier			$$.w = 0;
2576126353Smlaier			$$.w2 = 0;
2577126353Smlaier		}
2578223637Sbz		| RETURNRST '(' TTL NUMBER ')'	{
2579223637Sbz			if ($4 < 0 || $4 > 255) {
2580126353Smlaier				yyerror("illegal ttl value %d", $4);
2581126353Smlaier				YYERROR;
2582126353Smlaier			}
2583126353Smlaier			$$.b2 = PFRULE_RETURNRST;
2584126353Smlaier			$$.w = $4;
2585126353Smlaier			$$.w2 = 0;
2586126353Smlaier		}
2587126353Smlaier		| RETURNICMP		{
2588126353Smlaier			$$.b2 = PFRULE_RETURNICMP;
2589126353Smlaier			$$.w = returnicmpdefault;
2590126353Smlaier			$$.w2 = returnicmp6default;
2591126353Smlaier		}
2592126353Smlaier		| RETURNICMP6		{
2593126353Smlaier			$$.b2 = PFRULE_RETURNICMP;
2594126353Smlaier			$$.w = returnicmpdefault;
2595126353Smlaier			$$.w2 = returnicmp6default;
2596126353Smlaier		}
2597223637Sbz		| RETURNICMP '(' reticmpspec ')'	{
2598126353Smlaier			$$.b2 = PFRULE_RETURNICMP;
2599223637Sbz			$$.w = $3;
2600223637Sbz			$$.w2 = returnicmpdefault;
2601126353Smlaier		}
2602223637Sbz		| RETURNICMP6 '(' reticmp6spec ')'	{
2603126353Smlaier			$$.b2 = PFRULE_RETURNICMP;
2604126353Smlaier			$$.w = returnicmpdefault;
2605223637Sbz			$$.w2 = $3;
2606126353Smlaier		}
2607223637Sbz		| RETURNICMP '(' reticmpspec comma reticmp6spec ')' {
2608126353Smlaier			$$.b2 = PFRULE_RETURNICMP;
2609223637Sbz			$$.w = $3;
2610223637Sbz			$$.w2 = $5;
2611126353Smlaier		}
2612126353Smlaier		| RETURN {
2613126353Smlaier			$$.b2 = PFRULE_RETURN;
2614126353Smlaier			$$.w = returnicmpdefault;
2615126353Smlaier			$$.w2 = returnicmp6default;
2616126353Smlaier		}
2617126353Smlaier		;
2618126353Smlaier
2619223637Sbzreticmpspec	: STRING			{
2620223637Sbz			if (!($$ = parseicmpspec($1, AF_INET))) {
2621223637Sbz				free($1);
2622223637Sbz				YYERROR;
2623223637Sbz			}
2624223637Sbz			free($1);
2625223637Sbz		}
2626223637Sbz		| NUMBER			{
2627223637Sbz			u_int8_t		icmptype;
2628223637Sbz
2629223637Sbz			if ($1 < 0 || $1 > 255) {
2630223637Sbz				yyerror("invalid icmp code %lu", $1);
2631223637Sbz				YYERROR;
2632223637Sbz			}
2633223637Sbz			icmptype = returnicmpdefault >> 8;
2634223637Sbz			$$ = (icmptype << 8 | $1);
2635223637Sbz		}
2636223637Sbz		;
2637223637Sbz
2638223637Sbzreticmp6spec	: STRING			{
2639223637Sbz			if (!($$ = parseicmpspec($1, AF_INET6))) {
2640223637Sbz				free($1);
2641223637Sbz				YYERROR;
2642223637Sbz			}
2643223637Sbz			free($1);
2644223637Sbz		}
2645223637Sbz		| NUMBER			{
2646223637Sbz			u_int8_t		icmptype;
2647223637Sbz
2648223637Sbz			if ($1 < 0 || $1 > 255) {
2649223637Sbz				yyerror("invalid icmp code %lu", $1);
2650223637Sbz				YYERROR;
2651223637Sbz			}
2652223637Sbz			icmptype = returnicmp6default >> 8;
2653223637Sbz			$$ = (icmptype << 8 | $1);
2654223637Sbz		}
2655223637Sbz		;
2656223637Sbz
2657223637Sbzdir		: /* empty */			{ $$ = PF_INOUT; }
2658126353Smlaier		| IN				{ $$ = PF_IN; }
2659126353Smlaier		| OUT				{ $$ = PF_OUT; }
2660126353Smlaier		;
2661126353Smlaier
2662171172Smlaierquick		: /* empty */			{ $$.quick = 0; }
2663171172Smlaier		| QUICK				{ $$.quick = 1; }
2664126353Smlaier		;
2665126353Smlaier
2666171172Smlaierlogquick	: /* empty */	{ $$.log = 0; $$.quick = 0; $$.logif = 0; }
2667171172Smlaier		| log		{ $$ = $1; $$.quick = 0; }
2668171172Smlaier		| QUICK		{ $$.quick = 1; $$.log = 0; $$.logif = 0; }
2669171172Smlaier		| log QUICK	{ $$ = $1; $$.quick = 1; }
2670171172Smlaier		| QUICK log	{ $$ = $2; $$.quick = 1; }
2671126353Smlaier		;
2672126353Smlaier
2673171172Smlaierlog		: LOG			{ $$.log = PF_LOG; $$.logif = 0; }
2674171172Smlaier		| LOG '(' logopts ')'	{
2675171172Smlaier			$$.log = PF_LOG | $3.log;
2676171172Smlaier			$$.logif = $3.logif;
2677171172Smlaier		}
2678171172Smlaier		;
2679171172Smlaier
2680171172Smlaierlogopts		: logopt			{ $$ = $1; }
2681171172Smlaier		| logopts comma logopt		{
2682171172Smlaier			$$.log = $1.log | $3.log;
2683171172Smlaier			$$.logif = $3.logif;
2684171172Smlaier			if ($$.logif == 0)
2685171172Smlaier				$$.logif = $1.logif;
2686171172Smlaier		}
2687171172Smlaier		;
2688171172Smlaier
2689171172Smlaierlogopt		: ALL		{ $$.log = PF_LOG_ALL; $$.logif = 0; }
2690171172Smlaier		| USER		{ $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
2691171172Smlaier		| GROUP		{ $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
2692171172Smlaier		| TO string	{
2693171172Smlaier			const char	*errstr;
2694171172Smlaier			u_int		 i;
2695171172Smlaier
2696171172Smlaier			$$.log = 0;
2697171172Smlaier			if (strncmp($2, "pflog", 5)) {
2698171172Smlaier				yyerror("%s: should be a pflog interface", $2);
2699171172Smlaier				free($2);
2700171172Smlaier				YYERROR;
2701171172Smlaier			}
2702171172Smlaier			i = strtonum($2 + 5, 0, 255, &errstr);
2703171172Smlaier			if (errstr) {
2704171172Smlaier				yyerror("%s: %s", $2, errstr);
2705171172Smlaier				free($2);
2706171172Smlaier				YYERROR;
2707171172Smlaier			}
2708171172Smlaier			free($2);
2709171172Smlaier			$$.logif = i;
2710171172Smlaier		}
2711171172Smlaier		;
2712171172Smlaier
2713126353Smlaierinterface	: /* empty */			{ $$ = NULL; }
2714126353Smlaier		| ON if_item_not		{ $$ = $2; }
2715223637Sbz		| ON '{' optnl if_list '}'	{ $$ = $4; }
2716126353Smlaier		;
2717126353Smlaier
2718223637Sbzif_list		: if_item_not optnl		{ $$ = $1; }
2719223637Sbz		| if_list comma if_item_not optnl	{
2720126353Smlaier			$1->tail->next = $3;
2721126353Smlaier			$1->tail = $3;
2722126353Smlaier			$$ = $1;
2723126353Smlaier		}
2724126353Smlaier		;
2725126353Smlaier
2726126353Smlaierif_item_not	: not if_item			{ $$ = $2; $$->not = $1; }
2727126353Smlaier		;
2728126353Smlaier
2729126353Smlaierif_item		: STRING			{
2730126353Smlaier			struct node_host	*n;
2731126353Smlaier
2732126353Smlaier			$$ = calloc(1, sizeof(struct node_if));
2733126353Smlaier			if ($$ == NULL)
2734126353Smlaier				err(1, "if_item: calloc");
2735126353Smlaier			if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
2736126353Smlaier			    sizeof($$->ifname)) {
2737130617Smlaier				free($1);
2738126353Smlaier				free($$);
2739126353Smlaier				yyerror("interface name too long");
2740126353Smlaier				YYERROR;
2741126353Smlaier			}
2742145840Smlaier
2743171172Smlaier			if ((n = ifa_exists($1)) != NULL)
2744145840Smlaier				$$->ifa_flags = n->ifa_flags;
2745145840Smlaier
2746130617Smlaier			free($1);
2747126353Smlaier			$$->not = 0;
2748126353Smlaier			$$->next = NULL;
2749126353Smlaier			$$->tail = $$;
2750126353Smlaier		}
2751126353Smlaier		;
2752126353Smlaier
2753126353Smlaieraf		: /* empty */			{ $$ = 0; }
2754126353Smlaier		| INET				{ $$ = AF_INET; }
2755126353Smlaier		| INET6				{ $$ = AF_INET6; }
2756130617Smlaier		;
2757126353Smlaier
2758223637Sbzproto		: /* empty */				{ $$ = NULL; }
2759223637Sbz		| PROTO proto_item			{ $$ = $2; }
2760223637Sbz		| PROTO '{' optnl proto_list '}'	{ $$ = $4; }
2761126353Smlaier		;
2762126353Smlaier
2763223637Sbzproto_list	: proto_item optnl		{ $$ = $1; }
2764223637Sbz		| proto_list comma proto_item optnl	{
2765126353Smlaier			$1->tail->next = $3;
2766126353Smlaier			$1->tail = $3;
2767126353Smlaier			$$ = $1;
2768126353Smlaier		}
2769126353Smlaier		;
2770126353Smlaier
2771223637Sbzproto_item	: protoval			{
2772126353Smlaier			u_int8_t	pr;
2773126353Smlaier
2774223637Sbz			pr = (u_int8_t)$1;
2775126353Smlaier			if (pr == 0) {
2776126353Smlaier				yyerror("proto 0 cannot be used");
2777126353Smlaier				YYERROR;
2778126353Smlaier			}
2779126353Smlaier			$$ = calloc(1, sizeof(struct node_proto));
2780126353Smlaier			if ($$ == NULL)
2781126353Smlaier				err(1, "proto_item: calloc");
2782126353Smlaier			$$->proto = pr;
2783126353Smlaier			$$->next = NULL;
2784126353Smlaier			$$->tail = $$;
2785126353Smlaier		}
2786126353Smlaier		;
2787126353Smlaier
2788223637Sbzprotoval	: STRING			{
2789223637Sbz			struct protoent	*p;
2790223637Sbz
2791223637Sbz			p = getprotobyname($1);
2792223637Sbz			if (p == NULL) {
2793223637Sbz				yyerror("unknown protocol %s", $1);
2794223637Sbz				free($1);
2795223637Sbz				YYERROR;
2796223637Sbz			}
2797223637Sbz			$$ = p->p_proto;
2798223637Sbz			free($1);
2799223637Sbz		}
2800223637Sbz		| NUMBER			{
2801223637Sbz			if ($1 < 0 || $1 > 255) {
2802223637Sbz				yyerror("protocol outside range");
2803223637Sbz				YYERROR;
2804223637Sbz			}
2805223637Sbz		}
2806223637Sbz		;
2807223637Sbz
2808126353Smlaierfromto		: ALL				{
2809126353Smlaier			$$.src.host = NULL;
2810126353Smlaier			$$.src.port = NULL;
2811126353Smlaier			$$.dst.host = NULL;
2812126353Smlaier			$$.dst.port = NULL;
2813126353Smlaier			$$.src_os = NULL;
2814126353Smlaier		}
2815126353Smlaier		| from os to			{
2816126353Smlaier			$$.src = $1;
2817126353Smlaier			$$.src_os = $2;
2818126353Smlaier			$$.dst = $3;
2819126353Smlaier		}
2820126353Smlaier		;
2821126353Smlaier
2822126353Smlaieros		: /* empty */			{ $$ = NULL; }
2823126353Smlaier		| OS xos			{ $$ = $2; }
2824223637Sbz		| OS '{' optnl os_list '}'	{ $$ = $4; }
2825126353Smlaier		;
2826126353Smlaier
2827126353Smlaierxos		: STRING {
2828126353Smlaier			$$ = calloc(1, sizeof(struct node_os));
2829126353Smlaier			if ($$ == NULL)
2830126353Smlaier				err(1, "os: calloc");
2831126353Smlaier			$$->os = $1;
2832126353Smlaier			$$->tail = $$;
2833126353Smlaier		}
2834126353Smlaier		;
2835126353Smlaier
2836223637Sbzos_list		: xos optnl 			{ $$ = $1; }
2837223637Sbz		| os_list comma xos optnl	{
2838126353Smlaier			$1->tail->next = $3;
2839126353Smlaier			$1->tail = $3;
2840126353Smlaier			$$ = $1;
2841126353Smlaier		}
2842126353Smlaier		;
2843126353Smlaier
2844126353Smlaierfrom		: /* empty */			{
2845126353Smlaier			$$.host = NULL;
2846126353Smlaier			$$.port = NULL;
2847126353Smlaier		}
2848126353Smlaier		| FROM ipportspec		{
2849126353Smlaier			$$ = $2;
2850126353Smlaier		}
2851126353Smlaier		;
2852126353Smlaier
2853126353Smlaierto		: /* empty */			{
2854126353Smlaier			$$.host = NULL;
2855126353Smlaier			$$.port = NULL;
2856126353Smlaier		}
2857126353Smlaier		| TO ipportspec		{
2858171172Smlaier			if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
2859171172Smlaier			    "not permitted in a destination address"))
2860171172Smlaier				YYERROR;
2861126353Smlaier			$$ = $2;
2862126353Smlaier		}
2863126353Smlaier		;
2864126353Smlaier
2865126353Smlaieripportspec	: ipspec			{
2866126353Smlaier			$$.host = $1;
2867126353Smlaier			$$.port = NULL;
2868126353Smlaier		}
2869126353Smlaier		| ipspec PORT portspec		{
2870126353Smlaier			$$.host = $1;
2871126353Smlaier			$$.port = $3;
2872126353Smlaier		}
2873126353Smlaier		| PORT portspec			{
2874126353Smlaier			$$.host = NULL;
2875126353Smlaier			$$.port = $2;
2876126353Smlaier		}
2877126353Smlaier		;
2878126353Smlaier
2879223637Sbzoptnl		: '\n' optnl
2880223637Sbz		|
2881223637Sbz		;
2882223637Sbz
2883126353Smlaieripspec		: ANY				{ $$ = NULL; }
2884126353Smlaier		| xhost				{ $$ = $1; }
2885223637Sbz		| '{' optnl host_list '}'	{ $$ = $3; }
2886126353Smlaier		;
2887126353Smlaier
2888223637Sbztoipspec	: TO ipspec			{ $$ = $2; }
2889223637Sbz		| /* empty */			{ $$ = NULL; }
2890223637Sbz		;
2891223637Sbz
2892223637Sbzhost_list	: ipspec optnl			{ $$ = $1; }
2893223637Sbz		| host_list comma ipspec optnl	{
2894126353Smlaier			if ($3 == NULL)
2895126353Smlaier				$$ = $1;
2896126353Smlaier			else if ($1 == NULL)
2897126353Smlaier				$$ = $3;
2898126353Smlaier			else {
2899126353Smlaier				$1->tail->next = $3;
2900126353Smlaier				$1->tail = $3->tail;
2901126353Smlaier				$$ = $1;
2902126353Smlaier			}
2903126353Smlaier		}
2904126353Smlaier		;
2905126353Smlaier
2906126353Smlaierxhost		: not host			{
2907126353Smlaier			struct node_host	*n;
2908126353Smlaier
2909126353Smlaier			for (n = $2; n != NULL; n = n->next)
2910126353Smlaier				n->not = $1;
2911126353Smlaier			$$ = $2;
2912126353Smlaier		}
2913171172Smlaier		| not NOROUTE			{
2914126353Smlaier			$$ = calloc(1, sizeof(struct node_host));
2915126353Smlaier			if ($$ == NULL)
2916126353Smlaier				err(1, "xhost: calloc");
2917126353Smlaier			$$->addr.type = PF_ADDR_NOROUTE;
2918126353Smlaier			$$->next = NULL;
2919171172Smlaier			$$->not = $1;
2920126353Smlaier			$$->tail = $$;
2921126353Smlaier		}
2922171172Smlaier		| not URPFFAILED		{
2923171172Smlaier			$$ = calloc(1, sizeof(struct node_host));
2924171172Smlaier			if ($$ == NULL)
2925171172Smlaier				err(1, "xhost: calloc");
2926171172Smlaier			$$->addr.type = PF_ADDR_URPFFAILED;
2927171172Smlaier			$$->next = NULL;
2928171172Smlaier			$$->not = $1;
2929171172Smlaier			$$->tail = $$;
2930171172Smlaier		}
2931126353Smlaier		;
2932126353Smlaier
2933126353Smlaierhost		: STRING			{
2934126353Smlaier			if (($$ = host($1)) == NULL)	{
2935126353Smlaier				/* error. "any" is handled elsewhere */
2936130617Smlaier				free($1);
2937126353Smlaier				yyerror("could not parse host specification");
2938126353Smlaier				YYERROR;
2939126353Smlaier			}
2940130617Smlaier			free($1);
2941126353Smlaier
2942126353Smlaier		}
2943223637Sbz		| STRING '-' STRING		{
2944223637Sbz			struct node_host *b, *e;
2945223637Sbz
2946223637Sbz			if ((b = host($1)) == NULL || (e = host($3)) == NULL) {
2947223637Sbz				free($1);
2948223637Sbz				free($3);
2949223637Sbz				yyerror("could not parse host specification");
2950223637Sbz				YYERROR;
2951223637Sbz			}
2952223637Sbz			if (b->af != e->af ||
2953223637Sbz			    b->addr.type != PF_ADDR_ADDRMASK ||
2954223637Sbz			    e->addr.type != PF_ADDR_ADDRMASK ||
2955223637Sbz			    unmask(&b->addr.v.a.mask, b->af) !=
2956223637Sbz			    (b->af == AF_INET ? 32 : 128) ||
2957223637Sbz			    unmask(&e->addr.v.a.mask, e->af) !=
2958223637Sbz			    (e->af == AF_INET ? 32 : 128) ||
2959223637Sbz			    b->next != NULL || b->not ||
2960223637Sbz			    e->next != NULL || e->not) {
2961223637Sbz				free(b);
2962223637Sbz				free(e);
2963223637Sbz				free($1);
2964223637Sbz				free($3);
2965223637Sbz				yyerror("invalid address range");
2966223637Sbz				YYERROR;
2967223637Sbz			}
2968223637Sbz			memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
2969223637Sbz			    sizeof(b->addr.v.a.mask));
2970223637Sbz			b->addr.type = PF_ADDR_RANGE;
2971223637Sbz			$$ = b;
2972223637Sbz			free(e);
2973223637Sbz			free($1);
2974223637Sbz			free($3);
2975223637Sbz		}
2976223637Sbz		| STRING '/' NUMBER		{
2977126353Smlaier			char	*buf;
2978126353Smlaier
2979223637Sbz			if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1)
2980126353Smlaier				err(1, "host: asprintf");
2981130617Smlaier			free($1);
2982126353Smlaier			if (($$ = host(buf)) == NULL)	{
2983126353Smlaier				/* error. "any" is handled elsewhere */
2984126353Smlaier				free(buf);
2985126353Smlaier				yyerror("could not parse host specification");
2986126353Smlaier				YYERROR;
2987126353Smlaier			}
2988126353Smlaier			free(buf);
2989126353Smlaier		}
2990223637Sbz		| NUMBER '/' NUMBER		{
2991223637Sbz			char	*buf;
2992223637Sbz
2993223637Sbz			/* ie. for 10/8 parsing */
2994223637Sbz#ifdef __FreeBSD__
2995223637Sbz			if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1)
2996223637Sbz#else
2997223637Sbz			if (asprintf(&buf, "%lld/%lld", $1, $3) == -1)
2998223637Sbz#endif
2999223637Sbz				err(1, "host: asprintf");
3000223637Sbz			if (($$ = host(buf)) == NULL)	{
3001223637Sbz				/* error. "any" is handled elsewhere */
3002223637Sbz				free(buf);
3003223637Sbz				yyerror("could not parse host specification");
3004223637Sbz				YYERROR;
3005223637Sbz			}
3006223637Sbz			free(buf);
3007223637Sbz		}
3008126353Smlaier		| dynaddr
3009223637Sbz		| dynaddr '/' NUMBER		{
3010126353Smlaier			struct node_host	*n;
3011126353Smlaier
3012223637Sbz			if ($3 < 0 || $3 > 128) {
3013223637Sbz				yyerror("bit number too big");
3014223637Sbz				YYERROR;
3015223637Sbz			}
3016126353Smlaier			$$ = $1;
3017126353Smlaier			for (n = $1; n != NULL; n = n->next)
3018126353Smlaier				set_ipmask(n, $3);
3019126353Smlaier		}
3020126353Smlaier		| '<' STRING '>'	{
3021126353Smlaier			if (strlen($2) >= PF_TABLE_NAME_SIZE) {
3022130617Smlaier				yyerror("table name '%s' too long", $2);
3023130617Smlaier				free($2);
3024126353Smlaier				YYERROR;
3025126353Smlaier			}
3026126353Smlaier			$$ = calloc(1, sizeof(struct node_host));
3027126353Smlaier			if ($$ == NULL)
3028126353Smlaier				err(1, "host: calloc");
3029126353Smlaier			$$->addr.type = PF_ADDR_TABLE;
3030126353Smlaier			if (strlcpy($$->addr.v.tblname, $2,
3031126353Smlaier			    sizeof($$->addr.v.tblname)) >=
3032126353Smlaier			    sizeof($$->addr.v.tblname))
3033126353Smlaier				errx(1, "host: strlcpy");
3034130617Smlaier			free($2);
3035126353Smlaier			$$->next = NULL;
3036126353Smlaier			$$->tail = $$;
3037126353Smlaier		}
3038126353Smlaier		;
3039126353Smlaier
3040223637Sbznumber		: NUMBER
3041223637Sbz		| STRING		{
3042126353Smlaier			u_long	ulval;
3043126353Smlaier
3044126353Smlaier			if (atoul($1, &ulval) == -1) {
3045126353Smlaier				yyerror("%s is not a number", $1);
3046130617Smlaier				free($1);
3047126353Smlaier				YYERROR;
3048126353Smlaier			} else
3049126353Smlaier				$$ = ulval;
3050130617Smlaier			free($1);
3051126353Smlaier		}
3052126353Smlaier		;
3053126353Smlaier
3054126353Smlaierdynaddr		: '(' STRING ')'		{
3055130617Smlaier			int	 flags = 0;
3056130617Smlaier			char	*p, *op;
3057130617Smlaier
3058130617Smlaier			op = $2;
3059145840Smlaier			if (!isalpha(op[0])) {
3060145840Smlaier				yyerror("invalid interface name '%s'", op);
3061145840Smlaier				free(op);
3062145840Smlaier				YYERROR;
3063145840Smlaier			}
3064130617Smlaier			while ((p = strrchr($2, ':')) != NULL) {
3065130617Smlaier				if (!strcmp(p+1, "network"))
3066130617Smlaier					flags |= PFI_AFLAG_NETWORK;
3067130617Smlaier				else if (!strcmp(p+1, "broadcast"))
3068130617Smlaier					flags |= PFI_AFLAG_BROADCAST;
3069130617Smlaier				else if (!strcmp(p+1, "peer"))
3070130617Smlaier					flags |= PFI_AFLAG_PEER;
3071130617Smlaier				else if (!strcmp(p+1, "0"))
3072130617Smlaier					flags |= PFI_AFLAG_NOALIAS;
3073130617Smlaier				else {
3074130617Smlaier					yyerror("interface %s has bad modifier",
3075130617Smlaier					    $2);
3076130617Smlaier					free(op);
3077130617Smlaier					YYERROR;
3078130617Smlaier				}
3079130617Smlaier				*p = '\0';
3080130617Smlaier			}
3081130617Smlaier			if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
3082130617Smlaier				free(op);
3083130617Smlaier				yyerror("illegal combination of "
3084130617Smlaier				    "interface modifiers");
3085130617Smlaier				YYERROR;
3086130617Smlaier			}
3087126353Smlaier			$$ = calloc(1, sizeof(struct node_host));
3088126353Smlaier			if ($$ == NULL)
3089126353Smlaier				err(1, "address: calloc");
3090126353Smlaier			$$->af = 0;
3091126353Smlaier			set_ipmask($$, 128);
3092126353Smlaier			$$->addr.type = PF_ADDR_DYNIFTL;
3093130617Smlaier			$$->addr.iflags = flags;
3094126353Smlaier			if (strlcpy($$->addr.v.ifname, $2,
3095126353Smlaier			    sizeof($$->addr.v.ifname)) >=
3096126353Smlaier			    sizeof($$->addr.v.ifname)) {
3097130617Smlaier				free(op);
3098126353Smlaier				free($$);
3099126353Smlaier				yyerror("interface name too long");
3100126353Smlaier				YYERROR;
3101126353Smlaier			}
3102130617Smlaier			free(op);
3103126353Smlaier			$$->next = NULL;
3104126353Smlaier			$$->tail = $$;
3105126353Smlaier		}
3106126353Smlaier		;
3107126353Smlaier
3108126353Smlaierportspec	: port_item			{ $$ = $1; }
3109223637Sbz		| '{' optnl port_list '}'	{ $$ = $3; }
3110126353Smlaier		;
3111126353Smlaier
3112223637Sbzport_list	: port_item optnl		{ $$ = $1; }
3113223637Sbz		| port_list comma port_item optnl	{
3114126353Smlaier			$1->tail->next = $3;
3115126353Smlaier			$1->tail = $3;
3116126353Smlaier			$$ = $1;
3117126353Smlaier		}
3118126353Smlaier		;
3119126353Smlaier
3120223637Sbzport_item	: portrange			{
3121126353Smlaier			$$ = calloc(1, sizeof(struct node_port));
3122126353Smlaier			if ($$ == NULL)
3123126353Smlaier				err(1, "port_item: calloc");
3124126353Smlaier			$$->port[0] = $1.a;
3125126353Smlaier			$$->port[1] = $1.b;
3126126353Smlaier			if ($1.t)
3127126353Smlaier				$$->op = PF_OP_RRG;
3128126353Smlaier			else
3129126353Smlaier				$$->op = PF_OP_EQ;
3130126353Smlaier			$$->next = NULL;
3131126353Smlaier			$$->tail = $$;
3132126353Smlaier		}
3133223637Sbz		| unaryop portrange	{
3134126353Smlaier			if ($2.t) {
3135126353Smlaier				yyerror("':' cannot be used with an other "
3136126353Smlaier				    "port operator");
3137126353Smlaier				YYERROR;
3138126353Smlaier			}
3139126353Smlaier			$$ = calloc(1, sizeof(struct node_port));
3140126353Smlaier			if ($$ == NULL)
3141126353Smlaier				err(1, "port_item: calloc");
3142126353Smlaier			$$->port[0] = $2.a;
3143126353Smlaier			$$->port[1] = $2.b;
3144126353Smlaier			$$->op = $1;
3145126353Smlaier			$$->next = NULL;
3146126353Smlaier			$$->tail = $$;
3147126353Smlaier		}
3148223637Sbz		| portrange PORTBINARY portrange	{
3149126353Smlaier			if ($1.t || $3.t) {
3150126353Smlaier				yyerror("':' cannot be used with an other "
3151126353Smlaier				    "port operator");
3152126353Smlaier				YYERROR;
3153126353Smlaier			}
3154126353Smlaier			$$ = calloc(1, sizeof(struct node_port));
3155126353Smlaier			if ($$ == NULL)
3156126353Smlaier				err(1, "port_item: calloc");
3157126353Smlaier			$$->port[0] = $1.a;
3158126353Smlaier			$$->port[1] = $3.a;
3159126353Smlaier			$$->op = $2;
3160126353Smlaier			$$->next = NULL;
3161126353Smlaier			$$->tail = $$;
3162126353Smlaier		}
3163126353Smlaier		;
3164126353Smlaier
3165223637Sbzportplain	: numberstring			{
3166223637Sbz			if (parseport($1, &$$, 0) == -1) {
3167223637Sbz				free($1);
3168223637Sbz				YYERROR;
3169223637Sbz			}
3170223637Sbz			free($1);
3171223637Sbz		}
3172223637Sbz		;
3173126353Smlaier
3174223637Sbzportrange	: numberstring			{
3175223637Sbz			if (parseport($1, &$$, PPORT_RANGE) == -1) {
3176223637Sbz				free($1);
3177223637Sbz				YYERROR;
3178126353Smlaier			}
3179130617Smlaier			free($1);
3180126353Smlaier		}
3181126353Smlaier		;
3182126353Smlaier
3183126353Smlaieruids		: uid_item			{ $$ = $1; }
3184223637Sbz		| '{' optnl uid_list '}'	{ $$ = $3; }
3185126353Smlaier		;
3186126353Smlaier
3187223637Sbzuid_list	: uid_item optnl		{ $$ = $1; }
3188223637Sbz		| uid_list comma uid_item optnl	{
3189126353Smlaier			$1->tail->next = $3;
3190126353Smlaier			$1->tail = $3;
3191126353Smlaier			$$ = $1;
3192126353Smlaier		}
3193126353Smlaier		;
3194126353Smlaier
3195126353Smlaieruid_item	: uid				{
3196126353Smlaier			$$ = calloc(1, sizeof(struct node_uid));
3197126353Smlaier			if ($$ == NULL)
3198126353Smlaier				err(1, "uid_item: calloc");
3199126353Smlaier			$$->uid[0] = $1;
3200126353Smlaier			$$->uid[1] = $1;
3201126353Smlaier			$$->op = PF_OP_EQ;
3202126353Smlaier			$$->next = NULL;
3203126353Smlaier			$$->tail = $$;
3204126353Smlaier		}
3205126353Smlaier		| unaryop uid			{
3206126353Smlaier			if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
3207126353Smlaier				yyerror("user unknown requires operator = or "
3208126353Smlaier				    "!=");
3209126353Smlaier				YYERROR;
3210126353Smlaier			}
3211126353Smlaier			$$ = calloc(1, sizeof(struct node_uid));
3212126353Smlaier			if ($$ == NULL)
3213126353Smlaier				err(1, "uid_item: calloc");
3214126353Smlaier			$$->uid[0] = $2;
3215126353Smlaier			$$->uid[1] = $2;
3216126353Smlaier			$$->op = $1;
3217126353Smlaier			$$->next = NULL;
3218126353Smlaier			$$->tail = $$;
3219126353Smlaier		}
3220126353Smlaier		| uid PORTBINARY uid		{
3221126353Smlaier			if ($1 == UID_MAX || $3 == UID_MAX) {
3222126353Smlaier				yyerror("user unknown requires operator = or "
3223126353Smlaier				    "!=");
3224126353Smlaier				YYERROR;
3225126353Smlaier			}
3226126353Smlaier			$$ = calloc(1, sizeof(struct node_uid));
3227126353Smlaier			if ($$ == NULL)
3228126353Smlaier				err(1, "uid_item: calloc");
3229126353Smlaier			$$->uid[0] = $1;
3230126353Smlaier			$$->uid[1] = $3;
3231126353Smlaier			$$->op = $2;
3232126353Smlaier			$$->next = NULL;
3233126353Smlaier			$$->tail = $$;
3234126353Smlaier		}
3235126353Smlaier		;
3236126353Smlaier
3237126353Smlaieruid		: STRING			{
3238223637Sbz			if (!strcmp($1, "unknown"))
3239223637Sbz				$$ = UID_MAX;
3240223637Sbz			else {
3241223637Sbz				struct passwd	*pw;
3242126353Smlaier
3243223637Sbz				if ((pw = getpwnam($1)) == NULL) {
3244223637Sbz					yyerror("unknown user %s", $1);
3245130617Smlaier					free($1);
3246126353Smlaier					YYERROR;
3247126353Smlaier				}
3248223637Sbz				$$ = pw->pw_uid;
3249126353Smlaier			}
3250130617Smlaier			free($1);
3251126353Smlaier		}
3252223637Sbz		| NUMBER			{
3253223637Sbz			if ($1 < 0 || $1 >= UID_MAX) {
3254223637Sbz				yyerror("illegal uid value %lu", $1);
3255223637Sbz				YYERROR;
3256223637Sbz			}
3257223637Sbz			$$ = $1;
3258223637Sbz		}
3259126353Smlaier		;
3260126353Smlaier
3261126353Smlaiergids		: gid_item			{ $$ = $1; }
3262223637Sbz		| '{' optnl gid_list '}'	{ $$ = $3; }
3263126353Smlaier		;
3264126353Smlaier
3265223637Sbzgid_list	: gid_item optnl		{ $$ = $1; }
3266223637Sbz		| gid_list comma gid_item optnl	{
3267126353Smlaier			$1->tail->next = $3;
3268126353Smlaier			$1->tail = $3;
3269126353Smlaier			$$ = $1;
3270126353Smlaier		}
3271126353Smlaier		;
3272126353Smlaier
3273126353Smlaiergid_item	: gid				{
3274126353Smlaier			$$ = calloc(1, sizeof(struct node_gid));
3275126353Smlaier			if ($$ == NULL)
3276126353Smlaier				err(1, "gid_item: calloc");
3277126353Smlaier			$$->gid[0] = $1;
3278126353Smlaier			$$->gid[1] = $1;
3279126353Smlaier			$$->op = PF_OP_EQ;
3280126353Smlaier			$$->next = NULL;
3281126353Smlaier			$$->tail = $$;
3282126353Smlaier		}
3283126353Smlaier		| unaryop gid			{
3284126353Smlaier			if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
3285126353Smlaier				yyerror("group unknown requires operator = or "
3286126353Smlaier				    "!=");
3287126353Smlaier				YYERROR;
3288126353Smlaier			}
3289126353Smlaier			$$ = calloc(1, sizeof(struct node_gid));
3290126353Smlaier			if ($$ == NULL)
3291126353Smlaier				err(1, "gid_item: calloc");
3292126353Smlaier			$$->gid[0] = $2;
3293126353Smlaier			$$->gid[1] = $2;
3294126353Smlaier			$$->op = $1;
3295126353Smlaier			$$->next = NULL;
3296126353Smlaier			$$->tail = $$;
3297126353Smlaier		}
3298126353Smlaier		| gid PORTBINARY gid		{
3299126353Smlaier			if ($1 == GID_MAX || $3 == GID_MAX) {
3300126353Smlaier				yyerror("group unknown requires operator = or "
3301126353Smlaier				    "!=");
3302126353Smlaier				YYERROR;
3303126353Smlaier			}
3304126353Smlaier			$$ = calloc(1, sizeof(struct node_gid));
3305126353Smlaier			if ($$ == NULL)
3306126353Smlaier				err(1, "gid_item: calloc");
3307126353Smlaier			$$->gid[0] = $1;
3308126353Smlaier			$$->gid[1] = $3;
3309126353Smlaier			$$->op = $2;
3310126353Smlaier			$$->next = NULL;
3311126353Smlaier			$$->tail = $$;
3312126353Smlaier		}
3313126353Smlaier		;
3314126353Smlaier
3315126353Smlaiergid		: STRING			{
3316223637Sbz			if (!strcmp($1, "unknown"))
3317223637Sbz				$$ = GID_MAX;
3318223637Sbz			else {
3319223637Sbz				struct group	*grp;
3320126353Smlaier
3321223637Sbz				if ((grp = getgrnam($1)) == NULL) {
3322223637Sbz					yyerror("unknown group %s", $1);
3323130617Smlaier					free($1);
3324126353Smlaier					YYERROR;
3325126353Smlaier				}
3326223637Sbz				$$ = grp->gr_gid;
3327126353Smlaier			}
3328130617Smlaier			free($1);
3329126353Smlaier		}
3330223637Sbz		| NUMBER			{
3331223637Sbz			if ($1 < 0 || $1 >= GID_MAX) {
3332223637Sbz				yyerror("illegal gid value %lu", $1);
3333223637Sbz				YYERROR;
3334223637Sbz			}
3335223637Sbz			$$ = $1;
3336223637Sbz		}
3337126353Smlaier		;
3338126353Smlaier
3339126353Smlaierflag		: STRING			{
3340126353Smlaier			int	f;
3341126353Smlaier
3342126353Smlaier			if ((f = parse_flags($1)) < 0) {
3343126353Smlaier				yyerror("bad flags %s", $1);
3344130617Smlaier				free($1);
3345126353Smlaier				YYERROR;
3346126353Smlaier			}
3347130617Smlaier			free($1);
3348126353Smlaier			$$.b1 = f;
3349126353Smlaier		}
3350126353Smlaier		;
3351126353Smlaier
3352126353Smlaierflags		: FLAGS flag '/' flag	{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
3353126353Smlaier		| FLAGS '/' flag	{ $$.b1 = 0; $$.b2 = $3.b1; }
3354171172Smlaier		| FLAGS ANY		{ $$.b1 = 0; $$.b2 = 0; }
3355126353Smlaier		;
3356126353Smlaier
3357223637Sbzicmpspec	: ICMPTYPE icmp_item			{ $$ = $2; }
3358223637Sbz		| ICMPTYPE '{' optnl icmp_list '}'	{ $$ = $4; }
3359223637Sbz		| ICMP6TYPE icmp6_item			{ $$ = $2; }
3360223637Sbz		| ICMP6TYPE '{' optnl icmp6_list '}'	{ $$ = $4; }
3361126353Smlaier		;
3362126353Smlaier
3363223637Sbzicmp_list	: icmp_item optnl		{ $$ = $1; }
3364223637Sbz		| icmp_list comma icmp_item optnl {
3365126353Smlaier			$1->tail->next = $3;
3366126353Smlaier			$1->tail = $3;
3367126353Smlaier			$$ = $1;
3368126353Smlaier		}
3369126353Smlaier		;
3370126353Smlaier
3371223637Sbzicmp6_list	: icmp6_item optnl		{ $$ = $1; }
3372223637Sbz		| icmp6_list comma icmp6_item optnl {
3373126353Smlaier			$1->tail->next = $3;
3374126353Smlaier			$1->tail = $3;
3375126353Smlaier			$$ = $1;
3376126353Smlaier		}
3377126353Smlaier		;
3378126353Smlaier
3379126353Smlaiericmp_item	: icmptype		{
3380126353Smlaier			$$ = calloc(1, sizeof(struct node_icmp));
3381126353Smlaier			if ($$ == NULL)
3382126353Smlaier				err(1, "icmp_item: calloc");
3383126353Smlaier			$$->type = $1;
3384126353Smlaier			$$->code = 0;
3385126353Smlaier			$$->proto = IPPROTO_ICMP;
3386126353Smlaier			$$->next = NULL;
3387126353Smlaier			$$->tail = $$;
3388126353Smlaier		}
3389126353Smlaier		| icmptype CODE STRING	{
3390126353Smlaier			const struct icmpcodeent	*p;
3391126353Smlaier
3392223637Sbz			if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) {
3393223637Sbz				yyerror("unknown icmp-code %s", $3);
3394223637Sbz				free($3);
3395223637Sbz				YYERROR;
3396126353Smlaier			}
3397223637Sbz
3398130617Smlaier			free($3);
3399126353Smlaier			$$ = calloc(1, sizeof(struct node_icmp));
3400126353Smlaier			if ($$ == NULL)
3401126353Smlaier				err(1, "icmp_item: calloc");
3402126353Smlaier			$$->type = $1;
3403223637Sbz			$$->code = p->code + 1;
3404126353Smlaier			$$->proto = IPPROTO_ICMP;
3405126353Smlaier			$$->next = NULL;
3406126353Smlaier			$$->tail = $$;
3407126353Smlaier		}
3408223637Sbz		| icmptype CODE NUMBER	{
3409223637Sbz			if ($3 < 0 || $3 > 255) {
3410223637Sbz				yyerror("illegal icmp-code %lu", $3);
3411223637Sbz				YYERROR;
3412223637Sbz			}
3413223637Sbz			$$ = calloc(1, sizeof(struct node_icmp));
3414223637Sbz			if ($$ == NULL)
3415223637Sbz				err(1, "icmp_item: calloc");
3416223637Sbz			$$->type = $1;
3417223637Sbz			$$->code = $3 + 1;
3418223637Sbz			$$->proto = IPPROTO_ICMP;
3419223637Sbz			$$->next = NULL;
3420223637Sbz			$$->tail = $$;
3421223637Sbz		}
3422126353Smlaier		;
3423126353Smlaier
3424126353Smlaiericmp6_item	: icmp6type		{
3425126353Smlaier			$$ = calloc(1, sizeof(struct node_icmp));
3426126353Smlaier			if ($$ == NULL)
3427126353Smlaier				err(1, "icmp_item: calloc");
3428126353Smlaier			$$->type = $1;
3429126353Smlaier			$$->code = 0;
3430126353Smlaier			$$->proto = IPPROTO_ICMPV6;
3431126353Smlaier			$$->next = NULL;
3432126353Smlaier			$$->tail = $$;
3433126353Smlaier		}
3434126353Smlaier		| icmp6type CODE STRING	{
3435126353Smlaier			const struct icmpcodeent	*p;
3436126353Smlaier
3437223637Sbz			if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) {
3438223637Sbz				yyerror("unknown icmp6-code %s", $3);
3439223637Sbz				free($3);
3440223637Sbz				YYERROR;
3441126353Smlaier			}
3442130617Smlaier			free($3);
3443223637Sbz
3444126353Smlaier			$$ = calloc(1, sizeof(struct node_icmp));
3445126353Smlaier			if ($$ == NULL)
3446126353Smlaier				err(1, "icmp_item: calloc");
3447126353Smlaier			$$->type = $1;
3448223637Sbz			$$->code = p->code + 1;
3449126353Smlaier			$$->proto = IPPROTO_ICMPV6;
3450126353Smlaier			$$->next = NULL;
3451126353Smlaier			$$->tail = $$;
3452126353Smlaier		}
3453223637Sbz		| icmp6type CODE NUMBER	{
3454223637Sbz			if ($3 < 0 || $3 > 255) {
3455223637Sbz				yyerror("illegal icmp-code %lu", $3);
3456223637Sbz				YYERROR;
3457223637Sbz			}
3458223637Sbz			$$ = calloc(1, sizeof(struct node_icmp));
3459223637Sbz			if ($$ == NULL)
3460223637Sbz				err(1, "icmp_item: calloc");
3461223637Sbz			$$->type = $1;
3462223637Sbz			$$->code = $3 + 1;
3463223637Sbz			$$->proto = IPPROTO_ICMPV6;
3464223637Sbz			$$->next = NULL;
3465223637Sbz			$$->tail = $$;
3466223637Sbz		}
3467126353Smlaier		;
3468126353Smlaier
3469126353Smlaiericmptype	: STRING			{
3470126353Smlaier			const struct icmptypeent	*p;
3471126353Smlaier
3472223637Sbz			if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
3473223637Sbz				yyerror("unknown icmp-type %s", $1);
3474223637Sbz				free($1);
3475223637Sbz				YYERROR;
3476126353Smlaier			}
3477223637Sbz			$$ = p->type + 1;
3478130617Smlaier			free($1);
3479126353Smlaier		}
3480223637Sbz		| NUMBER			{
3481223637Sbz			if ($1 < 0 || $1 > 255) {
3482223637Sbz				yyerror("illegal icmp-type %lu", $1);
3483223637Sbz				YYERROR;
3484223637Sbz			}
3485223637Sbz			$$ = $1 + 1;
3486223637Sbz		}
3487126353Smlaier		;
3488126353Smlaier
3489126353Smlaiericmp6type	: STRING			{
3490126353Smlaier			const struct icmptypeent	*p;
3491126353Smlaier
3492223637Sbz			if ((p = geticmptypebyname($1, AF_INET6)) ==
3493223637Sbz			    NULL) {
3494223637Sbz				yyerror("unknown icmp6-type %s", $1);
3495223637Sbz				free($1);
3496223637Sbz				YYERROR;
3497126353Smlaier			}
3498223637Sbz			$$ = p->type + 1;
3499130617Smlaier			free($1);
3500126353Smlaier		}
3501223637Sbz		| NUMBER			{
3502223637Sbz			if ($1 < 0 || $1 > 255) {
3503223637Sbz				yyerror("illegal icmp6-type %lu", $1);
3504223637Sbz				YYERROR;
3505223637Sbz			}
3506223637Sbz			$$ = $1 + 1;
3507223637Sbz		}
3508126353Smlaier		;
3509126353Smlaier
3510223637Sbztos	: STRING			{
3511223637Sbz			if (!strcmp($1, "lowdelay"))
3512126353Smlaier				$$ = IPTOS_LOWDELAY;
3513223637Sbz			else if (!strcmp($1, "throughput"))
3514126353Smlaier				$$ = IPTOS_THROUGHPUT;
3515223637Sbz			else if (!strcmp($1, "reliability"))
3516126353Smlaier				$$ = IPTOS_RELIABILITY;
3517223637Sbz			else if ($1[0] == '0' && $1[1] == 'x')
3518223637Sbz				$$ = strtoul($1, NULL, 16);
3519126353Smlaier			else
3520304281Skp				$$ = 256;		/* flag bad argument */
3521304281Skp			if ($$ < 0 || $$ > 255) {
3522223637Sbz				yyerror("illegal tos value %s", $1);
3523223637Sbz				free($1);
3524126353Smlaier				YYERROR;
3525126353Smlaier			}
3526223637Sbz			free($1);
3527126353Smlaier		}
3528223637Sbz		| NUMBER			{
3529223637Sbz			$$ = $1;
3530304281Skp			if ($$ < 0 || $$ > 255) {
3531223637Sbz				yyerror("illegal tos value %s", $1);
3532223637Sbz				YYERROR;
3533223637Sbz			}
3534223637Sbz		}
3535126353Smlaier		;
3536126353Smlaier
3537130617Smlaiersourcetrack	: SOURCETRACK		{ $$ = PF_SRCTRACK; }
3538130617Smlaier		| SOURCETRACK GLOBAL	{ $$ = PF_SRCTRACK_GLOBAL; }
3539130617Smlaier		| SOURCETRACK RULE	{ $$ = PF_SRCTRACK_RULE; }
3540130617Smlaier		;
3541130617Smlaier
3542130617Smlaierstatelock	: IFBOUND {
3543130617Smlaier			$$ = PFRULE_IFBOUND;
3544130617Smlaier		}
3545130617Smlaier		| FLOATING {
3546130617Smlaier			$$ = 0;
3547130617Smlaier		}
3548130617Smlaier		;
3549130617Smlaier
3550171172Smlaierkeep		: NO STATE			{
3551171172Smlaier			$$.action = 0;
3552171172Smlaier			$$.options = NULL;
3553171172Smlaier		}
3554171172Smlaier		| KEEP STATE state_opt_spec	{
3555126353Smlaier			$$.action = PF_STATE_NORMAL;
3556126353Smlaier			$$.options = $3;
3557126353Smlaier		}
3558130617Smlaier		| MODULATE STATE state_opt_spec {
3559126353Smlaier			$$.action = PF_STATE_MODULATE;
3560126353Smlaier			$$.options = $3;
3561126353Smlaier		}
3562126353Smlaier		| SYNPROXY STATE state_opt_spec {
3563126353Smlaier			$$.action = PF_STATE_SYNPROXY;
3564126353Smlaier			$$.options = $3;
3565126353Smlaier		}
3566126353Smlaier		;
3567126353Smlaier
3568145840Smlaierflush		: /* empty */			{ $$ = 0; }
3569145840Smlaier		| FLUSH				{ $$ = PF_FLUSH; }
3570145840Smlaier		| FLUSH GLOBAL			{
3571145840Smlaier			$$ = PF_FLUSH | PF_FLUSH_GLOBAL;
3572145840Smlaier		}
3573145840Smlaier		;
3574145840Smlaier
3575126353Smlaierstate_opt_spec	: '(' state_opt_list ')'	{ $$ = $2; }
3576126353Smlaier		| /* empty */			{ $$ = NULL; }
3577126353Smlaier		;
3578126353Smlaier
3579126353Smlaierstate_opt_list	: state_opt_item		{ $$ = $1; }
3580126353Smlaier		| state_opt_list comma state_opt_item {
3581126353Smlaier			$1->tail->next = $3;
3582126353Smlaier			$1->tail = $3;
3583126353Smlaier			$$ = $1;
3584126353Smlaier		}
3585126353Smlaier		;
3586126353Smlaier
3587223637Sbzstate_opt_item	: MAXIMUM NUMBER		{
3588223637Sbz			if ($2 < 0 || $2 > UINT_MAX) {
3589223637Sbz				yyerror("only positive values permitted");
3590223637Sbz				YYERROR;
3591223637Sbz			}
3592126353Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3593126353Smlaier			if ($$ == NULL)
3594126353Smlaier				err(1, "state_opt_item: calloc");
3595126353Smlaier			$$->type = PF_STATE_OPT_MAX;
3596126353Smlaier			$$->data.max_states = $2;
3597126353Smlaier			$$->next = NULL;
3598126353Smlaier			$$->tail = $$;
3599126353Smlaier		}
3600130617Smlaier		| NOSYNC				{
3601130617Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3602130617Smlaier			if ($$ == NULL)
3603130617Smlaier				err(1, "state_opt_item: calloc");
3604130617Smlaier			$$->type = PF_STATE_OPT_NOSYNC;
3605130617Smlaier			$$->next = NULL;
3606130617Smlaier			$$->tail = $$;
3607130617Smlaier		}
3608223637Sbz		| MAXSRCSTATES NUMBER			{
3609223637Sbz			if ($2 < 0 || $2 > UINT_MAX) {
3610223637Sbz				yyerror("only positive values permitted");
3611223637Sbz				YYERROR;
3612223637Sbz			}
3613130617Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3614130617Smlaier			if ($$ == NULL)
3615130617Smlaier				err(1, "state_opt_item: calloc");
3616130617Smlaier			$$->type = PF_STATE_OPT_MAX_SRC_STATES;
3617130617Smlaier			$$->data.max_src_states = $2;
3618130617Smlaier			$$->next = NULL;
3619130617Smlaier			$$->tail = $$;
3620130617Smlaier		}
3621223637Sbz		| MAXSRCCONN NUMBER			{
3622223637Sbz			if ($2 < 0 || $2 > UINT_MAX) {
3623223637Sbz				yyerror("only positive values permitted");
3624223637Sbz				YYERROR;
3625223637Sbz			}
3626145840Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3627145840Smlaier			if ($$ == NULL)
3628145840Smlaier				err(1, "state_opt_item: calloc");
3629145840Smlaier			$$->type = PF_STATE_OPT_MAX_SRC_CONN;
3630145840Smlaier			$$->data.max_src_conn = $2;
3631145840Smlaier			$$->next = NULL;
3632145840Smlaier			$$->tail = $$;
3633145840Smlaier		}
3634223637Sbz		| MAXSRCCONNRATE NUMBER '/' NUMBER	{
3635223637Sbz			if ($2 < 0 || $2 > UINT_MAX ||
3636223637Sbz			    $4 < 0 || $4 > UINT_MAX) {
3637223637Sbz				yyerror("only positive values permitted");
3638223637Sbz				YYERROR;
3639223637Sbz			}
3640145840Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3641145840Smlaier			if ($$ == NULL)
3642145840Smlaier				err(1, "state_opt_item: calloc");
3643145840Smlaier			$$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
3644145840Smlaier			$$->data.max_src_conn_rate.limit = $2;
3645145840Smlaier			$$->data.max_src_conn_rate.seconds = $4;
3646145840Smlaier			$$->next = NULL;
3647145840Smlaier			$$->tail = $$;
3648145840Smlaier		}
3649145840Smlaier		| OVERLOAD '<' STRING '>' flush		{
3650145840Smlaier			if (strlen($3) >= PF_TABLE_NAME_SIZE) {
3651145840Smlaier				yyerror("table name '%s' too long", $3);
3652145840Smlaier				free($3);
3653145840Smlaier				YYERROR;
3654145840Smlaier			}
3655145840Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3656145840Smlaier			if ($$ == NULL)
3657145840Smlaier				err(1, "state_opt_item: calloc");
3658145840Smlaier			if (strlcpy($$->data.overload.tblname, $3,
3659145840Smlaier			    PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
3660145840Smlaier				errx(1, "state_opt_item: strlcpy");
3661145840Smlaier			free($3);
3662145840Smlaier			$$->type = PF_STATE_OPT_OVERLOAD;
3663145840Smlaier			$$->data.overload.flush = $5;
3664145840Smlaier			$$->next = NULL;
3665145840Smlaier			$$->tail = $$;
3666145840Smlaier		}
3667223637Sbz		| MAXSRCNODES NUMBER			{
3668223637Sbz			if ($2 < 0 || $2 > UINT_MAX) {
3669223637Sbz				yyerror("only positive values permitted");
3670223637Sbz				YYERROR;
3671223637Sbz			}
3672130617Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3673130617Smlaier			if ($$ == NULL)
3674130617Smlaier				err(1, "state_opt_item: calloc");
3675130617Smlaier			$$->type = PF_STATE_OPT_MAX_SRC_NODES;
3676130617Smlaier			$$->data.max_src_nodes = $2;
3677130617Smlaier			$$->next = NULL;
3678130617Smlaier			$$->tail = $$;
3679130617Smlaier		}
3680130617Smlaier		| sourcetrack {
3681130617Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3682130617Smlaier			if ($$ == NULL)
3683130617Smlaier				err(1, "state_opt_item: calloc");
3684130617Smlaier			$$->type = PF_STATE_OPT_SRCTRACK;
3685130617Smlaier			$$->data.src_track = $1;
3686130617Smlaier			$$->next = NULL;
3687130617Smlaier			$$->tail = $$;
3688130617Smlaier		}
3689130617Smlaier		| statelock {
3690130617Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3691130617Smlaier			if ($$ == NULL)
3692130617Smlaier				err(1, "state_opt_item: calloc");
3693130617Smlaier			$$->type = PF_STATE_OPT_STATELOCK;
3694130617Smlaier			$$->data.statelock = $1;
3695130617Smlaier			$$->next = NULL;
3696130617Smlaier			$$->tail = $$;
3697130617Smlaier		}
3698200930Sdelphij		| SLOPPY {
3699200930Sdelphij			$$ = calloc(1, sizeof(struct node_state_opt));
3700200930Sdelphij			if ($$ == NULL)
3701200930Sdelphij				err(1, "state_opt_item: calloc");
3702200930Sdelphij			$$->type = PF_STATE_OPT_SLOPPY;
3703200930Sdelphij			$$->next = NULL;
3704200930Sdelphij			$$->tail = $$;
3705200930Sdelphij		}
3706223637Sbz		| STRING NUMBER			{
3707126353Smlaier			int	i;
3708126353Smlaier
3709223637Sbz			if ($2 < 0 || $2 > UINT_MAX) {
3710223637Sbz				yyerror("only positive values permitted");
3711223637Sbz				YYERROR;
3712223637Sbz			}
3713126353Smlaier			for (i = 0; pf_timeouts[i].name &&
3714126353Smlaier			    strcmp(pf_timeouts[i].name, $1); ++i)
3715126353Smlaier				;	/* nothing */
3716126353Smlaier			if (!pf_timeouts[i].name) {
3717126353Smlaier				yyerror("illegal timeout name %s", $1);
3718130617Smlaier				free($1);
3719126353Smlaier				YYERROR;
3720126353Smlaier			}
3721126353Smlaier			if (strchr(pf_timeouts[i].name, '.') == NULL) {
3722126353Smlaier				yyerror("illegal state timeout %s", $1);
3723130617Smlaier				free($1);
3724126353Smlaier				YYERROR;
3725126353Smlaier			}
3726130617Smlaier			free($1);
3727126353Smlaier			$$ = calloc(1, sizeof(struct node_state_opt));
3728126353Smlaier			if ($$ == NULL)
3729126353Smlaier				err(1, "state_opt_item: calloc");
3730126353Smlaier			$$->type = PF_STATE_OPT_TIMEOUT;
3731126353Smlaier			$$->data.timeout.number = pf_timeouts[i].timeout;
3732126353Smlaier			$$->data.timeout.seconds = $2;
3733126353Smlaier			$$->next = NULL;
3734126353Smlaier			$$->tail = $$;
3735126353Smlaier		}
3736126353Smlaier		;
3737126353Smlaier
3738126353Smlaierlabel		: LABEL STRING			{
3739130617Smlaier			$$ = $2;
3740126353Smlaier		}
3741126353Smlaier		;
3742126353Smlaier
3743126353Smlaierqname		: QUEUE STRING				{
3744130617Smlaier			$$.qname = $2;
3745223637Sbz			$$.pqname = NULL;
3746126353Smlaier		}
3747126353Smlaier		| QUEUE '(' STRING ')'			{
3748130617Smlaier			$$.qname = $3;
3749223637Sbz			$$.pqname = NULL;
3750126353Smlaier		}
3751126353Smlaier		| QUEUE '(' STRING comma STRING ')'	{
3752130617Smlaier			$$.qname = $3;
3753130617Smlaier			$$.pqname = $5;
3754126353Smlaier		}
3755126353Smlaier		;
3756126353Smlaier
3757126353Smlaierno		: /* empty */			{ $$ = 0; }
3758126353Smlaier		| NO				{ $$ = 1; }
3759126353Smlaier		;
3760126353Smlaier
3761223637Sbzportstar	: numberstring			{
3762223637Sbz			if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) {
3763223637Sbz				free($1);
3764223637Sbz				YYERROR;
3765126353Smlaier			}
3766130617Smlaier			free($1);
3767126353Smlaier		}
3768126353Smlaier		;
3769126353Smlaier
3770126353Smlaierredirspec	: host				{ $$ = $1; }
3771223637Sbz		| '{' optnl redir_host_list '}'	{ $$ = $3; }
3772126353Smlaier		;
3773126353Smlaier
3774223637Sbzredir_host_list	: host optnl			{ $$ = $1; }
3775223637Sbz		| redir_host_list comma host optnl {
3776126353Smlaier			$1->tail->next = $3;
3777126353Smlaier			$1->tail = $3->tail;
3778126353Smlaier			$$ = $1;
3779126353Smlaier		}
3780126353Smlaier		;
3781126353Smlaier
3782126353Smlaierredirpool	: /* empty */			{ $$ = NULL; }
3783126353Smlaier		| ARROW redirspec		{
3784126353Smlaier			$$ = calloc(1, sizeof(struct redirection));
3785126353Smlaier			if ($$ == NULL)
3786126353Smlaier				err(1, "redirection: calloc");
3787126353Smlaier			$$->host = $2;
3788126353Smlaier			$$->rport.a = $$->rport.b = $$->rport.t = 0;
3789126353Smlaier		}
3790223637Sbz		| ARROW redirspec PORT portstar	{
3791126353Smlaier			$$ = calloc(1, sizeof(struct redirection));
3792126353Smlaier			if ($$ == NULL)
3793126353Smlaier				err(1, "redirection: calloc");
3794126353Smlaier			$$->host = $2;
3795126353Smlaier			$$->rport = $4;
3796126353Smlaier		}
3797126353Smlaier		;
3798126353Smlaier
3799126353Smlaierhashkey		: /* empty */
3800126353Smlaier		{
3801126353Smlaier			$$ = calloc(1, sizeof(struct pf_poolhashkey));
3802126353Smlaier			if ($$ == NULL)
3803126353Smlaier				err(1, "hashkey: calloc");
3804126353Smlaier			$$->key32[0] = arc4random();
3805126353Smlaier			$$->key32[1] = arc4random();
3806126353Smlaier			$$->key32[2] = arc4random();
3807126353Smlaier			$$->key32[3] = arc4random();
3808126353Smlaier		}
3809126353Smlaier		| string
3810126353Smlaier		{
3811126353Smlaier			if (!strncmp($1, "0x", 2)) {
3812126353Smlaier				if (strlen($1) != 34) {
3813130617Smlaier					free($1);
3814126353Smlaier					yyerror("hex key must be 128 bits "
3815126353Smlaier						"(32 hex digits) long");
3816126353Smlaier					YYERROR;
3817126353Smlaier				}
3818126353Smlaier				$$ = calloc(1, sizeof(struct pf_poolhashkey));
3819126353Smlaier				if ($$ == NULL)
3820126353Smlaier					err(1, "hashkey: calloc");
3821126353Smlaier
3822126353Smlaier				if (sscanf($1, "0x%8x%8x%8x%8x",
3823126353Smlaier				    &$$->key32[0], &$$->key32[1],
3824126353Smlaier				    &$$->key32[2], &$$->key32[3]) != 4) {
3825126353Smlaier					free($$);
3826130617Smlaier					free($1);
3827126353Smlaier					yyerror("invalid hex key");
3828126353Smlaier					YYERROR;
3829126353Smlaier				}
3830126353Smlaier			} else {
3831126353Smlaier				MD5_CTX	context;
3832126353Smlaier
3833126353Smlaier				$$ = calloc(1, sizeof(struct pf_poolhashkey));
3834126353Smlaier				if ($$ == NULL)
3835126353Smlaier					err(1, "hashkey: calloc");
3836126353Smlaier				MD5Init(&context);
3837126353Smlaier				MD5Update(&context, (unsigned char *)$1,
3838126353Smlaier				    strlen($1));
3839126353Smlaier				MD5Final((unsigned char *)$$, &context);
3840126353Smlaier				HTONL($$->key32[0]);
3841126353Smlaier				HTONL($$->key32[1]);
3842126353Smlaier				HTONL($$->key32[2]);
3843126353Smlaier				HTONL($$->key32[3]);
3844126353Smlaier			}
3845130617Smlaier			free($1);
3846126353Smlaier		}
3847126353Smlaier		;
3848126353Smlaier
3849130617Smlaierpool_opts	:	{ bzero(&pool_opts, sizeof pool_opts); }
3850130617Smlaier		    pool_opts_l
3851130617Smlaier			{ $$ = pool_opts; }
3852130617Smlaier		| /* empty */	{
3853130617Smlaier			bzero(&pool_opts, sizeof pool_opts);
3854130617Smlaier			$$ = pool_opts;
3855126353Smlaier		}
3856130617Smlaier		;
3857130617Smlaier
3858130617Smlaierpool_opts_l	: pool_opts_l pool_opt
3859130617Smlaier		| pool_opt
3860130617Smlaier		;
3861130617Smlaier
3862130617Smlaierpool_opt	: BITMASK	{
3863130617Smlaier			if (pool_opts.type) {
3864130617Smlaier				yyerror("pool type cannot be redefined");
3865130617Smlaier				YYERROR;
3866130617Smlaier			}
3867130617Smlaier			pool_opts.type =  PF_POOL_BITMASK;
3868126353Smlaier		}
3869130617Smlaier		| RANDOM	{
3870130617Smlaier			if (pool_opts.type) {
3871130617Smlaier				yyerror("pool type cannot be redefined");
3872130617Smlaier				YYERROR;
3873130617Smlaier			}
3874130617Smlaier			pool_opts.type = PF_POOL_RANDOM;
3875126353Smlaier		}
3876130617Smlaier		| SOURCEHASH hashkey {
3877130617Smlaier			if (pool_opts.type) {
3878130617Smlaier				yyerror("pool type cannot be redefined");
3879130617Smlaier				YYERROR;
3880130617Smlaier			}
3881130617Smlaier			pool_opts.type = PF_POOL_SRCHASH;
3882130617Smlaier			pool_opts.key = $2;
3883126353Smlaier		}
3884130617Smlaier		| ROUNDROBIN	{
3885130617Smlaier			if (pool_opts.type) {
3886130617Smlaier				yyerror("pool type cannot be redefined");
3887130617Smlaier				YYERROR;
3888130617Smlaier			}
3889130617Smlaier			pool_opts.type = PF_POOL_ROUNDROBIN;
3890126353Smlaier		}
3891130617Smlaier		| STATICPORT	{
3892130617Smlaier			if (pool_opts.staticport) {
3893130617Smlaier				yyerror("static-port cannot be redefined");
3894130617Smlaier				YYERROR;
3895130617Smlaier			}
3896130617Smlaier			pool_opts.staticport = 1;
3897130617Smlaier		}
3898130617Smlaier		| STICKYADDRESS	{
3899130617Smlaier			if (filter_opts.marker & POM_STICKYADDRESS) {
3900130617Smlaier				yyerror("sticky-address cannot be redefined");
3901130617Smlaier				YYERROR;
3902130617Smlaier			}
3903130617Smlaier			pool_opts.marker |= POM_STICKYADDRESS;
3904130617Smlaier			pool_opts.opts |= PF_POOL_STICKYADDR;
3905130617Smlaier		}
3906126353Smlaier		;
3907126353Smlaier
3908126353Smlaierredirection	: /* empty */			{ $$ = NULL; }
3909126353Smlaier		| ARROW host			{
3910126353Smlaier			$$ = calloc(1, sizeof(struct redirection));
3911126353Smlaier			if ($$ == NULL)
3912126353Smlaier				err(1, "redirection: calloc");
3913126353Smlaier			$$->host = $2;
3914126353Smlaier			$$->rport.a = $$->rport.b = $$->rport.t = 0;
3915126353Smlaier		}
3916223637Sbz		| ARROW host PORT portstar	{
3917126353Smlaier			$$ = calloc(1, sizeof(struct redirection));
3918126353Smlaier			if ($$ == NULL)
3919126353Smlaier				err(1, "redirection: calloc");
3920126353Smlaier			$$->host = $2;
3921126353Smlaier			$$->rport = $4;
3922126353Smlaier		}
3923126353Smlaier		;
3924126353Smlaier
3925223637Sbznatpasslog	: /* empty */	{ $$.b1 = $$.b2 = 0; $$.w2 = 0; }
3926171172Smlaier		| PASS		{ $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
3927171172Smlaier		| PASS log	{ $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
3928223637Sbz		| log		{ $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
3929126353Smlaier		;
3930126353Smlaier
3931223637Sbznataction	: no NAT natpasslog {
3932171172Smlaier			if ($1 && $3.b1) {
3933171172Smlaier				yyerror("\"pass\" not valid with \"no\"");
3934171172Smlaier				YYERROR;
3935171172Smlaier			}
3936126353Smlaier			if ($1)
3937126353Smlaier				$$.b1 = PF_NONAT;
3938126353Smlaier			else
3939126353Smlaier				$$.b1 = PF_NAT;
3940171172Smlaier			$$.b2 = $3.b1;
3941171172Smlaier			$$.w = $3.b2;
3942171172Smlaier			$$.w2 = $3.w2;
3943126353Smlaier		}
3944223637Sbz		| no RDR natpasslog {
3945171172Smlaier			if ($1 && $3.b1) {
3946171172Smlaier				yyerror("\"pass\" not valid with \"no\"");
3947171172Smlaier				YYERROR;
3948171172Smlaier			}
3949126353Smlaier			if ($1)
3950126353Smlaier				$$.b1 = PF_NORDR;
3951126353Smlaier			else
3952126353Smlaier				$$.b1 = PF_RDR;
3953171172Smlaier			$$.b2 = $3.b1;
3954171172Smlaier			$$.w = $3.b2;
3955171172Smlaier			$$.w2 = $3.w2;
3956126353Smlaier		}
3957126353Smlaier		;
3958126353Smlaier
3959171172Smlaiernatrule		: nataction interface af proto fromto tag tagged rtable
3960171172Smlaier		    redirpool pool_opts
3961126353Smlaier		{
3962126353Smlaier			struct pf_rule	r;
3963126353Smlaier
3964126353Smlaier			if (check_rulestate(PFCTL_STATE_NAT))
3965126353Smlaier				YYERROR;
3966126353Smlaier
3967126353Smlaier			memset(&r, 0, sizeof(r));
3968126353Smlaier
3969126353Smlaier			r.action = $1.b1;
3970126353Smlaier			r.natpass = $1.b2;
3971171172Smlaier			r.log = $1.w;
3972171172Smlaier			r.logif = $1.w2;
3973126353Smlaier			r.af = $3;
3974126353Smlaier
3975126353Smlaier			if (!r.af) {
3976126353Smlaier				if ($5.src.host && $5.src.host->af &&
3977126353Smlaier				    !$5.src.host->ifindex)
3978126353Smlaier					r.af = $5.src.host->af;
3979126353Smlaier				else if ($5.dst.host && $5.dst.host->af &&
3980126353Smlaier				    !$5.dst.host->ifindex)
3981126353Smlaier					r.af = $5.dst.host->af;
3982126353Smlaier			}
3983126353Smlaier
3984126353Smlaier			if ($6 != NULL)
3985130617Smlaier				if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
3986126353Smlaier				    PF_TAG_NAME_SIZE) {
3987126353Smlaier					yyerror("tag too long, max %u chars",
3988126353Smlaier					    PF_TAG_NAME_SIZE - 1);
3989126353Smlaier					YYERROR;
3990126353Smlaier				}
3991126353Smlaier
3992145840Smlaier			if ($7.name)
3993145840Smlaier				if (strlcpy(r.match_tagname, $7.name,
3994145840Smlaier				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
3995145840Smlaier					yyerror("tag too long, max %u chars",
3996145840Smlaier					    PF_TAG_NAME_SIZE - 1);
3997145840Smlaier					YYERROR;
3998145840Smlaier				}
3999145840Smlaier			r.match_tag_not = $7.neg;
4000171172Smlaier			r.rtableid = $8;
4001145840Smlaier
4002126353Smlaier			if (r.action == PF_NONAT || r.action == PF_NORDR) {
4003171172Smlaier				if ($9 != NULL) {
4004126353Smlaier					yyerror("translation rule with 'no' "
4005126353Smlaier					    "does not need '->'");
4006126353Smlaier					YYERROR;
4007126353Smlaier				}
4008126353Smlaier			} else {
4009171172Smlaier				if ($9 == NULL || $9->host == NULL) {
4010126353Smlaier					yyerror("translation rule requires '-> "
4011126353Smlaier					    "address'");
4012126353Smlaier					YYERROR;
4013126353Smlaier				}
4014171172Smlaier				if (!r.af && ! $9->host->ifindex)
4015171172Smlaier					r.af = $9->host->af;
4016126353Smlaier
4017171172Smlaier				remove_invalid_hosts(&$9->host, &r.af);
4018171172Smlaier				if (invalid_redirect($9->host, r.af))
4019126353Smlaier					YYERROR;
4020171172Smlaier				if (check_netmask($9->host, r.af))
4021126353Smlaier					YYERROR;
4022126353Smlaier
4023171172Smlaier				r.rpool.proxy_port[0] = ntohs($9->rport.a);
4024126353Smlaier
4025126353Smlaier				switch (r.action) {
4026126353Smlaier				case PF_RDR:
4027171172Smlaier					if (!$9->rport.b && $9->rport.t &&
4028126353Smlaier					    $5.dst.port != NULL) {
4029126353Smlaier						r.rpool.proxy_port[1] =
4030171172Smlaier						    ntohs($9->rport.a) +
4031130617Smlaier						    (ntohs(
4032130617Smlaier						    $5.dst.port->port[1]) -
4033130617Smlaier						    ntohs(
4034130617Smlaier						    $5.dst.port->port[0]));
4035126353Smlaier					} else
4036126353Smlaier						r.rpool.proxy_port[1] =
4037171172Smlaier						    ntohs($9->rport.b);
4038126353Smlaier					break;
4039126353Smlaier				case PF_NAT:
4040130617Smlaier					r.rpool.proxy_port[1] =
4041171172Smlaier					    ntohs($9->rport.b);
4042126353Smlaier					if (!r.rpool.proxy_port[0] &&
4043126353Smlaier					    !r.rpool.proxy_port[1]) {
4044126353Smlaier						r.rpool.proxy_port[0] =
4045126353Smlaier						    PF_NAT_PROXY_PORT_LOW;
4046126353Smlaier						r.rpool.proxy_port[1] =
4047126353Smlaier						    PF_NAT_PROXY_PORT_HIGH;
4048126353Smlaier					} else if (!r.rpool.proxy_port[1])
4049126353Smlaier						r.rpool.proxy_port[1] =
4050126353Smlaier						    r.rpool.proxy_port[0];
4051126353Smlaier					break;
4052126353Smlaier				default:
4053126353Smlaier					break;
4054126353Smlaier				}
4055126353Smlaier
4056171172Smlaier				r.rpool.opts = $10.type;
4057130617Smlaier				if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
4058171172Smlaier				    PF_POOL_NONE && ($9->host->next != NULL ||
4059171172Smlaier				    $9->host->addr.type == PF_ADDR_TABLE ||
4060171172Smlaier				    DYNIF_MULTIADDR($9->host->addr)))
4061126353Smlaier					r.rpool.opts = PF_POOL_ROUNDROBIN;
4062130617Smlaier				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
4063130617Smlaier				    PF_POOL_ROUNDROBIN &&
4064171172Smlaier				    disallow_table($9->host, "tables are only "
4065130617Smlaier				    "supported in round-robin redirection "
4066130617Smlaier				    "pools"))
4067130617Smlaier					YYERROR;
4068130617Smlaier				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
4069130617Smlaier				    PF_POOL_ROUNDROBIN &&
4070171172Smlaier				    disallow_alias($9->host, "interface (%s) "
4071130617Smlaier				    "is only supported in round-robin "
4072130617Smlaier				    "redirection pools"))
4073130617Smlaier					YYERROR;
4074171172Smlaier				if ($9->host->next != NULL) {
4075130617Smlaier					if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
4076126353Smlaier					    PF_POOL_ROUNDROBIN) {
4077126353Smlaier						yyerror("only round-robin "
4078126353Smlaier						    "valid for multiple "
4079126353Smlaier						    "redirection addresses");
4080126353Smlaier						YYERROR;
4081126353Smlaier					}
4082126353Smlaier				}
4083126353Smlaier			}
4084126353Smlaier
4085171172Smlaier			if ($10.key != NULL)
4086171172Smlaier				memcpy(&r.rpool.key, $10.key,
4087126353Smlaier				    sizeof(struct pf_poolhashkey));
4088126353Smlaier
4089171172Smlaier			 if ($10.opts)
4090171172Smlaier				r.rpool.opts |= $10.opts;
4091130617Smlaier
4092171172Smlaier			if ($10.staticport) {
4093126353Smlaier				if (r.action != PF_NAT) {
4094126353Smlaier					yyerror("the 'static-port' option is "
4095126353Smlaier					    "only valid with nat rules");
4096126353Smlaier					YYERROR;
4097126353Smlaier				}
4098126353Smlaier				if (r.rpool.proxy_port[0] !=
4099126353Smlaier				    PF_NAT_PROXY_PORT_LOW &&
4100126353Smlaier				    r.rpool.proxy_port[1] !=
4101126353Smlaier				    PF_NAT_PROXY_PORT_HIGH) {
4102126353Smlaier					yyerror("the 'static-port' option can't"
4103126353Smlaier					    " be used when specifying a port"
4104126353Smlaier					    " range");
4105126353Smlaier					YYERROR;
4106126353Smlaier				}
4107126353Smlaier				r.rpool.proxy_port[0] = 0;
4108126353Smlaier				r.rpool.proxy_port[1] = 0;
4109126353Smlaier			}
4110126353Smlaier
4111171172Smlaier			expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
4112126353Smlaier			    $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
4113145840Smlaier			    $5.dst.port, 0, 0, 0, "");
4114171172Smlaier			free($9);
4115126353Smlaier		}
4116126353Smlaier		;
4117126353Smlaier
4118223637Sbzbinatrule	: no BINAT natpasslog interface af proto FROM host toipspec tag
4119171172Smlaier		    tagged rtable redirection
4120126353Smlaier		{
4121126353Smlaier			struct pf_rule		binat;
4122126353Smlaier			struct pf_pooladdr	*pa;
4123126353Smlaier
4124126353Smlaier			if (check_rulestate(PFCTL_STATE_NAT))
4125126353Smlaier				YYERROR;
4126223637Sbz			if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
4127171172Smlaier			    "permitted as a binat destination"))
4128171172Smlaier				YYERROR;
4129126353Smlaier
4130126353Smlaier			memset(&binat, 0, sizeof(binat));
4131126353Smlaier
4132171172Smlaier			if ($1 && $3.b1) {
4133171172Smlaier				yyerror("\"pass\" not valid with \"no\"");
4134171172Smlaier				YYERROR;
4135171172Smlaier			}
4136126353Smlaier			if ($1)
4137126353Smlaier				binat.action = PF_NOBINAT;
4138126353Smlaier			else
4139126353Smlaier				binat.action = PF_BINAT;
4140171172Smlaier			binat.natpass = $3.b1;
4141171172Smlaier			binat.log = $3.b2;
4142171172Smlaier			binat.logif = $3.w2;
4143126353Smlaier			binat.af = $5;
4144126353Smlaier			if (!binat.af && $8 != NULL && $8->af)
4145126353Smlaier				binat.af = $8->af;
4146223637Sbz			if (!binat.af && $9 != NULL && $9->af)
4147223637Sbz				binat.af = $9->af;
4148145840Smlaier
4149223637Sbz			if (!binat.af && $13 != NULL && $13->host)
4150223637Sbz				binat.af = $13->host->af;
4151126353Smlaier			if (!binat.af) {
4152126353Smlaier				yyerror("address family (inet/inet6) "
4153126353Smlaier				    "undefined");
4154126353Smlaier				YYERROR;
4155126353Smlaier			}
4156126353Smlaier
4157126353Smlaier			if ($4 != NULL) {
4158126353Smlaier				memcpy(binat.ifname, $4->ifname,
4159126353Smlaier				    sizeof(binat.ifname));
4160130617Smlaier				binat.ifnot = $4->not;
4161126353Smlaier				free($4);
4162126353Smlaier			}
4163145840Smlaier
4164223637Sbz			if ($10 != NULL)
4165223637Sbz				if (strlcpy(binat.tagname, $10,
4166130617Smlaier				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
4167126353Smlaier					yyerror("tag too long, max %u chars",
4168126353Smlaier					    PF_TAG_NAME_SIZE - 1);
4169126353Smlaier					YYERROR;
4170126353Smlaier				}
4171223637Sbz			if ($11.name)
4172223637Sbz				if (strlcpy(binat.match_tagname, $11.name,
4173145840Smlaier				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
4174145840Smlaier					yyerror("tag too long, max %u chars",
4175145840Smlaier					    PF_TAG_NAME_SIZE - 1);
4176145840Smlaier					YYERROR;
4177145840Smlaier				}
4178223637Sbz			binat.match_tag_not = $11.neg;
4179223637Sbz			binat.rtableid = $12;
4180126353Smlaier
4181126353Smlaier			if ($6 != NULL) {
4182126353Smlaier				binat.proto = $6->proto;
4183126353Smlaier				free($6);
4184126353Smlaier			}
4185126353Smlaier
4186126353Smlaier			if ($8 != NULL && disallow_table($8, "invalid use of "
4187126353Smlaier			    "table <%s> as the source address of a binat rule"))
4188126353Smlaier				YYERROR;
4189130617Smlaier			if ($8 != NULL && disallow_alias($8, "invalid use of "
4190130617Smlaier			    "interface (%s) as the source address of a binat "
4191130617Smlaier			    "rule"))
4192130617Smlaier				YYERROR;
4193223637Sbz			if ($13 != NULL && $13->host != NULL && disallow_table(
4194223637Sbz			    $13->host, "invalid use of table <%s> as the "
4195126353Smlaier			    "redirect address of a binat rule"))
4196126353Smlaier				YYERROR;
4197223637Sbz			if ($13 != NULL && $13->host != NULL && disallow_alias(
4198223637Sbz			    $13->host, "invalid use of interface (%s) as the "
4199130617Smlaier			    "redirect address of a binat rule"))
4200130617Smlaier				YYERROR;
4201126353Smlaier
4202126353Smlaier			if ($8 != NULL) {
4203126353Smlaier				if ($8->next) {
4204126353Smlaier					yyerror("multiple binat ip addresses");
4205126353Smlaier					YYERROR;
4206126353Smlaier				}
4207126353Smlaier				if ($8->addr.type == PF_ADDR_DYNIFTL)
4208126353Smlaier					$8->af = binat.af;
4209126353Smlaier				if ($8->af != binat.af) {
4210126353Smlaier					yyerror("binat ip versions must match");
4211126353Smlaier					YYERROR;
4212126353Smlaier				}
4213126353Smlaier				if (check_netmask($8, binat.af))
4214126353Smlaier					YYERROR;
4215126353Smlaier				memcpy(&binat.src.addr, &$8->addr,
4216126353Smlaier				    sizeof(binat.src.addr));
4217126353Smlaier				free($8);
4218126353Smlaier			}
4219223637Sbz			if ($9 != NULL) {
4220223637Sbz				if ($9->next) {
4221126353Smlaier					yyerror("multiple binat ip addresses");
4222126353Smlaier					YYERROR;
4223126353Smlaier				}
4224223637Sbz				if ($9->af != binat.af && $9->af) {
4225126353Smlaier					yyerror("binat ip versions must match");
4226126353Smlaier					YYERROR;
4227126353Smlaier				}
4228223637Sbz				if (check_netmask($9, binat.af))
4229126353Smlaier					YYERROR;
4230223637Sbz				memcpy(&binat.dst.addr, &$9->addr,
4231126353Smlaier				    sizeof(binat.dst.addr));
4232223637Sbz				binat.dst.neg = $9->not;
4233223637Sbz				free($9);
4234126353Smlaier			}
4235126353Smlaier
4236126353Smlaier			if (binat.action == PF_NOBINAT) {
4237223637Sbz				if ($13 != NULL) {
4238126353Smlaier					yyerror("'no binat' rule does not need"
4239126353Smlaier					    " '->'");
4240126353Smlaier					YYERROR;
4241126353Smlaier				}
4242126353Smlaier			} else {
4243223637Sbz				if ($13 == NULL || $13->host == NULL) {
4244126353Smlaier					yyerror("'binat' rule requires"
4245126353Smlaier					    " '-> address'");
4246126353Smlaier					YYERROR;
4247126353Smlaier				}
4248126353Smlaier
4249223637Sbz				remove_invalid_hosts(&$13->host, &binat.af);
4250223637Sbz				if (invalid_redirect($13->host, binat.af))
4251126353Smlaier					YYERROR;
4252223637Sbz				if ($13->host->next != NULL) {
4253126353Smlaier					yyerror("binat rule must redirect to "
4254126353Smlaier					    "a single address");
4255126353Smlaier					YYERROR;
4256126353Smlaier				}
4257223637Sbz				if (check_netmask($13->host, binat.af))
4258126353Smlaier					YYERROR;
4259126353Smlaier
4260126353Smlaier				if (!PF_AZERO(&binat.src.addr.v.a.mask,
4261126353Smlaier				    binat.af) &&
4262126353Smlaier				    !PF_AEQ(&binat.src.addr.v.a.mask,
4263223637Sbz				    &$13->host->addr.v.a.mask, binat.af)) {
4264126353Smlaier					yyerror("'binat' source mask and "
4265126353Smlaier					    "redirect mask must be the same");
4266126353Smlaier					YYERROR;
4267126353Smlaier				}
4268126353Smlaier
4269126353Smlaier				TAILQ_INIT(&binat.rpool.list);
4270126353Smlaier				pa = calloc(1, sizeof(struct pf_pooladdr));
4271126353Smlaier				if (pa == NULL)
4272126353Smlaier					err(1, "binat: calloc");
4273223637Sbz				pa->addr = $13->host->addr;
4274126353Smlaier				pa->ifname[0] = 0;
4275126353Smlaier				TAILQ_INSERT_TAIL(&binat.rpool.list,
4276126353Smlaier				    pa, entries);
4277126353Smlaier
4278223637Sbz				free($13);
4279126353Smlaier			}
4280126353Smlaier
4281145840Smlaier			pfctl_add_rule(pf, &binat, "");
4282126353Smlaier		}
4283126353Smlaier		;
4284126353Smlaier
4285126353Smlaiertag		: /* empty */		{ $$ = NULL; }
4286126353Smlaier		| TAG STRING		{ $$ = $2; }
4287130617Smlaier		;
4288126353Smlaier
4289145840Smlaiertagged		: /* empty */		{ $$.neg = 0; $$.name = NULL; }
4290145840Smlaier		| not TAGGED string	{ $$.neg = $1; $$.name = $3; }
4291145840Smlaier		;
4292145840Smlaier
4293171172Smlaierrtable		: /* empty */		{ $$ = -1; }
4294223637Sbz		| RTABLE NUMBER		{
4295231852Sbz			if ($2 < 0 || $2 > rt_tableid_max()) {
4296171172Smlaier				yyerror("invalid rtable id");
4297171172Smlaier				YYERROR;
4298171172Smlaier			}
4299171172Smlaier			$$ = $2;
4300171172Smlaier		}
4301171172Smlaier		;
4302171172Smlaier
4303126353Smlaierroute_host	: STRING			{
4304126353Smlaier			$$ = calloc(1, sizeof(struct node_host));
4305126353Smlaier			if ($$ == NULL)
4306126353Smlaier				err(1, "route_host: calloc");
4307130617Smlaier			$$->ifname = $1;
4308126353Smlaier			set_ipmask($$, 128);
4309126353Smlaier			$$->next = NULL;
4310126353Smlaier			$$->tail = $$;
4311126353Smlaier		}
4312126353Smlaier		| '(' STRING host ')'		{
4313326414Skp			struct node_host *n;
4314326414Skp
4315126353Smlaier			$$ = $3;
4316326414Skp			for (n = $3; n != NULL; n = n->next)
4317326414Skp				n->ifname = $2;
4318126353Smlaier		}
4319126353Smlaier		;
4320126353Smlaier
4321223637Sbzroute_host_list	: route_host optnl			{ $$ = $1; }
4322223637Sbz		| route_host_list comma route_host optnl {
4323126353Smlaier			if ($1->af == 0)
4324126353Smlaier				$1->af = $3->af;
4325126353Smlaier			if ($1->af != $3->af) {
4326126353Smlaier				yyerror("all pool addresses must be in the "
4327126353Smlaier				    "same address family");
4328126353Smlaier				YYERROR;
4329126353Smlaier			}
4330126353Smlaier			$1->tail->next = $3;
4331126353Smlaier			$1->tail = $3->tail;
4332126353Smlaier			$$ = $1;
4333126353Smlaier		}
4334126353Smlaier		;
4335126353Smlaier
4336126353Smlaierroutespec	: route_host			{ $$ = $1; }
4337223637Sbz		| '{' optnl route_host_list '}'	{ $$ = $3; }
4338126353Smlaier		;
4339126353Smlaier
4340126353Smlaierroute		: /* empty */			{
4341126353Smlaier			$$.host = NULL;
4342126353Smlaier			$$.rt = 0;
4343126353Smlaier			$$.pool_opts = 0;
4344126353Smlaier		}
4345126353Smlaier		| FASTROUTE {
4346126353Smlaier			$$.host = NULL;
4347126353Smlaier			$$.rt = PF_FASTROUTE;
4348126353Smlaier			$$.pool_opts = 0;
4349126353Smlaier		}
4350130617Smlaier		| ROUTETO routespec pool_opts {
4351126353Smlaier			$$.host = $2;
4352126353Smlaier			$$.rt = PF_ROUTETO;
4353130617Smlaier			$$.pool_opts = $3.type | $3.opts;
4354126353Smlaier			if ($3.key != NULL)
4355126353Smlaier				$$.key = $3.key;
4356126353Smlaier		}
4357130617Smlaier		| REPLYTO routespec pool_opts {
4358126353Smlaier			$$.host = $2;
4359126353Smlaier			$$.rt = PF_REPLYTO;
4360130617Smlaier			$$.pool_opts = $3.type | $3.opts;
4361126353Smlaier			if ($3.key != NULL)
4362126353Smlaier				$$.key = $3.key;
4363126353Smlaier		}
4364130617Smlaier		| DUPTO routespec pool_opts {
4365126353Smlaier			$$.host = $2;
4366126353Smlaier			$$.rt = PF_DUPTO;
4367130617Smlaier			$$.pool_opts = $3.type | $3.opts;
4368126353Smlaier			if ($3.key != NULL)
4369126353Smlaier				$$.key = $3.key;
4370126353Smlaier		}
4371126353Smlaier		;
4372126353Smlaier
4373223637Sbztimeout_spec	: STRING NUMBER
4374126353Smlaier		{
4375130617Smlaier			if (check_rulestate(PFCTL_STATE_OPTION)) {
4376130617Smlaier				free($1);
4377126353Smlaier				YYERROR;
4378130617Smlaier			}
4379223637Sbz			if ($2 < 0 || $2 > UINT_MAX) {
4380223637Sbz				yyerror("only positive values permitted");
4381223637Sbz				YYERROR;
4382223637Sbz			}
4383126353Smlaier			if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
4384126353Smlaier				yyerror("unknown timeout %s", $1);
4385130617Smlaier				free($1);
4386126353Smlaier				YYERROR;
4387126353Smlaier			}
4388130617Smlaier			free($1);
4389126353Smlaier		}
4390303865Sloos		| INTERVAL NUMBER		{
4391303865Sloos			if (check_rulestate(PFCTL_STATE_OPTION))
4392303865Sloos				YYERROR;
4393303865Sloos			if ($2 < 0 || $2 > UINT_MAX) {
4394303865Sloos				yyerror("only positive values permitted");
4395303865Sloos				YYERROR;
4396303865Sloos			}
4397303865Sloos			if (pfctl_set_timeout(pf, "interval", $2, 0) != 0)
4398303865Sloos				YYERROR;
4399303865Sloos		}
4400126353Smlaier		;
4401126353Smlaier
4402223637Sbztimeout_list	: timeout_list comma timeout_spec optnl
4403223637Sbz		| timeout_spec optnl
4404126353Smlaier		;
4405126353Smlaier
4406223637Sbzlimit_spec	: STRING NUMBER
4407126353Smlaier		{
4408130617Smlaier			if (check_rulestate(PFCTL_STATE_OPTION)) {
4409130617Smlaier				free($1);
4410126353Smlaier				YYERROR;
4411130617Smlaier			}
4412223637Sbz			if ($2 < 0 || $2 > UINT_MAX) {
4413223637Sbz				yyerror("only positive values permitted");
4414223637Sbz				YYERROR;
4415223637Sbz			}
4416126353Smlaier			if (pfctl_set_limit(pf, $1, $2) != 0) {
4417126353Smlaier				yyerror("unable to set limit %s %u", $1, $2);
4418130617Smlaier				free($1);
4419126353Smlaier				YYERROR;
4420126353Smlaier			}
4421130617Smlaier			free($1);
4422126353Smlaier		}
4423130617Smlaier		;
4424126353Smlaier
4425223637Sbzlimit_list	: limit_list comma limit_spec optnl
4426223637Sbz		| limit_spec optnl
4427126353Smlaier		;
4428126353Smlaier
4429126353Smlaiercomma		: ','
4430126353Smlaier		| /* empty */
4431126353Smlaier		;
4432126353Smlaier
4433126353Smlaieryesno		: NO			{ $$ = 0; }
4434126353Smlaier		| STRING		{
4435126353Smlaier			if (!strcmp($1, "yes"))
4436126353Smlaier				$$ = 1;
4437130617Smlaier			else {
4438145840Smlaier				yyerror("invalid value '%s', expected 'yes' "
4439145840Smlaier				    "or 'no'", $1);
4440130617Smlaier				free($1);
4441126353Smlaier				YYERROR;
4442130617Smlaier			}
4443130617Smlaier			free($1);
4444126353Smlaier		}
4445130617Smlaier		;
4446126353Smlaier
4447126353Smlaierunaryop		: '='		{ $$ = PF_OP_EQ; }
4448126353Smlaier		| '!' '='	{ $$ = PF_OP_NE; }
4449126353Smlaier		| '<' '='	{ $$ = PF_OP_LE; }
4450126353Smlaier		| '<'		{ $$ = PF_OP_LT; }
4451126353Smlaier		| '>' '='	{ $$ = PF_OP_GE; }
4452126353Smlaier		| '>'		{ $$ = PF_OP_GT; }
4453126353Smlaier		;
4454126353Smlaier
4455126353Smlaier%%
4456126353Smlaier
4457126353Smlaierint
4458126353Smlaieryyerror(const char *fmt, ...)
4459126353Smlaier{
4460126353Smlaier	va_list		 ap;
4461126353Smlaier
4462223637Sbz	file->errors++;
4463126353Smlaier	va_start(ap, fmt);
4464223637Sbz	fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
4465126353Smlaier	vfprintf(stderr, fmt, ap);
4466126353Smlaier	fprintf(stderr, "\n");
4467126353Smlaier	va_end(ap);
4468126353Smlaier	return (0);
4469126353Smlaier}
4470126353Smlaier
4471126353Smlaierint
4472126353Smlaierdisallow_table(struct node_host *h, const char *fmt)
4473126353Smlaier{
4474126353Smlaier	for (; h != NULL; h = h->next)
4475126353Smlaier		if (h->addr.type == PF_ADDR_TABLE) {
4476126353Smlaier			yyerror(fmt, h->addr.v.tblname);
4477126353Smlaier			return (1);
4478126353Smlaier		}
4479126353Smlaier	return (0);
4480126353Smlaier}
4481126353Smlaier
4482126353Smlaierint
4483171172Smlaierdisallow_urpf_failed(struct node_host *h, const char *fmt)
4484171172Smlaier{
4485171172Smlaier	for (; h != NULL; h = h->next)
4486171172Smlaier		if (h->addr.type == PF_ADDR_URPFFAILED) {
4487171172Smlaier			yyerror(fmt);
4488171172Smlaier			return (1);
4489171172Smlaier		}
4490171172Smlaier	return (0);
4491171172Smlaier}
4492171172Smlaier
4493171172Smlaierint
4494130617Smlaierdisallow_alias(struct node_host *h, const char *fmt)
4495130617Smlaier{
4496130617Smlaier	for (; h != NULL; h = h->next)
4497130617Smlaier		if (DYNIF_MULTIADDR(h->addr)) {
4498130617Smlaier			yyerror(fmt, h->addr.v.tblname);
4499130617Smlaier			return (1);
4500130617Smlaier		}
4501130617Smlaier	return (0);
4502130617Smlaier}
4503130617Smlaier
4504130617Smlaierint
4505171172Smlaierrule_consistent(struct pf_rule *r, int anchor_call)
4506126353Smlaier{
4507126353Smlaier	int	problems = 0;
4508126353Smlaier
4509126353Smlaier	switch (r->action) {
4510126353Smlaier	case PF_PASS:
4511126353Smlaier	case PF_DROP:
4512126353Smlaier	case PF_SCRUB:
4513145840Smlaier	case PF_NOSCRUB:
4514171172Smlaier		problems = filter_consistent(r, anchor_call);
4515126353Smlaier		break;
4516126353Smlaier	case PF_NAT:
4517126353Smlaier	case PF_NONAT:
4518126353Smlaier		problems = nat_consistent(r);
4519126353Smlaier		break;
4520126353Smlaier	case PF_RDR:
4521126353Smlaier	case PF_NORDR:
4522126353Smlaier		problems = rdr_consistent(r);
4523126353Smlaier		break;
4524126353Smlaier	case PF_BINAT:
4525126353Smlaier	case PF_NOBINAT:
4526126353Smlaier	default:
4527126353Smlaier		break;
4528126353Smlaier	}
4529126353Smlaier	return (problems);
4530126353Smlaier}
4531126353Smlaier
4532126353Smlaierint
4533171172Smlaierfilter_consistent(struct pf_rule *r, int anchor_call)
4534126353Smlaier{
4535126353Smlaier	int	problems = 0;
4536126353Smlaier
4537126353Smlaier	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
4538126353Smlaier	    (r->src.port_op || r->dst.port_op)) {
4539126353Smlaier		yyerror("port only applies to tcp/udp");
4540126353Smlaier		problems++;
4541126353Smlaier	}
4542126353Smlaier	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
4543126353Smlaier	    (r->type || r->code)) {
4544126353Smlaier		yyerror("icmp-type/code only applies to icmp");
4545126353Smlaier		problems++;
4546126353Smlaier	}
4547126353Smlaier	if (!r->af && (r->type || r->code)) {
4548126353Smlaier		yyerror("must indicate address family with icmp-type/code");
4549126353Smlaier		problems++;
4550126353Smlaier	}
4551145840Smlaier	if (r->overload_tblname[0] &&
4552145840Smlaier	    r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
4553145840Smlaier		yyerror("'overload' requires 'max-src-conn' "
4554145840Smlaier		    "or 'max-src-conn-rate'");
4555145840Smlaier		problems++;
4556145840Smlaier	}
4557126353Smlaier	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
4558126353Smlaier	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
4559126353Smlaier		yyerror("proto %s doesn't match address family %s",
4560126353Smlaier		    r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
4561126353Smlaier		    r->af == AF_INET ? "inet" : "inet6");
4562126353Smlaier		problems++;
4563126353Smlaier	}
4564126353Smlaier	if (r->allow_opts && r->action != PF_PASS) {
4565126353Smlaier		yyerror("allow-opts can only be specified for pass rules");
4566126353Smlaier		problems++;
4567126353Smlaier	}
4568126353Smlaier	if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
4569126353Smlaier	    r->dst.port_op || r->flagset || r->type || r->code)) {
4570126353Smlaier		yyerror("fragments can be filtered only on IP header fields");
4571126353Smlaier		problems++;
4572126353Smlaier	}
4573126353Smlaier	if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
4574126353Smlaier		yyerror("return-rst can only be applied to TCP rules");
4575126353Smlaier		problems++;
4576126353Smlaier	}
4577130617Smlaier	if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
4578130617Smlaier		yyerror("max-src-nodes requires 'source-track rule'");
4579130617Smlaier		problems++;
4580130617Smlaier	}
4581126353Smlaier	if (r->action == PF_DROP && r->keep_state) {
4582126353Smlaier		yyerror("keep state on block rules doesn't make sense");
4583126353Smlaier		problems++;
4584126353Smlaier	}
4585200930Sdelphij	if (r->rule_flag & PFRULE_STATESLOPPY &&
4586200930Sdelphij	    (r->keep_state == PF_STATE_MODULATE ||
4587200930Sdelphij	    r->keep_state == PF_STATE_SYNPROXY)) {
4588200930Sdelphij		yyerror("sloppy state matching cannot be used with "
4589200930Sdelphij		    "synproxy state or modulate state");
4590200930Sdelphij		problems++;
4591200930Sdelphij	}
4592126353Smlaier	return (-problems);
4593126353Smlaier}
4594126353Smlaier
4595126353Smlaierint
4596126353Smlaiernat_consistent(struct pf_rule *r)
4597126353Smlaier{
4598130617Smlaier	return (0);	/* yeah! */
4599126353Smlaier}
4600126353Smlaier
4601126353Smlaierint
4602126353Smlaierrdr_consistent(struct pf_rule *r)
4603126353Smlaier{
4604126353Smlaier	int			 problems = 0;
4605126353Smlaier
4606126353Smlaier	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
4607126353Smlaier		if (r->src.port_op) {
4608126353Smlaier			yyerror("src port only applies to tcp/udp");
4609126353Smlaier			problems++;
4610126353Smlaier		}
4611126353Smlaier		if (r->dst.port_op) {
4612126353Smlaier			yyerror("dst port only applies to tcp/udp");
4613126353Smlaier			problems++;
4614126353Smlaier		}
4615126353Smlaier		if (r->rpool.proxy_port[0]) {
4616126353Smlaier			yyerror("rpool port only applies to tcp/udp");
4617126353Smlaier			problems++;
4618126353Smlaier		}
4619126353Smlaier	}
4620126353Smlaier	if (r->dst.port_op &&
4621126353Smlaier	    r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
4622126353Smlaier		yyerror("invalid port operator for rdr destination port");
4623126353Smlaier		problems++;
4624126353Smlaier	}
4625126353Smlaier	return (-problems);
4626126353Smlaier}
4627126353Smlaier
4628126353Smlaierint
4629126353Smlaierprocess_tabledef(char *name, struct table_opts *opts)
4630126353Smlaier{
4631126353Smlaier	struct pfr_buffer	 ab;
4632126353Smlaier	struct node_tinit	*ti;
4633126353Smlaier
4634126353Smlaier	bzero(&ab, sizeof(ab));
4635126353Smlaier	ab.pfrb_type = PFRB_ADDRS;
4636126353Smlaier	SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
4637126353Smlaier		if (ti->file)
4638126353Smlaier			if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
4639126353Smlaier				if (errno)
4640126353Smlaier					yyerror("cannot load \"%s\": %s",
4641126353Smlaier					    ti->file, strerror(errno));
4642126353Smlaier				else
4643126353Smlaier					yyerror("file \"%s\" contains bad data",
4644126353Smlaier					    ti->file);
4645126353Smlaier				goto _error;
4646126353Smlaier			}
4647126353Smlaier		if (ti->host)
4648126353Smlaier			if (append_addr_host(&ab, ti->host, 0, 0)) {
4649126353Smlaier				yyerror("cannot create address buffer: %s",
4650126353Smlaier				    strerror(errno));
4651126353Smlaier				goto _error;
4652126353Smlaier			}
4653126353Smlaier	}
4654126353Smlaier	if (pf->opts & PF_OPT_VERBOSE)
4655126353Smlaier		print_tabledef(name, opts->flags, opts->init_addr,
4656126353Smlaier		    &opts->init_nodes);
4657126353Smlaier	if (!(pf->opts & PF_OPT_NOACTION) &&
4658126353Smlaier	    pfctl_define_table(name, opts->flags, opts->init_addr,
4659171172Smlaier	    pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
4660126353Smlaier		yyerror("cannot define table %s: %s", name,
4661126353Smlaier		    pfr_strerror(errno));
4662126353Smlaier		goto _error;
4663126353Smlaier	}
4664126353Smlaier	pf->tdirty = 1;
4665126353Smlaier	pfr_buf_clear(&ab);
4666126353Smlaier	return (0);
4667126353Smlaier_error:
4668126353Smlaier	pfr_buf_clear(&ab);
4669126353Smlaier	return (-1);
4670126353Smlaier}
4671126353Smlaier
4672126353Smlaierstruct keywords {
4673126353Smlaier	const char	*k_name;
4674126353Smlaier	int		 k_val;
4675126353Smlaier};
4676126353Smlaier
4677126353Smlaier/* macro gore, but you should've seen the prior indentation nightmare... */
4678126353Smlaier
4679126353Smlaier#define FREE_LIST(T,r) \
4680126353Smlaier	do { \
4681126353Smlaier		T *p, *node = r; \
4682126353Smlaier		while (node != NULL) { \
4683126353Smlaier			p = node; \
4684126353Smlaier			node = node->next; \
4685126353Smlaier			free(p); \
4686126353Smlaier		} \
4687126353Smlaier	} while (0)
4688126353Smlaier
4689126353Smlaier#define LOOP_THROUGH(T,n,r,C) \
4690126353Smlaier	do { \
4691126353Smlaier		T *n; \
4692126353Smlaier		if (r == NULL) { \
4693126353Smlaier			r = calloc(1, sizeof(T)); \
4694126353Smlaier			if (r == NULL) \
4695126353Smlaier				err(1, "LOOP: calloc"); \
4696126353Smlaier			r->next = NULL; \
4697126353Smlaier		} \
4698126353Smlaier		n = r; \
4699126353Smlaier		while (n != NULL) { \
4700126353Smlaier			do { \
4701126353Smlaier				C; \
4702126353Smlaier			} while (0); \
4703126353Smlaier			n = n->next; \
4704126353Smlaier		} \
4705126353Smlaier	} while (0)
4706126353Smlaier
4707126353Smlaiervoid
4708130617Smlaierexpand_label_str(char *label, size_t len, const char *srch, const char *repl)
4709126353Smlaier{
4710130617Smlaier	char *tmp;
4711126353Smlaier	char *p, *q;
4712126353Smlaier
4713130617Smlaier	if ((tmp = calloc(1, len)) == NULL)
4714130617Smlaier		err(1, "expand_label_str: calloc");
4715126353Smlaier	p = q = label;
4716126353Smlaier	while ((q = strstr(p, srch)) != NULL) {
4717126353Smlaier		*q = '\0';
4718130617Smlaier		if ((strlcat(tmp, p, len) >= len) ||
4719130617Smlaier		    (strlcat(tmp, repl, len) >= len))
4720130617Smlaier			errx(1, "expand_label: label too long");
4721126353Smlaier		q += strlen(srch);
4722126353Smlaier		p = q;
4723126353Smlaier	}
4724130617Smlaier	if (strlcat(tmp, p, len) >= len)
4725130617Smlaier		errx(1, "expand_label: label too long");
4726130617Smlaier	strlcpy(label, tmp, len);	/* always fits */
4727130617Smlaier	free(tmp);
4728126353Smlaier}
4729126353Smlaier
4730126353Smlaiervoid
4731130617Smlaierexpand_label_if(const char *name, char *label, size_t len, const char *ifname)
4732126353Smlaier{
4733126353Smlaier	if (strstr(label, name) != NULL) {
4734126353Smlaier		if (!*ifname)
4735130617Smlaier			expand_label_str(label, len, name, "any");
4736126353Smlaier		else
4737130617Smlaier			expand_label_str(label, len, name, ifname);
4738126353Smlaier	}
4739126353Smlaier}
4740126353Smlaier
4741126353Smlaiervoid
4742130617Smlaierexpand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
4743126353Smlaier    struct node_host *h)
4744126353Smlaier{
4745126353Smlaier	char tmp[64], tmp_not[66];
4746126353Smlaier
4747126353Smlaier	if (strstr(label, name) != NULL) {
4748126353Smlaier		switch (h->addr.type) {
4749126353Smlaier		case PF_ADDR_DYNIFTL:
4750126353Smlaier			snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
4751126353Smlaier			break;
4752126353Smlaier		case PF_ADDR_TABLE:
4753126353Smlaier			snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
4754126353Smlaier			break;
4755126353Smlaier		case PF_ADDR_NOROUTE:
4756126353Smlaier			snprintf(tmp, sizeof(tmp), "no-route");
4757126353Smlaier			break;
4758171172Smlaier		case PF_ADDR_URPFFAILED:
4759171172Smlaier			snprintf(tmp, sizeof(tmp), "urpf-failed");
4760171172Smlaier			break;
4761126353Smlaier		case PF_ADDR_ADDRMASK:
4762126353Smlaier			if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
4763126353Smlaier			    PF_AZERO(&h->addr.v.a.mask, af)))
4764126353Smlaier				snprintf(tmp, sizeof(tmp), "any");
4765126353Smlaier			else {
4766126353Smlaier				char	a[48];
4767126353Smlaier				int	bits;
4768126353Smlaier
4769126353Smlaier				if (inet_ntop(af, &h->addr.v.a.addr, a,
4770126353Smlaier				    sizeof(a)) == NULL)
4771126353Smlaier					snprintf(tmp, sizeof(tmp), "?");
4772126353Smlaier				else {
4773126353Smlaier					bits = unmask(&h->addr.v.a.mask, af);
4774126353Smlaier					if ((af == AF_INET && bits < 32) ||
4775126353Smlaier					    (af == AF_INET6 && bits < 128))
4776126353Smlaier						snprintf(tmp, sizeof(tmp),
4777130617Smlaier						    "%s/%d", a, bits);
4778126353Smlaier					else
4779126353Smlaier						snprintf(tmp, sizeof(tmp),
4780126353Smlaier						    "%s", a);
4781126353Smlaier				}
4782126353Smlaier			}
4783126353Smlaier			break;
4784126353Smlaier		default:
4785126353Smlaier			snprintf(tmp, sizeof(tmp), "?");
4786126353Smlaier			break;
4787126353Smlaier		}
4788126353Smlaier
4789126353Smlaier		if (h->not) {
4790126353Smlaier			snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
4791130617Smlaier			expand_label_str(label, len, name, tmp_not);
4792126353Smlaier		} else
4793130617Smlaier			expand_label_str(label, len, name, tmp);
4794126353Smlaier	}
4795126353Smlaier}
4796126353Smlaier
4797126353Smlaiervoid
4798130617Smlaierexpand_label_port(const char *name, char *label, size_t len,
4799130617Smlaier    struct node_port *port)
4800126353Smlaier{
4801126353Smlaier	char	 a1[6], a2[6], op[13] = "";
4802126353Smlaier
4803126353Smlaier	if (strstr(label, name) != NULL) {
4804126353Smlaier		snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
4805126353Smlaier		snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
4806126353Smlaier		if (!port->op)
4807126353Smlaier			;
4808126353Smlaier		else if (port->op == PF_OP_IRG)
4809126353Smlaier			snprintf(op, sizeof(op), "%s><%s", a1, a2);
4810126353Smlaier		else if (port->op == PF_OP_XRG)
4811126353Smlaier			snprintf(op, sizeof(op), "%s<>%s", a1, a2);
4812126353Smlaier		else if (port->op == PF_OP_EQ)
4813126353Smlaier			snprintf(op, sizeof(op), "%s", a1);
4814126353Smlaier		else if (port->op == PF_OP_NE)
4815126353Smlaier			snprintf(op, sizeof(op), "!=%s", a1);
4816126353Smlaier		else if (port->op == PF_OP_LT)
4817126353Smlaier			snprintf(op, sizeof(op), "<%s", a1);
4818126353Smlaier		else if (port->op == PF_OP_LE)
4819126353Smlaier			snprintf(op, sizeof(op), "<=%s", a1);
4820126353Smlaier		else if (port->op == PF_OP_GT)
4821126353Smlaier			snprintf(op, sizeof(op), ">%s", a1);
4822126353Smlaier		else if (port->op == PF_OP_GE)
4823126353Smlaier			snprintf(op, sizeof(op), ">=%s", a1);
4824130617Smlaier		expand_label_str(label, len, name, op);
4825126353Smlaier	}
4826126353Smlaier}
4827126353Smlaier
4828126353Smlaiervoid
4829130617Smlaierexpand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
4830126353Smlaier{
4831126353Smlaier	struct protoent *pe;
4832126353Smlaier	char n[4];
4833126353Smlaier
4834126353Smlaier	if (strstr(label, name) != NULL) {
4835126353Smlaier		pe = getprotobynumber(proto);
4836126353Smlaier		if (pe != NULL)
4837130617Smlaier			expand_label_str(label, len, name, pe->p_name);
4838126353Smlaier		else {
4839126353Smlaier			snprintf(n, sizeof(n), "%u", proto);
4840130617Smlaier			expand_label_str(label, len, name, n);
4841126353Smlaier		}
4842126353Smlaier	}
4843126353Smlaier}
4844126353Smlaier
4845126353Smlaiervoid
4846130617Smlaierexpand_label_nr(const char *name, char *label, size_t len)
4847126353Smlaier{
4848126353Smlaier	char n[11];
4849126353Smlaier
4850126353Smlaier	if (strstr(label, name) != NULL) {
4851171172Smlaier		snprintf(n, sizeof(n), "%u", pf->anchor->match);
4852130617Smlaier		expand_label_str(label, len, name, n);
4853126353Smlaier	}
4854126353Smlaier}
4855126353Smlaier
4856126353Smlaiervoid
4857130617Smlaierexpand_label(char *label, size_t len, const char *ifname, sa_family_t af,
4858126353Smlaier    struct node_host *src_host, struct node_port *src_port,
4859126353Smlaier    struct node_host *dst_host, struct node_port *dst_port,
4860126353Smlaier    u_int8_t proto)
4861126353Smlaier{
4862130617Smlaier	expand_label_if("$if", label, len, ifname);
4863130617Smlaier	expand_label_addr("$srcaddr", label, len, af, src_host);
4864130617Smlaier	expand_label_addr("$dstaddr", label, len, af, dst_host);
4865130617Smlaier	expand_label_port("$srcport", label, len, src_port);
4866130617Smlaier	expand_label_port("$dstport", label, len, dst_port);
4867130617Smlaier	expand_label_proto("$proto", label, len, proto);
4868130617Smlaier	expand_label_nr("$nr", label, len);
4869126353Smlaier}
4870126353Smlaier
4871126353Smlaierint
4872126353Smlaierexpand_altq(struct pf_altq *a, struct node_if *interfaces,
4873126353Smlaier    struct node_queue *nqueues, struct node_queue_bw bwspec,
4874126353Smlaier    struct node_queue_opt *opts)
4875126353Smlaier{
4876126353Smlaier	struct pf_altq		 pa, pb;
4877126353Smlaier	char			 qname[PF_QNAME_SIZE];
4878126353Smlaier	struct node_queue	*n;
4879126353Smlaier	struct node_queue_bw	 bw;
4880126353Smlaier	int			 errs = 0;
4881126353Smlaier
4882126353Smlaier	if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
4883126353Smlaier		FREE_LIST(struct node_if, interfaces);
4884298133Sloos		if (nqueues)
4885298133Sloos			FREE_LIST(struct node_queue, nqueues);
4886126353Smlaier		return (0);
4887126353Smlaier	}
4888126353Smlaier
4889126353Smlaier	LOOP_THROUGH(struct node_if, interface, interfaces,
4890126353Smlaier		memcpy(&pa, a, sizeof(struct pf_altq));
4891126353Smlaier		if (strlcpy(pa.ifname, interface->ifname,
4892126353Smlaier		    sizeof(pa.ifname)) >= sizeof(pa.ifname))
4893126353Smlaier			errx(1, "expand_altq: strlcpy");
4894126353Smlaier
4895126353Smlaier		if (interface->not) {
4896126353Smlaier			yyerror("altq on ! <interface> is not supported");
4897126353Smlaier			errs++;
4898126353Smlaier		} else {
4899126353Smlaier			if (eval_pfaltq(pf, &pa, &bwspec, opts))
4900126353Smlaier				errs++;
4901126353Smlaier			else
4902126353Smlaier				if (pfctl_add_altq(pf, &pa))
4903126353Smlaier					errs++;
4904126353Smlaier
4905126353Smlaier			if (pf->opts & PF_OPT_VERBOSE) {
4906126353Smlaier				print_altq(&pf->paltq->altq, 0,
4907126353Smlaier				    &bwspec, opts);
4908126353Smlaier				if (nqueues && nqueues->tail) {
4909126353Smlaier					printf("queue { ");
4910126353Smlaier					LOOP_THROUGH(struct node_queue, queue,
4911126353Smlaier					    nqueues,
4912126353Smlaier						printf("%s ",
4913126353Smlaier						    queue->queue);
4914126353Smlaier					);
4915126353Smlaier					printf("}");
4916126353Smlaier				}
4917126353Smlaier				printf("\n");
4918126353Smlaier			}
4919126353Smlaier
4920126353Smlaier			if (pa.scheduler == ALTQT_CBQ ||
4921126353Smlaier			    pa.scheduler == ALTQT_HFSC) {
4922126353Smlaier				/* now create a root queue */
4923126353Smlaier				memset(&pb, 0, sizeof(struct pf_altq));
4924126353Smlaier				if (strlcpy(qname, "root_", sizeof(qname)) >=
4925126353Smlaier				    sizeof(qname))
4926126353Smlaier					errx(1, "expand_altq: strlcpy");
4927126353Smlaier				if (strlcat(qname, interface->ifname,
4928126353Smlaier				    sizeof(qname)) >= sizeof(qname))
4929126353Smlaier					errx(1, "expand_altq: strlcat");
4930126353Smlaier				if (strlcpy(pb.qname, qname,
4931126353Smlaier				    sizeof(pb.qname)) >= sizeof(pb.qname))
4932126353Smlaier					errx(1, "expand_altq: strlcpy");
4933126353Smlaier				if (strlcpy(pb.ifname, interface->ifname,
4934126353Smlaier				    sizeof(pb.ifname)) >= sizeof(pb.ifname))
4935126353Smlaier					errx(1, "expand_altq: strlcpy");
4936126353Smlaier				pb.qlimit = pa.qlimit;
4937126353Smlaier				pb.scheduler = pa.scheduler;
4938126353Smlaier				bw.bw_absolute = pa.ifbandwidth;
4939126353Smlaier				bw.bw_percent = 0;
4940126353Smlaier				if (eval_pfqueue(pf, &pb, &bw, opts))
4941126353Smlaier					errs++;
4942126353Smlaier				else
4943126353Smlaier					if (pfctl_add_altq(pf, &pb))
4944126353Smlaier						errs++;
4945126353Smlaier			}
4946126353Smlaier
4947126353Smlaier			LOOP_THROUGH(struct node_queue, queue, nqueues,
4948126353Smlaier				n = calloc(1, sizeof(struct node_queue));
4949126353Smlaier				if (n == NULL)
4950126353Smlaier					err(1, "expand_altq: calloc");
4951126353Smlaier				if (pa.scheduler == ALTQT_CBQ ||
4952126353Smlaier				    pa.scheduler == ALTQT_HFSC)
4953126353Smlaier					if (strlcpy(n->parent, qname,
4954126353Smlaier					    sizeof(n->parent)) >=
4955126353Smlaier					    sizeof(n->parent))
4956126353Smlaier						errx(1, "expand_altq: strlcpy");
4957126353Smlaier				if (strlcpy(n->queue, queue->queue,
4958126353Smlaier				    sizeof(n->queue)) >= sizeof(n->queue))
4959126353Smlaier					errx(1, "expand_altq: strlcpy");
4960126353Smlaier				if (strlcpy(n->ifname, interface->ifname,
4961126353Smlaier				    sizeof(n->ifname)) >= sizeof(n->ifname))
4962126353Smlaier					errx(1, "expand_altq: strlcpy");
4963126353Smlaier				n->scheduler = pa.scheduler;
4964126353Smlaier				n->next = NULL;
4965126353Smlaier				n->tail = n;
4966126353Smlaier				if (queues == NULL)
4967126353Smlaier					queues = n;
4968126353Smlaier				else {
4969126353Smlaier					queues->tail->next = n;
4970126353Smlaier					queues->tail = n;
4971126353Smlaier				}
4972126353Smlaier			);
4973126353Smlaier		}
4974126353Smlaier	);
4975126353Smlaier	FREE_LIST(struct node_if, interfaces);
4976298133Sloos	if (nqueues)
4977298133Sloos		FREE_LIST(struct node_queue, nqueues);
4978126353Smlaier
4979126353Smlaier	return (errs);
4980126353Smlaier}
4981126353Smlaier
4982126353Smlaierint
4983126353Smlaierexpand_queue(struct pf_altq *a, struct node_if *interfaces,
4984126353Smlaier    struct node_queue *nqueues, struct node_queue_bw bwspec,
4985126353Smlaier    struct node_queue_opt *opts)
4986126353Smlaier{
4987126353Smlaier	struct node_queue	*n, *nq;
4988126353Smlaier	struct pf_altq		 pa;
4989126353Smlaier	u_int8_t		 found = 0;
4990126353Smlaier	u_int8_t		 errs = 0;
4991126353Smlaier
4992126353Smlaier	if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
4993126353Smlaier		FREE_LIST(struct node_queue, nqueues);
4994126353Smlaier		return (0);
4995126353Smlaier	}
4996126353Smlaier
4997126353Smlaier	if (queues == NULL) {
4998126353Smlaier		yyerror("queue %s has no parent", a->qname);
4999126353Smlaier		FREE_LIST(struct node_queue, nqueues);
5000126353Smlaier		return (1);
5001126353Smlaier	}
5002126353Smlaier
5003126353Smlaier	LOOP_THROUGH(struct node_if, interface, interfaces,
5004126353Smlaier		LOOP_THROUGH(struct node_queue, tqueue, queues,
5005126353Smlaier			if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
5006126353Smlaier			    (interface->ifname[0] == 0 ||
5007126353Smlaier			    (!interface->not && !strncmp(interface->ifname,
5008126353Smlaier			    tqueue->ifname, IFNAMSIZ)) ||
5009126353Smlaier			    (interface->not && strncmp(interface->ifname,
5010126353Smlaier			    tqueue->ifname, IFNAMSIZ)))) {
5011126353Smlaier				/* found ourself in queues */
5012126353Smlaier				found++;
5013126353Smlaier
5014126353Smlaier				memcpy(&pa, a, sizeof(struct pf_altq));
5015126353Smlaier
5016126353Smlaier				if (pa.scheduler != ALTQT_NONE &&
5017126353Smlaier				    pa.scheduler != tqueue->scheduler) {
5018126353Smlaier					yyerror("exactly one scheduler type "
5019126353Smlaier					    "per interface allowed");
5020126353Smlaier					return (1);
5021126353Smlaier				}
5022126353Smlaier				pa.scheduler = tqueue->scheduler;
5023126353Smlaier
5024126353Smlaier				/* scheduler dependent error checking */
5025126353Smlaier				switch (pa.scheduler) {
5026126353Smlaier				case ALTQT_PRIQ:
5027126353Smlaier					if (nqueues != NULL) {
5028126353Smlaier						yyerror("priq queues cannot "
5029126353Smlaier						    "have child queues");
5030126353Smlaier						return (1);
5031126353Smlaier					}
5032126353Smlaier					if (bwspec.bw_absolute > 0 ||
5033126353Smlaier					    bwspec.bw_percent < 100) {
5034126353Smlaier						yyerror("priq doesn't take "
5035126353Smlaier						    "bandwidth");
5036126353Smlaier						return (1);
5037126353Smlaier					}
5038126353Smlaier					break;
5039126353Smlaier				default:
5040126353Smlaier					break;
5041126353Smlaier				}
5042126353Smlaier
5043126353Smlaier				if (strlcpy(pa.ifname, tqueue->ifname,
5044126353Smlaier				    sizeof(pa.ifname)) >= sizeof(pa.ifname))
5045126353Smlaier					errx(1, "expand_queue: strlcpy");
5046126353Smlaier				if (strlcpy(pa.parent, tqueue->parent,
5047126353Smlaier				    sizeof(pa.parent)) >= sizeof(pa.parent))
5048126353Smlaier					errx(1, "expand_queue: strlcpy");
5049126353Smlaier
5050126353Smlaier				if (eval_pfqueue(pf, &pa, &bwspec, opts))
5051126353Smlaier					errs++;
5052126353Smlaier				else
5053126353Smlaier					if (pfctl_add_altq(pf, &pa))
5054126353Smlaier						errs++;
5055126353Smlaier
5056126353Smlaier				for (nq = nqueues; nq != NULL; nq = nq->next) {
5057126353Smlaier					if (!strcmp(a->qname, nq->queue)) {
5058126353Smlaier						yyerror("queue cannot have "
5059126353Smlaier						    "itself as child");
5060126353Smlaier						errs++;
5061126353Smlaier						continue;
5062126353Smlaier					}
5063126353Smlaier					n = calloc(1,
5064126353Smlaier					    sizeof(struct node_queue));
5065126353Smlaier					if (n == NULL)
5066126353Smlaier						err(1, "expand_queue: calloc");
5067126353Smlaier					if (strlcpy(n->parent, a->qname,
5068126353Smlaier					    sizeof(n->parent)) >=
5069126353Smlaier					    sizeof(n->parent))
5070126353Smlaier						errx(1, "expand_queue strlcpy");
5071126353Smlaier					if (strlcpy(n->queue, nq->queue,
5072126353Smlaier					    sizeof(n->queue)) >=
5073126353Smlaier					    sizeof(n->queue))
5074126353Smlaier						errx(1, "expand_queue strlcpy");
5075126353Smlaier					if (strlcpy(n->ifname, tqueue->ifname,
5076126353Smlaier					    sizeof(n->ifname)) >=
5077126353Smlaier					    sizeof(n->ifname))
5078126353Smlaier						errx(1, "expand_queue strlcpy");
5079126353Smlaier					n->scheduler = tqueue->scheduler;
5080126353Smlaier					n->next = NULL;
5081126353Smlaier					n->tail = n;
5082126353Smlaier					if (queues == NULL)
5083126353Smlaier						queues = n;
5084126353Smlaier					else {
5085126353Smlaier						queues->tail->next = n;
5086126353Smlaier						queues->tail = n;
5087126353Smlaier					}
5088126353Smlaier				}
5089126353Smlaier				if ((pf->opts & PF_OPT_VERBOSE) && (
5090126353Smlaier				    (found == 1 && interface->ifname[0] == 0) ||
5091126353Smlaier				    (found > 0 && interface->ifname[0] != 0))) {
5092126353Smlaier					print_queue(&pf->paltq->altq, 0,
5093126353Smlaier					    &bwspec, interface->ifname[0] != 0,
5094126353Smlaier					    opts);
5095126353Smlaier					if (nqueues && nqueues->tail) {
5096126353Smlaier						printf("{ ");
5097126353Smlaier						LOOP_THROUGH(struct node_queue,
5098126353Smlaier						    queue, nqueues,
5099126353Smlaier							printf("%s ",
5100126353Smlaier							    queue->queue);
5101126353Smlaier						);
5102126353Smlaier						printf("}");
5103126353Smlaier					}
5104126353Smlaier					printf("\n");
5105126353Smlaier				}
5106126353Smlaier			}
5107126353Smlaier		);
5108126353Smlaier	);
5109126353Smlaier
5110126353Smlaier	FREE_LIST(struct node_queue, nqueues);
5111126353Smlaier	FREE_LIST(struct node_if, interfaces);
5112126353Smlaier
5113126353Smlaier	if (!found) {
5114126353Smlaier		yyerror("queue %s has no parent", a->qname);
5115126353Smlaier		errs++;
5116126353Smlaier	}
5117126353Smlaier
5118126353Smlaier	if (errs)
5119126353Smlaier		return (1);
5120126353Smlaier	else
5121126353Smlaier		return (0);
5122126353Smlaier}
5123126353Smlaier
5124126353Smlaiervoid
5125126353Smlaierexpand_rule(struct pf_rule *r,
5126126353Smlaier    struct node_if *interfaces, struct node_host *rpool_hosts,
5127126353Smlaier    struct node_proto *protos, struct node_os *src_oses,
5128126353Smlaier    struct node_host *src_hosts, struct node_port *src_ports,
5129126353Smlaier    struct node_host *dst_hosts, struct node_port *dst_ports,
5130145840Smlaier    struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
5131145840Smlaier    const char *anchor_call)
5132126353Smlaier{
5133126353Smlaier	sa_family_t		 af = r->af;
5134126353Smlaier	int			 added = 0, error = 0;
5135126353Smlaier	char			 ifname[IF_NAMESIZE];
5136126353Smlaier	char			 label[PF_RULE_LABEL_SIZE];
5137130617Smlaier	char			 tagname[PF_TAG_NAME_SIZE];
5138130617Smlaier	char			 match_tagname[PF_TAG_NAME_SIZE];
5139126353Smlaier	struct pf_pooladdr	*pa;
5140126353Smlaier	struct node_host	*h;
5141130617Smlaier	u_int8_t		 flags, flagset, keep_state;
5142126353Smlaier
5143126353Smlaier	if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
5144126353Smlaier		errx(1, "expand_rule: strlcpy");
5145130617Smlaier	if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
5146130617Smlaier		errx(1, "expand_rule: strlcpy");
5147130617Smlaier	if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
5148130617Smlaier	    sizeof(match_tagname))
5149130617Smlaier		errx(1, "expand_rule: strlcpy");
5150126353Smlaier	flags = r->flags;
5151126353Smlaier	flagset = r->flagset;
5152130617Smlaier	keep_state = r->keep_state;
5153126353Smlaier
5154126353Smlaier	LOOP_THROUGH(struct node_if, interface, interfaces,
5155126353Smlaier	LOOP_THROUGH(struct node_proto, proto, protos,
5156126353Smlaier	LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
5157126353Smlaier	LOOP_THROUGH(struct node_host, src_host, src_hosts,
5158126353Smlaier	LOOP_THROUGH(struct node_port, src_port, src_ports,
5159126353Smlaier	LOOP_THROUGH(struct node_os, src_os, src_oses,
5160126353Smlaier	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
5161126353Smlaier	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
5162126353Smlaier	LOOP_THROUGH(struct node_uid, uid, uids,
5163126353Smlaier	LOOP_THROUGH(struct node_gid, gid, gids,
5164126353Smlaier
5165126353Smlaier		r->af = af;
5166126353Smlaier		/* for link-local IPv6 address, interface must match up */
5167126353Smlaier		if ((r->af && src_host->af && r->af != src_host->af) ||
5168126353Smlaier		    (r->af && dst_host->af && r->af != dst_host->af) ||
5169126353Smlaier		    (src_host->af && dst_host->af &&
5170126353Smlaier		    src_host->af != dst_host->af) ||
5171126353Smlaier		    (src_host->ifindex && dst_host->ifindex &&
5172126353Smlaier		    src_host->ifindex != dst_host->ifindex) ||
5173130617Smlaier		    (src_host->ifindex && *interface->ifname &&
5174126353Smlaier		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
5175130617Smlaier		    (dst_host->ifindex && *interface->ifname &&
5176126353Smlaier		    dst_host->ifindex != if_nametoindex(interface->ifname)))
5177126353Smlaier			continue;
5178126353Smlaier		if (!r->af && src_host->af)
5179126353Smlaier			r->af = src_host->af;
5180126353Smlaier		else if (!r->af && dst_host->af)
5181126353Smlaier			r->af = dst_host->af;
5182126353Smlaier
5183130617Smlaier		if (*interface->ifname)
5184145840Smlaier			strlcpy(r->ifname, interface->ifname,
5185145840Smlaier			    sizeof(r->ifname));
5186130617Smlaier		else if (if_indextoname(src_host->ifindex, ifname))
5187145840Smlaier			strlcpy(r->ifname, ifname, sizeof(r->ifname));
5188126353Smlaier		else if (if_indextoname(dst_host->ifindex, ifname))
5189145840Smlaier			strlcpy(r->ifname, ifname, sizeof(r->ifname));
5190126353Smlaier		else
5191130617Smlaier			memset(r->ifname, '\0', sizeof(r->ifname));
5192126353Smlaier
5193126353Smlaier		if (strlcpy(r->label, label, sizeof(r->label)) >=
5194126353Smlaier		    sizeof(r->label))
5195126353Smlaier			errx(1, "expand_rule: strlcpy");
5196130617Smlaier		if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
5197130617Smlaier		    sizeof(r->tagname))
5198130617Smlaier			errx(1, "expand_rule: strlcpy");
5199130617Smlaier		if (strlcpy(r->match_tagname, match_tagname,
5200130617Smlaier		    sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
5201130617Smlaier			errx(1, "expand_rule: strlcpy");
5202130617Smlaier		expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
5203130617Smlaier		    src_host, src_port, dst_host, dst_port, proto->proto);
5204130617Smlaier		expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
5205130617Smlaier		    src_host, src_port, dst_host, dst_port, proto->proto);
5206130617Smlaier		expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
5207130617Smlaier		    r->af, src_host, src_port, dst_host, dst_port,
5208130617Smlaier		    proto->proto);
5209126353Smlaier
5210126353Smlaier		error += check_netmask(src_host, r->af);
5211126353Smlaier		error += check_netmask(dst_host, r->af);
5212126353Smlaier
5213126353Smlaier		r->ifnot = interface->not;
5214126353Smlaier		r->proto = proto->proto;
5215126353Smlaier		r->src.addr = src_host->addr;
5216145840Smlaier		r->src.neg = src_host->not;
5217126353Smlaier		r->src.port[0] = src_port->port[0];
5218126353Smlaier		r->src.port[1] = src_port->port[1];
5219126353Smlaier		r->src.port_op = src_port->op;
5220126353Smlaier		r->dst.addr = dst_host->addr;
5221145840Smlaier		r->dst.neg = dst_host->not;
5222126353Smlaier		r->dst.port[0] = dst_port->port[0];
5223126353Smlaier		r->dst.port[1] = dst_port->port[1];
5224126353Smlaier		r->dst.port_op = dst_port->op;
5225126353Smlaier		r->uid.op = uid->op;
5226126353Smlaier		r->uid.uid[0] = uid->uid[0];
5227126353Smlaier		r->uid.uid[1] = uid->uid[1];
5228126353Smlaier		r->gid.op = gid->op;
5229126353Smlaier		r->gid.gid[0] = gid->gid[0];
5230126353Smlaier		r->gid.gid[1] = gid->gid[1];
5231126353Smlaier		r->type = icmp_type->type;
5232126353Smlaier		r->code = icmp_type->code;
5233126353Smlaier
5234130617Smlaier		if ((keep_state == PF_STATE_MODULATE ||
5235130617Smlaier		    keep_state == PF_STATE_SYNPROXY) &&
5236130617Smlaier		    r->proto && r->proto != IPPROTO_TCP)
5237130617Smlaier			r->keep_state = PF_STATE_NORMAL;
5238130617Smlaier		else
5239130617Smlaier			r->keep_state = keep_state;
5240130617Smlaier
5241126353Smlaier		if (r->proto && r->proto != IPPROTO_TCP) {
5242126353Smlaier			r->flags = 0;
5243126353Smlaier			r->flagset = 0;
5244126353Smlaier		} else {
5245126353Smlaier			r->flags = flags;
5246126353Smlaier			r->flagset = flagset;
5247126353Smlaier		}
5248126353Smlaier		if (icmp_type->proto && r->proto != icmp_type->proto) {
5249126353Smlaier			yyerror("icmp-type mismatch");
5250126353Smlaier			error++;
5251126353Smlaier		}
5252126353Smlaier
5253126353Smlaier		if (src_os && src_os->os) {
5254126353Smlaier			r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
5255126353Smlaier			if ((pf->opts & PF_OPT_VERBOSE2) &&
5256126353Smlaier			    r->os_fingerprint == PF_OSFP_NOMATCH)
5257126353Smlaier				fprintf(stderr,
5258126353Smlaier				    "warning: unknown '%s' OS fingerprint\n",
5259126353Smlaier				    src_os->os);
5260126353Smlaier		} else {
5261126353Smlaier			r->os_fingerprint = PF_OSFP_ANY;
5262126353Smlaier		}
5263126353Smlaier
5264126353Smlaier		TAILQ_INIT(&r->rpool.list);
5265126353Smlaier		for (h = rpool_hosts; h != NULL; h = h->next) {
5266126353Smlaier			pa = calloc(1, sizeof(struct pf_pooladdr));
5267126353Smlaier			if (pa == NULL)
5268126353Smlaier				err(1, "expand_rule: calloc");
5269126353Smlaier			pa->addr = h->addr;
5270126353Smlaier			if (h->ifname != NULL) {
5271126353Smlaier				if (strlcpy(pa->ifname, h->ifname,
5272126353Smlaier				    sizeof(pa->ifname)) >=
5273126353Smlaier				    sizeof(pa->ifname))
5274126353Smlaier					errx(1, "expand_rule: strlcpy");
5275126353Smlaier			} else
5276126353Smlaier				pa->ifname[0] = 0;
5277126353Smlaier			TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
5278126353Smlaier		}
5279126353Smlaier
5280171172Smlaier		if (rule_consistent(r, anchor_call[0]) < 0 || error)
5281126353Smlaier			yyerror("skipping rule due to errors");
5282126353Smlaier		else {
5283171172Smlaier			r->nr = pf->astack[pf->asd]->match++;
5284145840Smlaier			pfctl_add_rule(pf, r, anchor_call);
5285126353Smlaier			added++;
5286126353Smlaier		}
5287126353Smlaier
5288126353Smlaier	))))))))));
5289126353Smlaier
5290126353Smlaier	FREE_LIST(struct node_if, interfaces);
5291126353Smlaier	FREE_LIST(struct node_proto, protos);
5292126353Smlaier	FREE_LIST(struct node_host, src_hosts);
5293126353Smlaier	FREE_LIST(struct node_port, src_ports);
5294126353Smlaier	FREE_LIST(struct node_os, src_oses);
5295126353Smlaier	FREE_LIST(struct node_host, dst_hosts);
5296126353Smlaier	FREE_LIST(struct node_port, dst_ports);
5297126353Smlaier	FREE_LIST(struct node_uid, uids);
5298126353Smlaier	FREE_LIST(struct node_gid, gids);
5299126353Smlaier	FREE_LIST(struct node_icmp, icmp_types);
5300126353Smlaier	FREE_LIST(struct node_host, rpool_hosts);
5301126353Smlaier
5302126353Smlaier	if (!added)
5303126353Smlaier		yyerror("rule expands to no valid combination");
5304126353Smlaier}
5305126353Smlaier
5306145840Smlaierint
5307145840Smlaierexpand_skip_interface(struct node_if *interfaces)
5308145840Smlaier{
5309145840Smlaier	int	errs = 0;
5310145840Smlaier
5311145840Smlaier	if (!interfaces || (!interfaces->next && !interfaces->not &&
5312145840Smlaier	    !strcmp(interfaces->ifname, "none"))) {
5313145840Smlaier		if (pf->opts & PF_OPT_VERBOSE)
5314145840Smlaier			printf("set skip on none\n");
5315145840Smlaier		errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
5316145840Smlaier		return (errs);
5317145840Smlaier	}
5318145840Smlaier
5319145840Smlaier	if (pf->opts & PF_OPT_VERBOSE)
5320145840Smlaier		printf("set skip on {");
5321145840Smlaier	LOOP_THROUGH(struct node_if, interface, interfaces,
5322145840Smlaier		if (pf->opts & PF_OPT_VERBOSE)
5323145840Smlaier			printf(" %s", interface->ifname);
5324145840Smlaier		if (interface->not) {
5325145840Smlaier			yyerror("skip on ! <interface> is not supported");
5326145840Smlaier			errs++;
5327145840Smlaier		} else
5328145840Smlaier			errs += pfctl_set_interface_flags(pf,
5329145840Smlaier			    interface->ifname, PFI_IFLAG_SKIP, 1);
5330145840Smlaier	);
5331145840Smlaier	if (pf->opts & PF_OPT_VERBOSE)
5332145840Smlaier		printf(" }\n");
5333145840Smlaier
5334145840Smlaier	FREE_LIST(struct node_if, interfaces);
5335145840Smlaier
5336145840Smlaier	if (errs)
5337145840Smlaier		return (1);
5338145840Smlaier	else
5339145840Smlaier		return (0);
5340145840Smlaier}
5341145840Smlaier
5342126353Smlaier#undef FREE_LIST
5343126353Smlaier#undef LOOP_THROUGH
5344126353Smlaier
5345126353Smlaierint
5346126353Smlaiercheck_rulestate(int desired_state)
5347126353Smlaier{
5348126353Smlaier	if (require_order && (rulestate > desired_state)) {
5349126353Smlaier		yyerror("Rules must be in order: options, normalization, "
5350126353Smlaier		    "queueing, translation, filtering");
5351126353Smlaier		return (1);
5352126353Smlaier	}
5353126353Smlaier	rulestate = desired_state;
5354126353Smlaier	return (0);
5355126353Smlaier}
5356126353Smlaier
5357126353Smlaierint
5358126353Smlaierkw_cmp(const void *k, const void *e)
5359126353Smlaier{
5360126353Smlaier	return (strcmp(k, ((const struct keywords *)e)->k_name));
5361126353Smlaier}
5362126353Smlaier
5363126353Smlaierint
5364126353Smlaierlookup(char *s)
5365126353Smlaier{
5366126353Smlaier	/* this has to be sorted always */
5367126353Smlaier	static const struct keywords keywords[] = {
5368126353Smlaier		{ "all",		ALL},
5369126353Smlaier		{ "allow-opts",		ALLOWOPTS},
5370126353Smlaier		{ "altq",		ALTQ},
5371126353Smlaier		{ "anchor",		ANCHOR},
5372126353Smlaier		{ "antispoof",		ANTISPOOF},
5373126353Smlaier		{ "any",		ANY},
5374126353Smlaier		{ "bandwidth",		BANDWIDTH},
5375126353Smlaier		{ "binat",		BINAT},
5376126353Smlaier		{ "binat-anchor",	BINATANCHOR},
5377126353Smlaier		{ "bitmask",		BITMASK},
5378126353Smlaier		{ "block",		BLOCK},
5379126353Smlaier		{ "block-policy",	BLOCKPOLICY},
5380298091Sloos		{ "buckets",		BUCKETS},
5381126353Smlaier		{ "cbq",		CBQ},
5382126353Smlaier		{ "code",		CODE},
5383298133Sloos		{ "codelq",		CODEL},
5384126353Smlaier		{ "crop",		FRAGCROP},
5385130617Smlaier		{ "debug",		DEBUG},
5386223637Sbz		{ "divert-reply",	DIVERTREPLY},
5387223637Sbz		{ "divert-to",		DIVERTTO},
5388126353Smlaier		{ "drop",		DROP},
5389126353Smlaier		{ "drop-ovl",		FRAGDROP},
5390126353Smlaier		{ "dup-to",		DUPTO},
5391298091Sloos		{ "fairq",		FAIRQ},
5392126353Smlaier		{ "fastroute",		FASTROUTE},
5393126353Smlaier		{ "file",		FILENAME},
5394126353Smlaier		{ "fingerprints",	FINGERPRINTS},
5395126353Smlaier		{ "flags",		FLAGS},
5396130617Smlaier		{ "floating",		FLOATING},
5397145840Smlaier		{ "flush",		FLUSH},
5398126353Smlaier		{ "for",		FOR},
5399126353Smlaier		{ "fragment",		FRAGMENT},
5400126353Smlaier		{ "from",		FROM},
5401130617Smlaier		{ "global",		GLOBAL},
5402126353Smlaier		{ "group",		GROUP},
5403126353Smlaier		{ "hfsc",		HFSC},
5404298091Sloos		{ "hogs",		HOGS},
5405130617Smlaier		{ "hostid",		HOSTID},
5406126353Smlaier		{ "icmp-type",		ICMPTYPE},
5407126353Smlaier		{ "icmp6-type",		ICMP6TYPE},
5408130617Smlaier		{ "if-bound",		IFBOUND},
5409126353Smlaier		{ "in",			IN},
5410223637Sbz		{ "include",		INCLUDE},
5411126353Smlaier		{ "inet",		INET},
5412126353Smlaier		{ "inet6",		INET6},
5413298133Sloos		{ "interval",		INTERVAL},
5414126353Smlaier		{ "keep",		KEEP},
5415126353Smlaier		{ "label",		LABEL},
5416126353Smlaier		{ "limit",		LIMIT},
5417126353Smlaier		{ "linkshare",		LINKSHARE},
5418126353Smlaier		{ "load",		LOAD},
5419126353Smlaier		{ "log",		LOG},
5420126353Smlaier		{ "loginterface",	LOGINTERFACE},
5421126353Smlaier		{ "max",		MAXIMUM},
5422126353Smlaier		{ "max-mss",		MAXMSS},
5423145840Smlaier		{ "max-src-conn",	MAXSRCCONN},
5424145840Smlaier		{ "max-src-conn-rate",	MAXSRCCONNRATE},
5425130617Smlaier		{ "max-src-nodes",	MAXSRCNODES},
5426130617Smlaier		{ "max-src-states",	MAXSRCSTATES},
5427126353Smlaier		{ "min-ttl",		MINTTL},
5428126353Smlaier		{ "modulate",		MODULATE},
5429126353Smlaier		{ "nat",		NAT},
5430126353Smlaier		{ "nat-anchor",		NATANCHOR},
5431126353Smlaier		{ "no",			NO},
5432126353Smlaier		{ "no-df",		NODF},
5433126353Smlaier		{ "no-route",		NOROUTE},
5434130617Smlaier		{ "no-sync",		NOSYNC},
5435126353Smlaier		{ "on",			ON},
5436126353Smlaier		{ "optimization",	OPTIMIZATION},
5437126353Smlaier		{ "os",			OS},
5438126353Smlaier		{ "out",		OUT},
5439145840Smlaier		{ "overload",		OVERLOAD},
5440126353Smlaier		{ "pass",		PASS},
5441126353Smlaier		{ "port",		PORT},
5442126353Smlaier		{ "priority",		PRIORITY},
5443126353Smlaier		{ "priq",		PRIQ},
5444145840Smlaier		{ "probability",	PROBABILITY},
5445126353Smlaier		{ "proto",		PROTO},
5446126353Smlaier		{ "qlimit",		QLIMIT},
5447126353Smlaier		{ "queue",		QUEUE},
5448126353Smlaier		{ "quick",		QUICK},
5449126353Smlaier		{ "random",		RANDOM},
5450126353Smlaier		{ "random-id",		RANDOMID},
5451126353Smlaier		{ "rdr",		RDR},
5452126353Smlaier		{ "rdr-anchor",		RDRANCHOR},
5453126353Smlaier		{ "realtime",		REALTIME},
5454126353Smlaier		{ "reassemble",		REASSEMBLE},
5455126353Smlaier		{ "reply-to",		REPLYTO},
5456126353Smlaier		{ "require-order",	REQUIREORDER},
5457126353Smlaier		{ "return",		RETURN},
5458126353Smlaier		{ "return-icmp",	RETURNICMP},
5459126353Smlaier		{ "return-icmp6",	RETURNICMP6},
5460126353Smlaier		{ "return-rst",		RETURNRST},
5461126353Smlaier		{ "round-robin",	ROUNDROBIN},
5462145840Smlaier		{ "route",		ROUTE},
5463126353Smlaier		{ "route-to",		ROUTETO},
5464171172Smlaier		{ "rtable",		RTABLE},
5465130617Smlaier		{ "rule",		RULE},
5466171172Smlaier		{ "ruleset-optimization",	RULESET_OPTIMIZATION},
5467126353Smlaier		{ "scrub",		SCRUB},
5468126353Smlaier		{ "set",		SET},
5469223637Sbz		{ "set-tos",		SETTOS},
5470145840Smlaier		{ "skip",		SKIP},
5471200930Sdelphij		{ "sloppy",		SLOPPY},
5472126353Smlaier		{ "source-hash",	SOURCEHASH},
5473130617Smlaier		{ "source-track",	SOURCETRACK},
5474126353Smlaier		{ "state",		STATE},
5475223637Sbz		{ "state-defaults",	STATEDEFAULTS},
5476130617Smlaier		{ "state-policy",	STATEPOLICY},
5477126353Smlaier		{ "static-port",	STATICPORT},
5478130617Smlaier		{ "sticky-address",	STICKYADDRESS},
5479126353Smlaier		{ "synproxy",		SYNPROXY},
5480126353Smlaier		{ "table",		TABLE},
5481126353Smlaier		{ "tag",		TAG},
5482126353Smlaier		{ "tagged",		TAGGED},
5483298133Sloos		{ "target",		TARGET},
5484126353Smlaier		{ "tbrsize",		TBRSIZE},
5485126353Smlaier		{ "timeout",		TIMEOUT},
5486126353Smlaier		{ "to",			TO},
5487126353Smlaier		{ "tos",		TOS},
5488126353Smlaier		{ "ttl",		TTL},
5489126353Smlaier		{ "upperlimit",		UPPERLIMIT},
5490171172Smlaier		{ "urpf-failed",	URPFFAILED},
5491126353Smlaier		{ "user",		USER},
5492126353Smlaier	};
5493126353Smlaier	const struct keywords	*p;
5494126353Smlaier
5495126353Smlaier	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
5496126353Smlaier	    sizeof(keywords[0]), kw_cmp);
5497126353Smlaier
5498126353Smlaier	if (p) {
5499126353Smlaier		if (debug > 1)
5500126353Smlaier			fprintf(stderr, "%s: %d\n", s, p->k_val);
5501126353Smlaier		return (p->k_val);
5502126353Smlaier	} else {
5503126353Smlaier		if (debug > 1)
5504126353Smlaier			fprintf(stderr, "string: %s\n", s);
5505126353Smlaier		return (STRING);
5506126353Smlaier	}
5507126353Smlaier}
5508126353Smlaier
5509126353Smlaier#define MAXPUSHBACK	128
5510126353Smlaier
5511126353Smlaierchar	*parsebuf;
5512126353Smlaierint	 parseindex;
5513126353Smlaierchar	 pushback_buffer[MAXPUSHBACK];
5514126353Smlaierint	 pushback_index = 0;
5515126353Smlaier
5516126353Smlaierint
5517223637Sbzlgetc(int quotec)
5518126353Smlaier{
5519223637Sbz	int		c, next;
5520126353Smlaier
5521126353Smlaier	if (parsebuf) {
5522126353Smlaier		/* Read character from the parsebuffer instead of input. */
5523126353Smlaier		if (parseindex >= 0) {
5524126353Smlaier			c = parsebuf[parseindex++];
5525126353Smlaier			if (c != '\0')
5526126353Smlaier				return (c);
5527126353Smlaier			parsebuf = NULL;
5528126353Smlaier		} else
5529126353Smlaier			parseindex++;
5530126353Smlaier	}
5531126353Smlaier
5532126353Smlaier	if (pushback_index)
5533126353Smlaier		return (pushback_buffer[--pushback_index]);
5534126353Smlaier
5535223637Sbz	if (quotec) {
5536223637Sbz		if ((c = getc(file->stream)) == EOF) {
5537223637Sbz			yyerror("reached end of file while parsing quoted string");
5538223637Sbz			if (popfile() == EOF)
5539223637Sbz				return (EOF);
5540223637Sbz			return (quotec);
5541223637Sbz		}
5542223637Sbz		return (c);
5543223637Sbz	}
5544223637Sbz
5545223637Sbz	while ((c = getc(file->stream)) == '\\') {
5546223637Sbz		next = getc(file->stream);
5547126353Smlaier		if (next != '\n') {
5548171172Smlaier			c = next;
5549126353Smlaier			break;
5550126353Smlaier		}
5551223637Sbz		yylval.lineno = file->lineno;
5552223637Sbz		file->lineno++;
5553126353Smlaier	}
5554223637Sbz
5555223637Sbz	while (c == EOF) {
5556223637Sbz		if (popfile() == EOF)
5557223637Sbz			return (EOF);
5558223637Sbz		c = getc(file->stream);
5559126353Smlaier	}
5560126353Smlaier	return (c);
5561126353Smlaier}
5562126353Smlaier
5563126353Smlaierint
5564126353Smlaierlungetc(int c)
5565126353Smlaier{
5566126353Smlaier	if (c == EOF)
5567126353Smlaier		return (EOF);
5568126353Smlaier	if (parsebuf) {
5569126353Smlaier		parseindex--;
5570126353Smlaier		if (parseindex >= 0)
5571126353Smlaier			return (c);
5572126353Smlaier	}
5573126353Smlaier	if (pushback_index < MAXPUSHBACK-1)
5574126353Smlaier		return (pushback_buffer[pushback_index++] = c);
5575126353Smlaier	else
5576126353Smlaier		return (EOF);
5577126353Smlaier}
5578126353Smlaier
5579126353Smlaierint
5580126353Smlaierfindeol(void)
5581126353Smlaier{
5582126353Smlaier	int	c;
5583126353Smlaier
5584126353Smlaier	parsebuf = NULL;
5585126353Smlaier
5586126353Smlaier	/* skip to either EOF or the first real EOL */
5587126353Smlaier	while (1) {
5588223637Sbz		if (pushback_index)
5589223637Sbz			c = pushback_buffer[--pushback_index];
5590223637Sbz		else
5591223637Sbz			c = lgetc(0);
5592126353Smlaier		if (c == '\n') {
5593223637Sbz			file->lineno++;
5594126353Smlaier			break;
5595126353Smlaier		}
5596126353Smlaier		if (c == EOF)
5597126353Smlaier			break;
5598126353Smlaier	}
5599126353Smlaier	return (ERROR);
5600126353Smlaier}
5601126353Smlaier
5602126353Smlaierint
5603126353Smlaieryylex(void)
5604126353Smlaier{
5605126353Smlaier	char	 buf[8096];
5606126353Smlaier	char	*p, *val;
5607223637Sbz	int	 quotec, next, c;
5608126353Smlaier	int	 token;
5609126353Smlaier
5610126353Smlaiertop:
5611126353Smlaier	p = buf;
5612223637Sbz	while ((c = lgetc(0)) == ' ' || c == '\t')
5613126353Smlaier		; /* nothing */
5614126353Smlaier
5615223637Sbz	yylval.lineno = file->lineno;
5616126353Smlaier	if (c == '#')
5617223637Sbz		while ((c = lgetc(0)) != '\n' && c != EOF)
5618126353Smlaier			; /* nothing */
5619126353Smlaier	if (c == '$' && parsebuf == NULL) {
5620126353Smlaier		while (1) {
5621223637Sbz			if ((c = lgetc(0)) == EOF)
5622126353Smlaier				return (0);
5623126353Smlaier
5624126353Smlaier			if (p + 1 >= buf + sizeof(buf) - 1) {
5625126353Smlaier				yyerror("string too long");
5626126353Smlaier				return (findeol());
5627126353Smlaier			}
5628126353Smlaier			if (isalnum(c) || c == '_') {
5629126353Smlaier				*p++ = (char)c;
5630126353Smlaier				continue;
5631126353Smlaier			}
5632126353Smlaier			*p = '\0';
5633126353Smlaier			lungetc(c);
5634126353Smlaier			break;
5635126353Smlaier		}
5636126353Smlaier		val = symget(buf);
5637126353Smlaier		if (val == NULL) {
5638126353Smlaier			yyerror("macro '%s' not defined", buf);
5639126353Smlaier			return (findeol());
5640126353Smlaier		}
5641126353Smlaier		parsebuf = val;
5642126353Smlaier		parseindex = 0;
5643126353Smlaier		goto top;
5644126353Smlaier	}
5645126353Smlaier
5646126353Smlaier	switch (c) {
5647126353Smlaier	case '\'':
5648126353Smlaier	case '"':
5649223637Sbz		quotec = c;
5650126353Smlaier		while (1) {
5651223637Sbz			if ((c = lgetc(quotec)) == EOF)
5652126353Smlaier				return (0);
5653223637Sbz			if (c == '\n') {
5654223637Sbz				file->lineno++;
5655223637Sbz				continue;
5656223637Sbz			} else if (c == '\\') {
5657223637Sbz				if ((next = lgetc(quotec)) == EOF)
5658223637Sbz					return (0);
5659223637Sbz				if (next == quotec || c == ' ' || c == '\t')
5660223637Sbz					c = next;
5661223637Sbz				else if (next == '\n')
5662223637Sbz					continue;
5663223637Sbz				else
5664223637Sbz					lungetc(next);
5665223637Sbz			} else if (c == quotec) {
5666126353Smlaier				*p = '\0';
5667126353Smlaier				break;
5668126353Smlaier			}
5669126353Smlaier			if (p + 1 >= buf + sizeof(buf) - 1) {
5670126353Smlaier				yyerror("string too long");
5671126353Smlaier				return (findeol());
5672126353Smlaier			}
5673126353Smlaier			*p++ = (char)c;
5674126353Smlaier		}
5675126353Smlaier		yylval.v.string = strdup(buf);
5676126353Smlaier		if (yylval.v.string == NULL)
5677126353Smlaier			err(1, "yylex: strdup");
5678126353Smlaier		return (STRING);
5679126353Smlaier	case '<':
5680223637Sbz		next = lgetc(0);
5681126353Smlaier		if (next == '>') {
5682126353Smlaier			yylval.v.i = PF_OP_XRG;
5683126353Smlaier			return (PORTBINARY);
5684126353Smlaier		}
5685126353Smlaier		lungetc(next);
5686126353Smlaier		break;
5687126353Smlaier	case '>':
5688223637Sbz		next = lgetc(0);
5689126353Smlaier		if (next == '<') {
5690126353Smlaier			yylval.v.i = PF_OP_IRG;
5691126353Smlaier			return (PORTBINARY);
5692126353Smlaier		}
5693126353Smlaier		lungetc(next);
5694126353Smlaier		break;
5695126353Smlaier	case '-':
5696223637Sbz		next = lgetc(0);
5697126353Smlaier		if (next == '>')
5698126353Smlaier			return (ARROW);
5699126353Smlaier		lungetc(next);
5700126353Smlaier		break;
5701126353Smlaier	}
5702126353Smlaier
5703223637Sbz#define allowed_to_end_number(x) \
5704223637Sbz	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
5705223637Sbz
5706223637Sbz	if (c == '-' || isdigit(c)) {
5707223637Sbz		do {
5708223637Sbz			*p++ = c;
5709223637Sbz			if ((unsigned)(p-buf) >= sizeof(buf)) {
5710223637Sbz				yyerror("string too long");
5711223637Sbz				return (findeol());
5712223637Sbz			}
5713223637Sbz		} while ((c = lgetc(0)) != EOF && isdigit(c));
5714223637Sbz		lungetc(c);
5715223637Sbz		if (p == buf + 1 && buf[0] == '-')
5716223637Sbz			goto nodigits;
5717223637Sbz		if (c == EOF || allowed_to_end_number(c)) {
5718223637Sbz			const char *errstr = NULL;
5719223637Sbz
5720223637Sbz			*p = '\0';
5721223637Sbz			yylval.v.number = strtonum(buf, LLONG_MIN,
5722223637Sbz			    LLONG_MAX, &errstr);
5723223637Sbz			if (errstr) {
5724223637Sbz				yyerror("\"%s\" invalid number: %s",
5725223637Sbz				    buf, errstr);
5726223637Sbz				return (findeol());
5727223637Sbz			}
5728223637Sbz			return (NUMBER);
5729223637Sbz		} else {
5730223637Sbznodigits:
5731223637Sbz			while (p > buf + 1)
5732223637Sbz				lungetc(*--p);
5733223637Sbz			c = *--p;
5734223637Sbz			if (c == '-')
5735223637Sbz				return (c);
5736223637Sbz		}
5737223637Sbz	}
5738223637Sbz
5739126353Smlaier#define allowed_in_string(x) \
5740126353Smlaier	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
5741126353Smlaier	x != '{' && x != '}' && x != '<' && x != '>' && \
5742126353Smlaier	x != '!' && x != '=' && x != '/' && x != '#' && \
5743126353Smlaier	x != ','))
5744126353Smlaier
5745126353Smlaier	if (isalnum(c) || c == ':' || c == '_') {
5746126353Smlaier		do {
5747126353Smlaier			*p++ = c;
5748126353Smlaier			if ((unsigned)(p-buf) >= sizeof(buf)) {
5749126353Smlaier				yyerror("string too long");
5750126353Smlaier				return (findeol());
5751126353Smlaier			}
5752223637Sbz		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
5753126353Smlaier		lungetc(c);
5754126353Smlaier		*p = '\0';
5755130617Smlaier		if ((token = lookup(buf)) == STRING)
5756130617Smlaier			if ((yylval.v.string = strdup(buf)) == NULL)
5757130617Smlaier				err(1, "yylex: strdup");
5758126353Smlaier		return (token);
5759126353Smlaier	}
5760126353Smlaier	if (c == '\n') {
5761223637Sbz		yylval.lineno = file->lineno;
5762223637Sbz		file->lineno++;
5763126353Smlaier	}
5764126353Smlaier	if (c == EOF)
5765126353Smlaier		return (0);
5766126353Smlaier	return (c);
5767126353Smlaier}
5768126353Smlaier
5769126353Smlaierint
5770223637Sbzcheck_file_secrecy(int fd, const char *fname)
5771126353Smlaier{
5772223637Sbz	struct stat	st;
5773126353Smlaier
5774223637Sbz	if (fstat(fd, &st)) {
5775223637Sbz		warn("cannot stat %s", fname);
5776223637Sbz		return (-1);
5777223637Sbz	}
5778223637Sbz	if (st.st_uid != 0 && st.st_uid != getuid()) {
5779223637Sbz		warnx("%s: owner not root or current user", fname);
5780223637Sbz		return (-1);
5781223637Sbz	}
5782223637Sbz	if (st.st_mode & (S_IRWXG | S_IRWXO)) {
5783223637Sbz		warnx("%s: group/world readable/writeable", fname);
5784223637Sbz		return (-1);
5785223637Sbz	}
5786223637Sbz	return (0);
5787223637Sbz}
5788223637Sbz
5789223637Sbzstruct file *
5790223637Sbzpushfile(const char *name, int secret)
5791223637Sbz{
5792223637Sbz	struct file	*nfile;
5793223637Sbz
5794223637Sbz	if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
5795223637Sbz	    (nfile->name = strdup(name)) == NULL) {
5796223637Sbz		warn("malloc");
5797223637Sbz		return (NULL);
5798223637Sbz	}
5799223637Sbz	if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
5800223637Sbz		nfile->stream = stdin;
5801223637Sbz		free(nfile->name);
5802223637Sbz		if ((nfile->name = strdup("stdin")) == NULL) {
5803223637Sbz			warn("strdup");
5804223637Sbz			free(nfile);
5805223637Sbz			return (NULL);
5806223637Sbz		}
5807223637Sbz	} else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
5808223637Sbz		warn("%s", nfile->name);
5809223637Sbz		free(nfile->name);
5810223637Sbz		free(nfile);
5811223637Sbz		return (NULL);
5812223637Sbz	} else if (secret &&
5813223637Sbz	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
5814223637Sbz		fclose(nfile->stream);
5815223637Sbz		free(nfile->name);
5816223637Sbz		free(nfile);
5817223637Sbz		return (NULL);
5818223637Sbz	}
5819223637Sbz	nfile->lineno = 1;
5820223637Sbz	TAILQ_INSERT_TAIL(&files, nfile, entry);
5821223637Sbz	return (nfile);
5822223637Sbz}
5823223637Sbz
5824223637Sbzint
5825223637Sbzpopfile(void)
5826223637Sbz{
5827223637Sbz	struct file	*prev;
5828223637Sbz
5829223637Sbz	if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
5830223637Sbz		prev->errors += file->errors;
5831223637Sbz		TAILQ_REMOVE(&files, file, entry);
5832223637Sbz		fclose(file->stream);
5833223637Sbz		free(file->name);
5834223637Sbz		free(file);
5835223637Sbz		file = prev;
5836223637Sbz		return (0);
5837223637Sbz	}
5838223637Sbz	return (EOF);
5839223637Sbz}
5840223637Sbz
5841223637Sbzint
5842223637Sbzparse_config(char *filename, struct pfctl *xpf)
5843223637Sbz{
5844223637Sbz	int		 errors = 0;
5845223637Sbz	struct sym	*sym;
5846223637Sbz
5847126353Smlaier	pf = xpf;
5848126353Smlaier	errors = 0;
5849126353Smlaier	rulestate = PFCTL_STATE_NONE;
5850126353Smlaier	returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
5851126353Smlaier	returnicmp6default =
5852126353Smlaier	    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
5853126353Smlaier	blockpolicy = PFRULE_DROP;
5854126353Smlaier	require_order = 1;
5855126353Smlaier
5856223637Sbz	if ((file = pushfile(filename, 0)) == NULL) {
5857223637Sbz		warn("cannot open the main config file!");
5858223637Sbz		return (-1);
5859223637Sbz	}
5860223637Sbz
5861126353Smlaier	yyparse();
5862223637Sbz	errors = file->errors;
5863223637Sbz	popfile();
5864126353Smlaier
5865126353Smlaier	/* Free macros and check which have not been used. */
5866223637Sbz	while ((sym = TAILQ_FIRST(&symhead))) {
5867126353Smlaier		if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
5868126353Smlaier			fprintf(stderr, "warning: macro '%s' not "
5869126353Smlaier			    "used\n", sym->nam);
5870126353Smlaier		free(sym->nam);
5871126353Smlaier		free(sym->val);
5872223637Sbz		TAILQ_REMOVE(&symhead, sym, entry);
5873130617Smlaier		free(sym);
5874126353Smlaier	}
5875126353Smlaier
5876126353Smlaier	return (errors ? -1 : 0);
5877126353Smlaier}
5878126353Smlaier
5879126353Smlaierint
5880126353Smlaiersymset(const char *nam, const char *val, int persist)
5881126353Smlaier{
5882126353Smlaier	struct sym	*sym;
5883126353Smlaier
5884126353Smlaier	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
5885223637Sbz	    sym = TAILQ_NEXT(sym, entry))
5886126353Smlaier		;	/* nothing */
5887126353Smlaier
5888126353Smlaier	if (sym != NULL) {
5889126353Smlaier		if (sym->persist == 1)
5890126353Smlaier			return (0);
5891126353Smlaier		else {
5892126353Smlaier			free(sym->nam);
5893126353Smlaier			free(sym->val);
5894223637Sbz			TAILQ_REMOVE(&symhead, sym, entry);
5895126353Smlaier			free(sym);
5896126353Smlaier		}
5897126353Smlaier	}
5898126353Smlaier	if ((sym = calloc(1, sizeof(*sym))) == NULL)
5899126353Smlaier		return (-1);
5900126353Smlaier
5901126353Smlaier	sym->nam = strdup(nam);
5902126353Smlaier	if (sym->nam == NULL) {
5903126353Smlaier		free(sym);
5904126353Smlaier		return (-1);
5905126353Smlaier	}
5906126353Smlaier	sym->val = strdup(val);
5907126353Smlaier	if (sym->val == NULL) {
5908126353Smlaier		free(sym->nam);
5909126353Smlaier		free(sym);
5910126353Smlaier		return (-1);
5911126353Smlaier	}
5912126353Smlaier	sym->used = 0;
5913126353Smlaier	sym->persist = persist;
5914223637Sbz	TAILQ_INSERT_TAIL(&symhead, sym, entry);
5915126353Smlaier	return (0);
5916126353Smlaier}
5917126353Smlaier
5918126353Smlaierint
5919126353Smlaierpfctl_cmdline_symset(char *s)
5920126353Smlaier{
5921126353Smlaier	char	*sym, *val;
5922126353Smlaier	int	 ret;
5923126353Smlaier
5924126353Smlaier	if ((val = strrchr(s, '=')) == NULL)
5925126353Smlaier		return (-1);
5926126353Smlaier
5927126353Smlaier	if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
5928126353Smlaier		err(1, "pfctl_cmdline_symset: malloc");
5929126353Smlaier
5930126353Smlaier	strlcpy(sym, s, strlen(s) - strlen(val) + 1);
5931126353Smlaier
5932126353Smlaier	ret = symset(sym, val + 1, 1);
5933126353Smlaier	free(sym);
5934126353Smlaier
5935126353Smlaier	return (ret);
5936126353Smlaier}
5937126353Smlaier
5938126353Smlaierchar *
5939126353Smlaiersymget(const char *nam)
5940126353Smlaier{
5941126353Smlaier	struct sym	*sym;
5942126353Smlaier
5943223637Sbz	TAILQ_FOREACH(sym, &symhead, entry)
5944126353Smlaier		if (strcmp(nam, sym->nam) == 0) {
5945126353Smlaier			sym->used = 1;
5946126353Smlaier			return (sym->val);
5947126353Smlaier		}
5948126353Smlaier	return (NULL);
5949126353Smlaier}
5950126353Smlaier
5951126353Smlaiervoid
5952171172Smlaiermv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
5953126353Smlaier{
5954171172Smlaier	int i;
5955171172Smlaier	struct pf_rule *r;
5956126353Smlaier
5957171172Smlaier	for (i = 0; i < PF_RULESET_MAX; ++i) {
5958171172Smlaier		while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
5959171172Smlaier		    != NULL) {
5960171172Smlaier			TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
5961171172Smlaier			TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
5962171172Smlaier			dst->anchor->match++;
5963126353Smlaier		}
5964171172Smlaier		src->anchor->match = 0;
5965171172Smlaier		while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
5966171172Smlaier		    != NULL) {
5967171172Smlaier			TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
5968171172Smlaier			TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
5969171172Smlaier				r, entries);
5970171172Smlaier		}
5971126353Smlaier	}
5972126353Smlaier}
5973126353Smlaier
5974126353Smlaiervoid
5975171172Smlaierdecide_address_family(struct node_host *n, sa_family_t *af)
5976171172Smlaier{
5977171172Smlaier	if (*af != 0 || n == NULL)
5978171172Smlaier		return;
5979171172Smlaier	*af = n->af;
5980171172Smlaier	while ((n = n->next) != NULL) {
5981171172Smlaier		if (n->af != *af) {
5982171172Smlaier			*af = 0;
5983171172Smlaier			return;
5984171172Smlaier		}
5985171172Smlaier	}
5986171172Smlaier}
5987171172Smlaier
5988171172Smlaiervoid
5989126353Smlaierremove_invalid_hosts(struct node_host **nh, sa_family_t *af)
5990126353Smlaier{
5991126353Smlaier	struct node_host	*n = *nh, *prev = NULL;
5992126353Smlaier
5993126353Smlaier	while (n != NULL) {
5994126353Smlaier		if (*af && n->af && n->af != *af) {
5995126353Smlaier			/* unlink and free n */
5996126353Smlaier			struct node_host *next = n->next;
5997126353Smlaier
5998126353Smlaier			/* adjust tail pointer */
5999126353Smlaier			if (n == (*nh)->tail)
6000126353Smlaier				(*nh)->tail = prev;
6001126353Smlaier			/* adjust previous node's next pointer */
6002126353Smlaier			if (prev == NULL)
6003126353Smlaier				*nh = next;
6004126353Smlaier			else
6005126353Smlaier				prev->next = next;
6006126353Smlaier			/* free node */
6007126353Smlaier			if (n->ifname != NULL)
6008126353Smlaier				free(n->ifname);
6009126353Smlaier			free(n);
6010126353Smlaier			n = next;
6011126353Smlaier		} else {
6012126353Smlaier			if (n->af && !*af)
6013126353Smlaier				*af = n->af;
6014126353Smlaier			prev = n;
6015126353Smlaier			n = n->next;
6016126353Smlaier		}
6017126353Smlaier	}
6018126353Smlaier}
6019126353Smlaier
6020126353Smlaierint
6021126353Smlaierinvalid_redirect(struct node_host *nh, sa_family_t af)
6022126353Smlaier{
6023126353Smlaier	if (!af) {
6024126353Smlaier		struct node_host *n;
6025126353Smlaier
6026130617Smlaier		/* tables and dyniftl are ok without an address family */
6027126353Smlaier		for (n = nh; n != NULL; n = n->next) {
6028130617Smlaier			if (n->addr.type != PF_ADDR_TABLE &&
6029130617Smlaier			    n->addr.type != PF_ADDR_DYNIFTL) {
6030126353Smlaier				yyerror("address family not given and "
6031126353Smlaier				    "translation address expands to multiple "
6032126353Smlaier				    "address families");
6033126353Smlaier				return (1);
6034126353Smlaier			}
6035126353Smlaier		}
6036126353Smlaier	}
6037126353Smlaier	if (nh == NULL) {
6038126353Smlaier		yyerror("no translation address with matching address family "
6039126353Smlaier		    "found.");
6040126353Smlaier		return (1);
6041126353Smlaier	}
6042126353Smlaier	return (0);
6043126353Smlaier}
6044126353Smlaier
6045126353Smlaierint
6046126353Smlaieratoul(char *s, u_long *ulvalp)
6047126353Smlaier{
6048126353Smlaier	u_long	 ulval;
6049126353Smlaier	char	*ep;
6050126353Smlaier
6051126353Smlaier	errno = 0;
6052126353Smlaier	ulval = strtoul(s, &ep, 0);
6053126353Smlaier	if (s[0] == '\0' || *ep != '\0')
6054126353Smlaier		return (-1);
6055126353Smlaier	if (errno == ERANGE && ulval == ULONG_MAX)
6056126353Smlaier		return (-1);
6057126353Smlaier	*ulvalp = ulval;
6058126353Smlaier	return (0);
6059126353Smlaier}
6060126353Smlaier
6061126353Smlaierint
6062126353Smlaiergetservice(char *n)
6063126353Smlaier{
6064126353Smlaier	struct servent	*s;
6065126353Smlaier	u_long		 ulval;
6066126353Smlaier
6067126353Smlaier	if (atoul(n, &ulval) == 0) {
6068126353Smlaier		if (ulval > 65535) {
6069145840Smlaier			yyerror("illegal port value %lu", ulval);
6070126353Smlaier			return (-1);
6071126353Smlaier		}
6072126353Smlaier		return (htons(ulval));
6073126353Smlaier	} else {
6074126353Smlaier		s = getservbyname(n, "tcp");
6075126353Smlaier		if (s == NULL)
6076126353Smlaier			s = getservbyname(n, "udp");
6077126353Smlaier		if (s == NULL) {
6078126353Smlaier			yyerror("unknown port %s", n);
6079126353Smlaier			return (-1);
6080126353Smlaier		}
6081126353Smlaier		return (s->s_port);
6082126353Smlaier	}
6083126353Smlaier}
6084126353Smlaier
6085126353Smlaierint
6086126353Smlaierrule_label(struct pf_rule *r, char *s)
6087126353Smlaier{
6088126353Smlaier	if (s) {
6089126353Smlaier		if (strlcpy(r->label, s, sizeof(r->label)) >=
6090126353Smlaier		    sizeof(r->label)) {
6091126353Smlaier			yyerror("rule label too long (max %d chars)",
6092126353Smlaier			    sizeof(r->label)-1);
6093126353Smlaier			return (-1);
6094126353Smlaier		}
6095126353Smlaier	}
6096126353Smlaier	return (0);
6097126353Smlaier}
6098126353Smlaier
6099126353Smlaieru_int16_t
6100126353Smlaierparseicmpspec(char *w, sa_family_t af)
6101126353Smlaier{
6102126353Smlaier	const struct icmpcodeent	*p;
6103126353Smlaier	u_long				 ulval;
6104126353Smlaier	u_int8_t			 icmptype;
6105126353Smlaier
6106126353Smlaier	if (af == AF_INET)
6107126353Smlaier		icmptype = returnicmpdefault >> 8;
6108126353Smlaier	else
6109126353Smlaier		icmptype = returnicmp6default >> 8;
6110126353Smlaier
6111126353Smlaier	if (atoul(w, &ulval) == -1) {
6112126353Smlaier		if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
6113126353Smlaier			yyerror("unknown icmp code %s", w);
6114126353Smlaier			return (0);
6115126353Smlaier		}
6116126353Smlaier		ulval = p->code;
6117126353Smlaier	}
6118126353Smlaier	if (ulval > 255) {
6119145840Smlaier		yyerror("invalid icmp code %lu", ulval);
6120126353Smlaier		return (0);
6121126353Smlaier	}
6122126353Smlaier	return (icmptype << 8 | ulval);
6123126353Smlaier}
6124126353Smlaier
6125126353Smlaierint
6126223637Sbzparseport(char *port, struct range *r, int extensions)
6127223637Sbz{
6128223637Sbz	char	*p = strchr(port, ':');
6129223637Sbz
6130223637Sbz	if (p == NULL) {
6131223637Sbz		if ((r->a = getservice(port)) == -1)
6132223637Sbz			return (-1);
6133223637Sbz		r->b = 0;
6134223637Sbz		r->t = PF_OP_NONE;
6135223637Sbz		return (0);
6136223637Sbz	}
6137223637Sbz	if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
6138223637Sbz		*p = 0;
6139223637Sbz		if ((r->a = getservice(port)) == -1)
6140223637Sbz			return (-1);
6141223637Sbz		r->b = 0;
6142223637Sbz		r->t = PF_OP_IRG;
6143223637Sbz		return (0);
6144223637Sbz	}
6145223637Sbz	if ((extensions & PPORT_RANGE)) {
6146223637Sbz		*p++ = 0;
6147223637Sbz		if ((r->a = getservice(port)) == -1 ||
6148223637Sbz		    (r->b = getservice(p)) == -1)
6149223637Sbz			return (-1);
6150223637Sbz		if (r->a == r->b) {
6151223637Sbz			r->b = 0;
6152223637Sbz			r->t = PF_OP_NONE;
6153223637Sbz		} else
6154223637Sbz			r->t = PF_OP_RRG;
6155223637Sbz		return (0);
6156223637Sbz	}
6157223637Sbz	return (-1);
6158223637Sbz}
6159223637Sbz
6160223637Sbzint
6161171172Smlaierpfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
6162126353Smlaier{
6163126353Smlaier	struct loadanchors	*la;
6164126353Smlaier
6165126353Smlaier	TAILQ_FOREACH(la, &loadanchorshead, entries) {
6166171172Smlaier		if (pf->opts & PF_OPT_VERBOSE)
6167145840Smlaier			fprintf(stderr, "\nLoading anchor %s from %s\n",
6168145840Smlaier			    la->anchorname, la->filename);
6169223637Sbz		if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
6170171172Smlaier		    la->anchorname, trans) == -1)
6171126353Smlaier			return (-1);
6172126353Smlaier	}
6173126353Smlaier
6174126353Smlaier	return (0);
6175126353Smlaier}
6176231852Sbz
6177231852Sbzint
6178231852Sbzrt_tableid_max(void)
6179231852Sbz{
6180231852Sbz#ifdef __FreeBSD__
6181231852Sbz	int fibs;
6182231852Sbz	size_t l = sizeof(fibs);
6183231852Sbz
6184231852Sbz        if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
6185231852Sbz		fibs = 16;	/* XXX RT_MAXFIBS, at least limit it some. */
6186231852Sbz	/*
6187231852Sbz	 * As the OpenBSD code only compares > and not >= we need to adjust
6188231852Sbz	 * here given we only accept values of 0..n and want to avoid #ifdefs
6189231852Sbz	 * in the grammer.
6190231852Sbz	 */
6191231852Sbz	return (fibs - 1);
6192231852Sbz#else
6193231852Sbz	return (RT_TABLEID_MAX);
6194231852Sbz#endif
6195231852Sbz}
6196