xref: /freebsd/sbin/pfctl/parse.y (revision db1bbde602dd439c6de30121dd3304f6e98cd9c3)
13b3a8eb9SGleb Smirnoff /*	$OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $	*/
23b3a8eb9SGleb Smirnoff 
33b3a8eb9SGleb Smirnoff /*
43b3a8eb9SGleb Smirnoff  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
53b3a8eb9SGleb Smirnoff  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
63b3a8eb9SGleb Smirnoff  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
73b3a8eb9SGleb Smirnoff  * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
83b3a8eb9SGleb Smirnoff  *
93b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
103b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
113b3a8eb9SGleb Smirnoff  * are met:
123b3a8eb9SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
133b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
143b3a8eb9SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
153b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
163b3a8eb9SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
173b3a8eb9SGleb Smirnoff  *
183b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
193b3a8eb9SGleb Smirnoff  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
203b3a8eb9SGleb Smirnoff  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
213b3a8eb9SGleb Smirnoff  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
223b3a8eb9SGleb Smirnoff  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
233b3a8eb9SGleb Smirnoff  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
243b3a8eb9SGleb Smirnoff  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
253b3a8eb9SGleb Smirnoff  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
263b3a8eb9SGleb Smirnoff  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
273b3a8eb9SGleb Smirnoff  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
283b3a8eb9SGleb Smirnoff  */
293b3a8eb9SGleb Smirnoff %{
303b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
313b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$");
323b3a8eb9SGleb Smirnoff 
333b3a8eb9SGleb Smirnoff #include <sys/types.h>
343b3a8eb9SGleb Smirnoff #include <sys/socket.h>
353b3a8eb9SGleb Smirnoff #include <sys/stat.h>
363b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
373b3a8eb9SGleb Smirnoff #include <sys/sysctl.h>
383b3a8eb9SGleb Smirnoff #endif
393b3a8eb9SGleb Smirnoff #include <net/if.h>
403b3a8eb9SGleb Smirnoff #include <netinet/in.h>
413b3a8eb9SGleb Smirnoff #include <netinet/in_systm.h>
423b3a8eb9SGleb Smirnoff #include <netinet/ip.h>
433b3a8eb9SGleb Smirnoff #include <netinet/ip_icmp.h>
443b3a8eb9SGleb Smirnoff #include <netinet/icmp6.h>
453b3a8eb9SGleb Smirnoff #include <net/pfvar.h>
463b3a8eb9SGleb Smirnoff #include <arpa/inet.h>
47772e66a6SGleb Smirnoff #include <net/altq/altq.h>
48772e66a6SGleb Smirnoff #include <net/altq/altq_cbq.h>
490a70aaf8SLuiz Otavio O Souza #include <net/altq/altq_codel.h>
50772e66a6SGleb Smirnoff #include <net/altq/altq_priq.h>
51772e66a6SGleb Smirnoff #include <net/altq/altq_hfsc.h>
52a5b789f6SErmal Luçi #include <net/altq/altq_fairq.h>
533b3a8eb9SGleb Smirnoff 
543b3a8eb9SGleb Smirnoff #include <stdio.h>
553b3a8eb9SGleb Smirnoff #include <unistd.h>
563b3a8eb9SGleb Smirnoff #include <stdlib.h>
573b3a8eb9SGleb Smirnoff #include <netdb.h>
583b3a8eb9SGleb Smirnoff #include <stdarg.h>
593b3a8eb9SGleb Smirnoff #include <errno.h>
603b3a8eb9SGleb Smirnoff #include <string.h>
613b3a8eb9SGleb Smirnoff #include <ctype.h>
623b3a8eb9SGleb Smirnoff #include <math.h>
633b3a8eb9SGleb Smirnoff #include <err.h>
643b3a8eb9SGleb Smirnoff #include <limits.h>
653b3a8eb9SGleb Smirnoff #include <pwd.h>
663b3a8eb9SGleb Smirnoff #include <grp.h>
673b3a8eb9SGleb Smirnoff #include <md5.h>
683b3a8eb9SGleb Smirnoff 
693b3a8eb9SGleb Smirnoff #include "pfctl_parser.h"
703b3a8eb9SGleb Smirnoff #include "pfctl.h"
713b3a8eb9SGleb Smirnoff 
723b3a8eb9SGleb Smirnoff static struct pfctl	*pf = NULL;
733b3a8eb9SGleb Smirnoff static int		 debug = 0;
743b3a8eb9SGleb Smirnoff static int		 rulestate = 0;
753b3a8eb9SGleb Smirnoff static u_int16_t	 returnicmpdefault =
763b3a8eb9SGleb Smirnoff 			    (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
773b3a8eb9SGleb Smirnoff static u_int16_t	 returnicmp6default =
783b3a8eb9SGleb Smirnoff 			    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
793b3a8eb9SGleb Smirnoff static int		 blockpolicy = PFRULE_DROP;
803b3a8eb9SGleb Smirnoff static int		 require_order = 1;
813b3a8eb9SGleb Smirnoff static int		 default_statelock;
823b3a8eb9SGleb Smirnoff 
833b3a8eb9SGleb Smirnoff TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
843b3a8eb9SGleb Smirnoff static struct file {
853b3a8eb9SGleb Smirnoff 	TAILQ_ENTRY(file)	 entry;
863b3a8eb9SGleb Smirnoff 	FILE			*stream;
873b3a8eb9SGleb Smirnoff 	char			*name;
883b3a8eb9SGleb Smirnoff 	int			 lineno;
893b3a8eb9SGleb Smirnoff 	int			 errors;
903b3a8eb9SGleb Smirnoff } *file;
913b3a8eb9SGleb Smirnoff struct file	*pushfile(const char *, int);
923b3a8eb9SGleb Smirnoff int		 popfile(void);
933b3a8eb9SGleb Smirnoff int		 check_file_secrecy(int, const char *);
943b3a8eb9SGleb Smirnoff int		 yyparse(void);
953b3a8eb9SGleb Smirnoff int		 yylex(void);
963b3a8eb9SGleb Smirnoff int		 yyerror(const char *, ...);
973b3a8eb9SGleb Smirnoff int		 kw_cmp(const void *, const void *);
983b3a8eb9SGleb Smirnoff int		 lookup(char *);
993b3a8eb9SGleb Smirnoff int		 lgetc(int);
1003b3a8eb9SGleb Smirnoff int		 lungetc(int);
1013b3a8eb9SGleb Smirnoff int		 findeol(void);
1023b3a8eb9SGleb Smirnoff 
1033b3a8eb9SGleb Smirnoff TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
1043b3a8eb9SGleb Smirnoff struct sym {
1053b3a8eb9SGleb Smirnoff 	TAILQ_ENTRY(sym)	 entry;
1063b3a8eb9SGleb Smirnoff 	int			 used;
1073b3a8eb9SGleb Smirnoff 	int			 persist;
1083b3a8eb9SGleb Smirnoff 	char			*nam;
1093b3a8eb9SGleb Smirnoff 	char			*val;
1103b3a8eb9SGleb Smirnoff };
1113b3a8eb9SGleb Smirnoff int		 symset(const char *, const char *, int);
1123b3a8eb9SGleb Smirnoff char		*symget(const char *);
1133b3a8eb9SGleb Smirnoff 
1143b3a8eb9SGleb Smirnoff int		 atoul(char *, u_long *);
1153b3a8eb9SGleb Smirnoff 
1163b3a8eb9SGleb Smirnoff enum {
1173b3a8eb9SGleb Smirnoff 	PFCTL_STATE_NONE,
1183b3a8eb9SGleb Smirnoff 	PFCTL_STATE_OPTION,
1193b3a8eb9SGleb Smirnoff 	PFCTL_STATE_SCRUB,
1203b3a8eb9SGleb Smirnoff 	PFCTL_STATE_QUEUE,
1213b3a8eb9SGleb Smirnoff 	PFCTL_STATE_NAT,
1223b3a8eb9SGleb Smirnoff 	PFCTL_STATE_FILTER
1233b3a8eb9SGleb Smirnoff };
1243b3a8eb9SGleb Smirnoff 
1253b3a8eb9SGleb Smirnoff struct node_proto {
1263b3a8eb9SGleb Smirnoff 	u_int8_t		 proto;
1273b3a8eb9SGleb Smirnoff 	struct node_proto	*next;
1283b3a8eb9SGleb Smirnoff 	struct node_proto	*tail;
1293b3a8eb9SGleb Smirnoff };
1303b3a8eb9SGleb Smirnoff 
1313b3a8eb9SGleb Smirnoff struct node_port {
1323b3a8eb9SGleb Smirnoff 	u_int16_t		 port[2];
1333b3a8eb9SGleb Smirnoff 	u_int8_t		 op;
1343b3a8eb9SGleb Smirnoff 	struct node_port	*next;
1353b3a8eb9SGleb Smirnoff 	struct node_port	*tail;
1363b3a8eb9SGleb Smirnoff };
1373b3a8eb9SGleb Smirnoff 
1383b3a8eb9SGleb Smirnoff struct node_uid {
1393b3a8eb9SGleb Smirnoff 	uid_t			 uid[2];
1403b3a8eb9SGleb Smirnoff 	u_int8_t		 op;
1413b3a8eb9SGleb Smirnoff 	struct node_uid		*next;
1423b3a8eb9SGleb Smirnoff 	struct node_uid		*tail;
1433b3a8eb9SGleb Smirnoff };
1443b3a8eb9SGleb Smirnoff 
1453b3a8eb9SGleb Smirnoff struct node_gid {
1463b3a8eb9SGleb Smirnoff 	gid_t			 gid[2];
1473b3a8eb9SGleb Smirnoff 	u_int8_t		 op;
1483b3a8eb9SGleb Smirnoff 	struct node_gid		*next;
1493b3a8eb9SGleb Smirnoff 	struct node_gid		*tail;
1503b3a8eb9SGleb Smirnoff };
1513b3a8eb9SGleb Smirnoff 
1523b3a8eb9SGleb Smirnoff struct node_icmp {
1533b3a8eb9SGleb Smirnoff 	u_int8_t		 code;
1543b3a8eb9SGleb Smirnoff 	u_int8_t		 type;
1553b3a8eb9SGleb Smirnoff 	u_int8_t		 proto;
1563b3a8eb9SGleb Smirnoff 	struct node_icmp	*next;
1573b3a8eb9SGleb Smirnoff 	struct node_icmp	*tail;
1583b3a8eb9SGleb Smirnoff };
1593b3a8eb9SGleb Smirnoff 
1603b3a8eb9SGleb Smirnoff enum	{ PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
1613b3a8eb9SGleb Smirnoff 	    PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
1623b3a8eb9SGleb Smirnoff 	    PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
1633b3a8eb9SGleb Smirnoff 	    PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
1643b3a8eb9SGleb Smirnoff 	    PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
1653b3a8eb9SGleb Smirnoff 
1663b3a8eb9SGleb Smirnoff enum	{ PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
1673b3a8eb9SGleb Smirnoff 
1683b3a8eb9SGleb Smirnoff struct node_state_opt {
1693b3a8eb9SGleb Smirnoff 	int			 type;
1703b3a8eb9SGleb Smirnoff 	union {
1713b3a8eb9SGleb Smirnoff 		u_int32_t	 max_states;
1723b3a8eb9SGleb Smirnoff 		u_int32_t	 max_src_states;
1733b3a8eb9SGleb Smirnoff 		u_int32_t	 max_src_conn;
1743b3a8eb9SGleb Smirnoff 		struct {
1753b3a8eb9SGleb Smirnoff 			u_int32_t	limit;
1763b3a8eb9SGleb Smirnoff 			u_int32_t	seconds;
1773b3a8eb9SGleb Smirnoff 		}		 max_src_conn_rate;
1783b3a8eb9SGleb Smirnoff 		struct {
1793b3a8eb9SGleb Smirnoff 			u_int8_t	flush;
1803b3a8eb9SGleb Smirnoff 			char		tblname[PF_TABLE_NAME_SIZE];
1813b3a8eb9SGleb Smirnoff 		}		 overload;
1823b3a8eb9SGleb Smirnoff 		u_int32_t	 max_src_nodes;
1833b3a8eb9SGleb Smirnoff 		u_int8_t	 src_track;
1843b3a8eb9SGleb Smirnoff 		u_int32_t	 statelock;
1853b3a8eb9SGleb Smirnoff 		struct {
1863b3a8eb9SGleb Smirnoff 			int		number;
1873b3a8eb9SGleb Smirnoff 			u_int32_t	seconds;
1883b3a8eb9SGleb Smirnoff 		}		 timeout;
1893b3a8eb9SGleb Smirnoff 	}			 data;
1903b3a8eb9SGleb Smirnoff 	struct node_state_opt	*next;
1913b3a8eb9SGleb Smirnoff 	struct node_state_opt	*tail;
1923b3a8eb9SGleb Smirnoff };
1933b3a8eb9SGleb Smirnoff 
1943b3a8eb9SGleb Smirnoff struct peer {
1953b3a8eb9SGleb Smirnoff 	struct node_host	*host;
1963b3a8eb9SGleb Smirnoff 	struct node_port	*port;
1973b3a8eb9SGleb Smirnoff };
1983b3a8eb9SGleb Smirnoff 
1993b3a8eb9SGleb Smirnoff struct node_queue {
2003b3a8eb9SGleb Smirnoff 	char			 queue[PF_QNAME_SIZE];
2013b3a8eb9SGleb Smirnoff 	char			 parent[PF_QNAME_SIZE];
2023b3a8eb9SGleb Smirnoff 	char			 ifname[IFNAMSIZ];
2033b3a8eb9SGleb Smirnoff 	int			 scheduler;
2043b3a8eb9SGleb Smirnoff 	struct node_queue	*next;
2053b3a8eb9SGleb Smirnoff 	struct node_queue	*tail;
2063b3a8eb9SGleb Smirnoff }	*queues = NULL;
2073b3a8eb9SGleb Smirnoff 
2083b3a8eb9SGleb Smirnoff struct node_qassign {
2093b3a8eb9SGleb Smirnoff 	char		*qname;
2103b3a8eb9SGleb Smirnoff 	char		*pqname;
2113b3a8eb9SGleb Smirnoff };
2123b3a8eb9SGleb Smirnoff 
2133b3a8eb9SGleb Smirnoff struct filter_opts {
2143b3a8eb9SGleb Smirnoff 	int			 marker;
2153b3a8eb9SGleb Smirnoff #define FOM_FLAGS	0x01
2163b3a8eb9SGleb Smirnoff #define FOM_ICMP	0x02
2173b3a8eb9SGleb Smirnoff #define FOM_TOS		0x04
2183b3a8eb9SGleb Smirnoff #define FOM_KEEP	0x08
2193b3a8eb9SGleb Smirnoff #define FOM_SRCTRACK	0x10
2203b3a8eb9SGleb Smirnoff 	struct node_uid		*uid;
2213b3a8eb9SGleb Smirnoff 	struct node_gid		*gid;
2223b3a8eb9SGleb Smirnoff 	struct {
2233b3a8eb9SGleb Smirnoff 		u_int8_t	 b1;
2243b3a8eb9SGleb Smirnoff 		u_int8_t	 b2;
2253b3a8eb9SGleb Smirnoff 		u_int16_t	 w;
2263b3a8eb9SGleb Smirnoff 		u_int16_t	 w2;
2273b3a8eb9SGleb Smirnoff 	} flags;
2283b3a8eb9SGleb Smirnoff 	struct node_icmp	*icmpspec;
2293b3a8eb9SGleb Smirnoff 	u_int32_t		 tos;
2303b3a8eb9SGleb Smirnoff 	u_int32_t		 prob;
2313b3a8eb9SGleb Smirnoff 	struct {
2323b3a8eb9SGleb Smirnoff 		int			 action;
2333b3a8eb9SGleb Smirnoff 		struct node_state_opt	*options;
2343b3a8eb9SGleb Smirnoff 	} keep;
2353b3a8eb9SGleb Smirnoff 	int			 fragment;
2363b3a8eb9SGleb Smirnoff 	int			 allowopts;
2373b3a8eb9SGleb Smirnoff 	char			*label;
2383b3a8eb9SGleb Smirnoff 	struct node_qassign	 queues;
2393b3a8eb9SGleb Smirnoff 	char			*tag;
2403b3a8eb9SGleb Smirnoff 	char			*match_tag;
2413b3a8eb9SGleb Smirnoff 	u_int8_t		 match_tag_not;
2423b3a8eb9SGleb Smirnoff 	u_int			 rtableid;
2433b3a8eb9SGleb Smirnoff 	struct {
2443b3a8eb9SGleb Smirnoff 		struct node_host	*addr;
2453b3a8eb9SGleb Smirnoff 		u_int16_t		port;
2463b3a8eb9SGleb Smirnoff 	}			 divert;
2473b3a8eb9SGleb Smirnoff } filter_opts;
2483b3a8eb9SGleb Smirnoff 
2493b3a8eb9SGleb Smirnoff struct antispoof_opts {
2503b3a8eb9SGleb Smirnoff 	char			*label;
2513b3a8eb9SGleb Smirnoff 	u_int			 rtableid;
2523b3a8eb9SGleb Smirnoff } antispoof_opts;
2533b3a8eb9SGleb Smirnoff 
2543b3a8eb9SGleb Smirnoff struct scrub_opts {
2553b3a8eb9SGleb Smirnoff 	int			 marker;
2563b3a8eb9SGleb Smirnoff #define SOM_MINTTL	0x01
2573b3a8eb9SGleb Smirnoff #define SOM_MAXMSS	0x02
2583b3a8eb9SGleb Smirnoff #define SOM_FRAGCACHE	0x04
2593b3a8eb9SGleb Smirnoff #define SOM_SETTOS	0x08
2603b3a8eb9SGleb Smirnoff 	int			 nodf;
2613b3a8eb9SGleb Smirnoff 	int			 minttl;
2623b3a8eb9SGleb Smirnoff 	int			 maxmss;
2633b3a8eb9SGleb Smirnoff 	int			 settos;
2643b3a8eb9SGleb Smirnoff 	int			 fragcache;
2653b3a8eb9SGleb Smirnoff 	int			 randomid;
2663b3a8eb9SGleb Smirnoff 	int			 reassemble_tcp;
2673b3a8eb9SGleb Smirnoff 	char			*match_tag;
2683b3a8eb9SGleb Smirnoff 	u_int8_t		 match_tag_not;
2693b3a8eb9SGleb Smirnoff 	u_int			 rtableid;
2703b3a8eb9SGleb Smirnoff } scrub_opts;
2713b3a8eb9SGleb Smirnoff 
2723b3a8eb9SGleb Smirnoff struct queue_opts {
2733b3a8eb9SGleb Smirnoff 	int			marker;
2743b3a8eb9SGleb Smirnoff #define QOM_BWSPEC	0x01
2753b3a8eb9SGleb Smirnoff #define QOM_SCHEDULER	0x02
2763b3a8eb9SGleb Smirnoff #define QOM_PRIORITY	0x04
2773b3a8eb9SGleb Smirnoff #define QOM_TBRSIZE	0x08
2783b3a8eb9SGleb Smirnoff #define QOM_QLIMIT	0x10
2793b3a8eb9SGleb Smirnoff 	struct node_queue_bw	queue_bwspec;
2803b3a8eb9SGleb Smirnoff 	struct node_queue_opt	scheduler;
2813b3a8eb9SGleb Smirnoff 	int			priority;
2823b3a8eb9SGleb Smirnoff 	int			tbrsize;
2833b3a8eb9SGleb Smirnoff 	int			qlimit;
2843b3a8eb9SGleb Smirnoff } queue_opts;
2853b3a8eb9SGleb Smirnoff 
2863b3a8eb9SGleb Smirnoff struct table_opts {
2873b3a8eb9SGleb Smirnoff 	int			flags;
2883b3a8eb9SGleb Smirnoff 	int			init_addr;
2893b3a8eb9SGleb Smirnoff 	struct node_tinithead	init_nodes;
2903b3a8eb9SGleb Smirnoff } table_opts;
2913b3a8eb9SGleb Smirnoff 
2923b3a8eb9SGleb Smirnoff struct pool_opts {
2933b3a8eb9SGleb Smirnoff 	int			 marker;
2943b3a8eb9SGleb Smirnoff #define POM_TYPE		0x01
2953b3a8eb9SGleb Smirnoff #define POM_STICKYADDRESS	0x02
2963b3a8eb9SGleb Smirnoff 	u_int8_t		 opts;
2973b3a8eb9SGleb Smirnoff 	int			 type;
2983b3a8eb9SGleb Smirnoff 	int			 staticport;
2993b3a8eb9SGleb Smirnoff 	struct pf_poolhashkey	*key;
3003b3a8eb9SGleb Smirnoff 
3013b3a8eb9SGleb Smirnoff } pool_opts;
3023b3a8eb9SGleb Smirnoff 
3030a70aaf8SLuiz Otavio O Souza struct codel_opts	 codel_opts;
3043b3a8eb9SGleb Smirnoff struct node_hfsc_opts	 hfsc_opts;
305a5b789f6SErmal Luçi struct node_fairq_opts	 fairq_opts;
3063b3a8eb9SGleb Smirnoff struct node_state_opt	*keep_state_defaults = NULL;
3073b3a8eb9SGleb Smirnoff 
3083b3a8eb9SGleb Smirnoff int		 disallow_table(struct node_host *, const char *);
3093b3a8eb9SGleb Smirnoff int		 disallow_urpf_failed(struct node_host *, const char *);
3103b3a8eb9SGleb Smirnoff int		 disallow_alias(struct node_host *, const char *);
3113b3a8eb9SGleb Smirnoff int		 rule_consistent(struct pf_rule *, int);
3123b3a8eb9SGleb Smirnoff int		 filter_consistent(struct pf_rule *, int);
3133b3a8eb9SGleb Smirnoff int		 nat_consistent(struct pf_rule *);
3143b3a8eb9SGleb Smirnoff int		 rdr_consistent(struct pf_rule *);
3153b3a8eb9SGleb Smirnoff int		 process_tabledef(char *, struct table_opts *);
3163b3a8eb9SGleb Smirnoff void		 expand_label_str(char *, size_t, const char *, const char *);
3173b3a8eb9SGleb Smirnoff void		 expand_label_if(const char *, char *, size_t, const char *);
3183b3a8eb9SGleb Smirnoff void		 expand_label_addr(const char *, char *, size_t, u_int8_t,
3193b3a8eb9SGleb Smirnoff 		    struct node_host *);
3203b3a8eb9SGleb Smirnoff void		 expand_label_port(const char *, char *, size_t,
3213b3a8eb9SGleb Smirnoff 		    struct node_port *);
3223b3a8eb9SGleb Smirnoff void		 expand_label_proto(const char *, char *, size_t, u_int8_t);
3233b3a8eb9SGleb Smirnoff void		 expand_label_nr(const char *, char *, size_t);
3243b3a8eb9SGleb Smirnoff void		 expand_label(char *, size_t, const char *, u_int8_t,
3253b3a8eb9SGleb Smirnoff 		    struct node_host *, struct node_port *, struct node_host *,
3263b3a8eb9SGleb Smirnoff 		    struct node_port *, u_int8_t);
3273b3a8eb9SGleb Smirnoff void		 expand_rule(struct pf_rule *, struct node_if *,
3283b3a8eb9SGleb Smirnoff 		    struct node_host *, struct node_proto *, struct node_os *,
3293b3a8eb9SGleb Smirnoff 		    struct node_host *, struct node_port *, struct node_host *,
3303b3a8eb9SGleb Smirnoff 		    struct node_port *, struct node_uid *, struct node_gid *,
3313b3a8eb9SGleb Smirnoff 		    struct node_icmp *, const char *);
3323b3a8eb9SGleb Smirnoff int		 expand_altq(struct pf_altq *, struct node_if *,
3333b3a8eb9SGleb Smirnoff 		    struct node_queue *, struct node_queue_bw bwspec,
3343b3a8eb9SGleb Smirnoff 		    struct node_queue_opt *);
3353b3a8eb9SGleb Smirnoff int		 expand_queue(struct pf_altq *, struct node_if *,
3363b3a8eb9SGleb Smirnoff 		    struct node_queue *, struct node_queue_bw,
3373b3a8eb9SGleb Smirnoff 		    struct node_queue_opt *);
3383b3a8eb9SGleb Smirnoff int		 expand_skip_interface(struct node_if *);
3393b3a8eb9SGleb Smirnoff 
3403b3a8eb9SGleb Smirnoff int	 check_rulestate(int);
3413b3a8eb9SGleb Smirnoff int	 getservice(char *);
3423b3a8eb9SGleb Smirnoff int	 rule_label(struct pf_rule *, char *);
3433b3a8eb9SGleb Smirnoff int	 rt_tableid_max(void);
3443b3a8eb9SGleb Smirnoff 
3453b3a8eb9SGleb Smirnoff void	 mv_rules(struct pf_ruleset *, struct pf_ruleset *);
3463b3a8eb9SGleb Smirnoff void	 decide_address_family(struct node_host *, sa_family_t *);
3473b3a8eb9SGleb Smirnoff void	 remove_invalid_hosts(struct node_host **, sa_family_t *);
3483b3a8eb9SGleb Smirnoff int	 invalid_redirect(struct node_host *, sa_family_t);
3493b3a8eb9SGleb Smirnoff u_int16_t parseicmpspec(char *, sa_family_t);
3503b3a8eb9SGleb Smirnoff 
3513b3a8eb9SGleb Smirnoff TAILQ_HEAD(loadanchorshead, loadanchors)
3523b3a8eb9SGleb Smirnoff     loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
3533b3a8eb9SGleb Smirnoff 
3543b3a8eb9SGleb Smirnoff struct loadanchors {
3553b3a8eb9SGleb Smirnoff 	TAILQ_ENTRY(loadanchors)	 entries;
3563b3a8eb9SGleb Smirnoff 	char				*anchorname;
3573b3a8eb9SGleb Smirnoff 	char				*filename;
3583b3a8eb9SGleb Smirnoff };
3593b3a8eb9SGleb Smirnoff 
3603b3a8eb9SGleb Smirnoff typedef struct {
3613b3a8eb9SGleb Smirnoff 	union {
3623b3a8eb9SGleb Smirnoff 		int64_t			 number;
3633b3a8eb9SGleb Smirnoff 		double			 probability;
3643b3a8eb9SGleb Smirnoff 		int			 i;
3653b3a8eb9SGleb Smirnoff 		char			*string;
3663b3a8eb9SGleb Smirnoff 		u_int			 rtableid;
3673b3a8eb9SGleb Smirnoff 		struct {
3683b3a8eb9SGleb Smirnoff 			u_int8_t	 b1;
3693b3a8eb9SGleb Smirnoff 			u_int8_t	 b2;
3703b3a8eb9SGleb Smirnoff 			u_int16_t	 w;
3713b3a8eb9SGleb Smirnoff 			u_int16_t	 w2;
3723b3a8eb9SGleb Smirnoff 		}			 b;
3733b3a8eb9SGleb Smirnoff 		struct range {
3743b3a8eb9SGleb Smirnoff 			int		 a;
3753b3a8eb9SGleb Smirnoff 			int		 b;
3763b3a8eb9SGleb Smirnoff 			int		 t;
3773b3a8eb9SGleb Smirnoff 		}			 range;
3783b3a8eb9SGleb Smirnoff 		struct node_if		*interface;
3793b3a8eb9SGleb Smirnoff 		struct node_proto	*proto;
3803b3a8eb9SGleb Smirnoff 		struct node_icmp	*icmp;
3813b3a8eb9SGleb Smirnoff 		struct node_host	*host;
3823b3a8eb9SGleb Smirnoff 		struct node_os		*os;
3833b3a8eb9SGleb Smirnoff 		struct node_port	*port;
3843b3a8eb9SGleb Smirnoff 		struct node_uid		*uid;
3853b3a8eb9SGleb Smirnoff 		struct node_gid		*gid;
3863b3a8eb9SGleb Smirnoff 		struct node_state_opt	*state_opt;
3873b3a8eb9SGleb Smirnoff 		struct peer		 peer;
3883b3a8eb9SGleb Smirnoff 		struct {
3893b3a8eb9SGleb Smirnoff 			struct peer	 src, dst;
3903b3a8eb9SGleb Smirnoff 			struct node_os	*src_os;
3913b3a8eb9SGleb Smirnoff 		}			 fromto;
3923b3a8eb9SGleb Smirnoff 		struct {
3933b3a8eb9SGleb Smirnoff 			struct node_host	*host;
3943b3a8eb9SGleb Smirnoff 			u_int8_t		 rt;
3953b3a8eb9SGleb Smirnoff 			u_int8_t		 pool_opts;
3963b3a8eb9SGleb Smirnoff 			sa_family_t		 af;
3973b3a8eb9SGleb Smirnoff 			struct pf_poolhashkey	*key;
3983b3a8eb9SGleb Smirnoff 		}			 route;
3993b3a8eb9SGleb Smirnoff 		struct redirection {
4003b3a8eb9SGleb Smirnoff 			struct node_host	*host;
4013b3a8eb9SGleb Smirnoff 			struct range		 rport;
4023b3a8eb9SGleb Smirnoff 		}			*redirection;
4033b3a8eb9SGleb Smirnoff 		struct {
4043b3a8eb9SGleb Smirnoff 			int			 action;
4053b3a8eb9SGleb Smirnoff 			struct node_state_opt	*options;
4063b3a8eb9SGleb Smirnoff 		}			 keep_state;
4073b3a8eb9SGleb Smirnoff 		struct {
4083b3a8eb9SGleb Smirnoff 			u_int8_t	 log;
4093b3a8eb9SGleb Smirnoff 			u_int8_t	 logif;
4103b3a8eb9SGleb Smirnoff 			u_int8_t	 quick;
4113b3a8eb9SGleb Smirnoff 		}			 logquick;
4123b3a8eb9SGleb Smirnoff 		struct {
4133b3a8eb9SGleb Smirnoff 			int		 neg;
4143b3a8eb9SGleb Smirnoff 			char		*name;
4153b3a8eb9SGleb Smirnoff 		}			 tagged;
4163b3a8eb9SGleb Smirnoff 		struct pf_poolhashkey	*hashkey;
4173b3a8eb9SGleb Smirnoff 		struct node_queue	*queue;
4183b3a8eb9SGleb Smirnoff 		struct node_queue_opt	 queue_options;
4193b3a8eb9SGleb Smirnoff 		struct node_queue_bw	 queue_bwspec;
4203b3a8eb9SGleb Smirnoff 		struct node_qassign	 qassign;
4213b3a8eb9SGleb Smirnoff 		struct filter_opts	 filter_opts;
4223b3a8eb9SGleb Smirnoff 		struct antispoof_opts	 antispoof_opts;
4233b3a8eb9SGleb Smirnoff 		struct queue_opts	 queue_opts;
4243b3a8eb9SGleb Smirnoff 		struct scrub_opts	 scrub_opts;
4253b3a8eb9SGleb Smirnoff 		struct table_opts	 table_opts;
4263b3a8eb9SGleb Smirnoff 		struct pool_opts	 pool_opts;
4273b3a8eb9SGleb Smirnoff 		struct node_hfsc_opts	 hfsc_opts;
428a5b789f6SErmal Luçi 		struct node_fairq_opts	 fairq_opts;
4290a70aaf8SLuiz Otavio O Souza 		struct codel_opts	 codel_opts;
4303b3a8eb9SGleb Smirnoff 	} v;
4313b3a8eb9SGleb Smirnoff 	int lineno;
4323b3a8eb9SGleb Smirnoff } YYSTYPE;
4333b3a8eb9SGleb Smirnoff 
4343b3a8eb9SGleb Smirnoff #define PPORT_RANGE	1
4353b3a8eb9SGleb Smirnoff #define PPORT_STAR	2
4363b3a8eb9SGleb Smirnoff int	parseport(char *, struct range *r, int);
4373b3a8eb9SGleb Smirnoff 
4383b3a8eb9SGleb Smirnoff #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
4393b3a8eb9SGleb Smirnoff 	(!((addr).iflags & PFI_AFLAG_NOALIAS) ||		 \
4403b3a8eb9SGleb Smirnoff 	!isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
4413b3a8eb9SGleb Smirnoff 
4423b3a8eb9SGleb Smirnoff %}
4433b3a8eb9SGleb Smirnoff 
4443b3a8eb9SGleb Smirnoff %token	PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
4453b3a8eb9SGleb Smirnoff %token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
4463b3a8eb9SGleb Smirnoff %token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
4473b3a8eb9SGleb Smirnoff %token	MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
4483b3a8eb9SGleb Smirnoff %token	NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
4493b3a8eb9SGleb Smirnoff %token	REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
4503b3a8eb9SGleb Smirnoff %token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
4513b3a8eb9SGleb Smirnoff %token	REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
4523b3a8eb9SGleb Smirnoff %token	ANTISPOOF FOR INCLUDE
4533b3a8eb9SGleb Smirnoff %token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
4540a70aaf8SLuiz Otavio O Souza %token	ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
4550a70aaf8SLuiz Otavio O Souza %token	UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
4563b3a8eb9SGleb Smirnoff %token	LOAD RULESET_OPTIMIZATION
4573b3a8eb9SGleb Smirnoff %token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
4583b3a8eb9SGleb Smirnoff %token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
4593b3a8eb9SGleb Smirnoff %token	TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
4603b3a8eb9SGleb Smirnoff %token	DIVERTTO DIVERTREPLY
4613b3a8eb9SGleb Smirnoff %token	<v.string>		STRING
4623b3a8eb9SGleb Smirnoff %token	<v.number>		NUMBER
4633b3a8eb9SGleb Smirnoff %token	<v.i>			PORTBINARY
4643b3a8eb9SGleb Smirnoff %type	<v.interface>		interface if_list if_item_not if_item
4653b3a8eb9SGleb Smirnoff %type	<v.number>		number icmptype icmp6type uid gid
4663b3a8eb9SGleb Smirnoff %type	<v.number>		tos not yesno
4673b3a8eb9SGleb Smirnoff %type	<v.probability>		probability
4683b3a8eb9SGleb Smirnoff %type	<v.i>			no dir af fragcache optimizer
4693b3a8eb9SGleb Smirnoff %type	<v.i>			sourcetrack flush unaryop statelock
4703b3a8eb9SGleb Smirnoff %type	<v.b>			action nataction natpasslog scrubaction
4713b3a8eb9SGleb Smirnoff %type	<v.b>			flags flag blockspec
4723b3a8eb9SGleb Smirnoff %type	<v.range>		portplain portstar portrange
4733b3a8eb9SGleb Smirnoff %type	<v.hashkey>		hashkey
4743b3a8eb9SGleb Smirnoff %type	<v.proto>		proto proto_list proto_item
4753b3a8eb9SGleb Smirnoff %type	<v.number>		protoval
4763b3a8eb9SGleb Smirnoff %type	<v.icmp>		icmpspec
4773b3a8eb9SGleb Smirnoff %type	<v.icmp>		icmp_list icmp_item
4783b3a8eb9SGleb Smirnoff %type	<v.icmp>		icmp6_list icmp6_item
4793b3a8eb9SGleb Smirnoff %type	<v.number>		reticmpspec reticmp6spec
4803b3a8eb9SGleb Smirnoff %type	<v.fromto>		fromto
4813b3a8eb9SGleb Smirnoff %type	<v.peer>		ipportspec from to
4823b3a8eb9SGleb Smirnoff %type	<v.host>		ipspec toipspec xhost host dynaddr host_list
4833b3a8eb9SGleb Smirnoff %type	<v.host>		redir_host_list redirspec
4843b3a8eb9SGleb Smirnoff %type	<v.host>		route_host route_host_list routespec
4853b3a8eb9SGleb Smirnoff %type	<v.os>			os xos os_list
4863b3a8eb9SGleb Smirnoff %type	<v.port>		portspec port_list port_item
4873b3a8eb9SGleb Smirnoff %type	<v.uid>			uids uid_list uid_item
4883b3a8eb9SGleb Smirnoff %type	<v.gid>			gids gid_list gid_item
4893b3a8eb9SGleb Smirnoff %type	<v.route>		route
4903b3a8eb9SGleb Smirnoff %type	<v.redirection>		redirection redirpool
4913b3a8eb9SGleb Smirnoff %type	<v.string>		label stringall tag anchorname
4923b3a8eb9SGleb Smirnoff %type	<v.string>		string varstring numberstring
4933b3a8eb9SGleb Smirnoff %type	<v.keep_state>		keep
4943b3a8eb9SGleb Smirnoff %type	<v.state_opt>		state_opt_spec state_opt_list state_opt_item
4953b3a8eb9SGleb Smirnoff %type	<v.logquick>		logquick quick log logopts logopt
4963b3a8eb9SGleb Smirnoff %type	<v.interface>		antispoof_ifspc antispoof_iflst antispoof_if
4973b3a8eb9SGleb Smirnoff %type	<v.qassign>		qname
4983b3a8eb9SGleb Smirnoff %type	<v.queue>		qassign qassign_list qassign_item
4993b3a8eb9SGleb Smirnoff %type	<v.queue_options>	scheduler
5003b3a8eb9SGleb Smirnoff %type	<v.number>		cbqflags_list cbqflags_item
5013b3a8eb9SGleb Smirnoff %type	<v.number>		priqflags_list priqflags_item
5023b3a8eb9SGleb Smirnoff %type	<v.hfsc_opts>		hfscopts_list hfscopts_item hfsc_opts
503a5b789f6SErmal Luçi %type	<v.fairq_opts>		fairqopts_list fairqopts_item fairq_opts
5040a70aaf8SLuiz Otavio O Souza %type	<v.codel_opts>		codelopts_list codelopts_item codel_opts
5053b3a8eb9SGleb Smirnoff %type	<v.queue_bwspec>	bandwidth
5063b3a8eb9SGleb Smirnoff %type	<v.filter_opts>		filter_opts filter_opt filter_opts_l
5073b3a8eb9SGleb Smirnoff %type	<v.antispoof_opts>	antispoof_opts antispoof_opt antispoof_opts_l
5083b3a8eb9SGleb Smirnoff %type	<v.queue_opts>		queue_opts queue_opt queue_opts_l
5093b3a8eb9SGleb Smirnoff %type	<v.scrub_opts>		scrub_opts scrub_opt scrub_opts_l
5103b3a8eb9SGleb Smirnoff %type	<v.table_opts>		table_opts table_opt table_opts_l
5113b3a8eb9SGleb Smirnoff %type	<v.pool_opts>		pool_opts pool_opt pool_opts_l
5123b3a8eb9SGleb Smirnoff %type	<v.tagged>		tagged
5133b3a8eb9SGleb Smirnoff %type	<v.rtableid>		rtable
5143b3a8eb9SGleb Smirnoff %%
5153b3a8eb9SGleb Smirnoff 
5163b3a8eb9SGleb Smirnoff ruleset		: /* empty */
5173b3a8eb9SGleb Smirnoff 		| ruleset include '\n'
5183b3a8eb9SGleb Smirnoff 		| ruleset '\n'
5193b3a8eb9SGleb Smirnoff 		| ruleset option '\n'
5203b3a8eb9SGleb Smirnoff 		| ruleset scrubrule '\n'
5213b3a8eb9SGleb Smirnoff 		| ruleset natrule '\n'
5223b3a8eb9SGleb Smirnoff 		| ruleset binatrule '\n'
5233b3a8eb9SGleb Smirnoff 		| ruleset pfrule '\n'
5243b3a8eb9SGleb Smirnoff 		| ruleset anchorrule '\n'
5253b3a8eb9SGleb Smirnoff 		| ruleset loadrule '\n'
5263b3a8eb9SGleb Smirnoff 		| ruleset altqif '\n'
5273b3a8eb9SGleb Smirnoff 		| ruleset queuespec '\n'
5283b3a8eb9SGleb Smirnoff 		| ruleset varset '\n'
5293b3a8eb9SGleb Smirnoff 		| ruleset antispoof '\n'
5303b3a8eb9SGleb Smirnoff 		| ruleset tabledef '\n'
5313b3a8eb9SGleb Smirnoff 		| '{' fakeanchor '}' '\n';
5323b3a8eb9SGleb Smirnoff 		| ruleset error '\n'		{ file->errors++; }
5333b3a8eb9SGleb Smirnoff 		;
5343b3a8eb9SGleb Smirnoff 
5353b3a8eb9SGleb Smirnoff include		: INCLUDE STRING		{
5363b3a8eb9SGleb Smirnoff 			struct file	*nfile;
5373b3a8eb9SGleb Smirnoff 
5383b3a8eb9SGleb Smirnoff 			if ((nfile = pushfile($2, 0)) == NULL) {
5393b3a8eb9SGleb Smirnoff 				yyerror("failed to include file %s", $2);
5403b3a8eb9SGleb Smirnoff 				free($2);
5413b3a8eb9SGleb Smirnoff 				YYERROR;
5423b3a8eb9SGleb Smirnoff 			}
5433b3a8eb9SGleb Smirnoff 			free($2);
5443b3a8eb9SGleb Smirnoff 
5453b3a8eb9SGleb Smirnoff 			file = nfile;
5463b3a8eb9SGleb Smirnoff 			lungetc('\n');
5473b3a8eb9SGleb Smirnoff 		}
5483b3a8eb9SGleb Smirnoff 		;
5493b3a8eb9SGleb Smirnoff 
5503b3a8eb9SGleb Smirnoff /*
5513b3a8eb9SGleb Smirnoff  * apply to previouslys specified rule: must be careful to note
5523b3a8eb9SGleb Smirnoff  * what that is: pf or nat or binat or rdr
5533b3a8eb9SGleb Smirnoff  */
5543b3a8eb9SGleb Smirnoff fakeanchor	: fakeanchor '\n'
5553b3a8eb9SGleb Smirnoff 		| fakeanchor anchorrule '\n'
5563b3a8eb9SGleb Smirnoff 		| fakeanchor binatrule '\n'
5573b3a8eb9SGleb Smirnoff 		| fakeanchor natrule '\n'
5583b3a8eb9SGleb Smirnoff 		| fakeanchor pfrule '\n'
5593b3a8eb9SGleb Smirnoff 		| fakeanchor error '\n'
5603b3a8eb9SGleb Smirnoff 		;
5613b3a8eb9SGleb Smirnoff 
5623b3a8eb9SGleb Smirnoff optimizer	: string	{
5633b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "none"))
5643b3a8eb9SGleb Smirnoff 				$$ = 0;
5653b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "basic"))
5663b3a8eb9SGleb Smirnoff 				$$ = PF_OPTIMIZE_BASIC;
5673b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "profile"))
5683b3a8eb9SGleb Smirnoff 				$$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
5693b3a8eb9SGleb Smirnoff 			else {
5703b3a8eb9SGleb Smirnoff 				yyerror("unknown ruleset-optimization %s", $1);
5713b3a8eb9SGleb Smirnoff 				YYERROR;
5723b3a8eb9SGleb Smirnoff 			}
5733b3a8eb9SGleb Smirnoff 		}
5743b3a8eb9SGleb Smirnoff 		;
5753b3a8eb9SGleb Smirnoff 
5763b3a8eb9SGleb Smirnoff option		: SET OPTIMIZATION STRING		{
5773b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
5783b3a8eb9SGleb Smirnoff 				free($3);
5793b3a8eb9SGleb Smirnoff 				YYERROR;
5803b3a8eb9SGleb Smirnoff 			}
5813b3a8eb9SGleb Smirnoff 			if (pfctl_set_optimization(pf, $3) != 0) {
5823b3a8eb9SGleb Smirnoff 				yyerror("unknown optimization %s", $3);
5833b3a8eb9SGleb Smirnoff 				free($3);
5843b3a8eb9SGleb Smirnoff 				YYERROR;
5853b3a8eb9SGleb Smirnoff 			}
5863b3a8eb9SGleb Smirnoff 			free($3);
5873b3a8eb9SGleb Smirnoff 		}
5883b3a8eb9SGleb Smirnoff 		| SET RULESET_OPTIMIZATION optimizer {
5893b3a8eb9SGleb Smirnoff 			if (!(pf->opts & PF_OPT_OPTIMIZE)) {
5903b3a8eb9SGleb Smirnoff 				pf->opts |= PF_OPT_OPTIMIZE;
5913b3a8eb9SGleb Smirnoff 				pf->optimize = $3;
5923b3a8eb9SGleb Smirnoff 			}
5933b3a8eb9SGleb Smirnoff 		}
5943b3a8eb9SGleb Smirnoff 		| SET TIMEOUT timeout_spec
5953b3a8eb9SGleb Smirnoff 		| SET TIMEOUT '{' optnl timeout_list '}'
5963b3a8eb9SGleb Smirnoff 		| SET LIMIT limit_spec
5973b3a8eb9SGleb Smirnoff 		| SET LIMIT '{' optnl limit_list '}'
5983b3a8eb9SGleb Smirnoff 		| SET LOGINTERFACE stringall		{
5993b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
6003b3a8eb9SGleb Smirnoff 				free($3);
6013b3a8eb9SGleb Smirnoff 				YYERROR;
6023b3a8eb9SGleb Smirnoff 			}
6033b3a8eb9SGleb Smirnoff 			if (pfctl_set_logif(pf, $3) != 0) {
6043b3a8eb9SGleb Smirnoff 				yyerror("error setting loginterface %s", $3);
6053b3a8eb9SGleb Smirnoff 				free($3);
6063b3a8eb9SGleb Smirnoff 				YYERROR;
6073b3a8eb9SGleb Smirnoff 			}
6083b3a8eb9SGleb Smirnoff 			free($3);
6093b3a8eb9SGleb Smirnoff 		}
6103b3a8eb9SGleb Smirnoff 		| SET HOSTID number {
6113b3a8eb9SGleb Smirnoff 			if ($3 == 0 || $3 > UINT_MAX) {
6123b3a8eb9SGleb Smirnoff 				yyerror("hostid must be non-zero");
6133b3a8eb9SGleb Smirnoff 				YYERROR;
6143b3a8eb9SGleb Smirnoff 			}
6153b3a8eb9SGleb Smirnoff 			if (pfctl_set_hostid(pf, $3) != 0) {
6163b3a8eb9SGleb Smirnoff 				yyerror("error setting hostid %08x", $3);
6173b3a8eb9SGleb Smirnoff 				YYERROR;
6183b3a8eb9SGleb Smirnoff 			}
6193b3a8eb9SGleb Smirnoff 		}
6203b3a8eb9SGleb Smirnoff 		| SET BLOCKPOLICY DROP	{
6213b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
6223b3a8eb9SGleb Smirnoff 				printf("set block-policy drop\n");
6233b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION))
6243b3a8eb9SGleb Smirnoff 				YYERROR;
6253b3a8eb9SGleb Smirnoff 			blockpolicy = PFRULE_DROP;
6263b3a8eb9SGleb Smirnoff 		}
6273b3a8eb9SGleb Smirnoff 		| SET BLOCKPOLICY RETURN {
6283b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
6293b3a8eb9SGleb Smirnoff 				printf("set block-policy return\n");
6303b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION))
6313b3a8eb9SGleb Smirnoff 				YYERROR;
6323b3a8eb9SGleb Smirnoff 			blockpolicy = PFRULE_RETURN;
6333b3a8eb9SGleb Smirnoff 		}
6343b3a8eb9SGleb Smirnoff 		| SET REQUIREORDER yesno {
6353b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
6363b3a8eb9SGleb Smirnoff 				printf("set require-order %s\n",
6373b3a8eb9SGleb Smirnoff 				    $3 == 1 ? "yes" : "no");
6383b3a8eb9SGleb Smirnoff 			require_order = $3;
6393b3a8eb9SGleb Smirnoff 		}
6403b3a8eb9SGleb Smirnoff 		| SET FINGERPRINTS STRING {
6413b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
6423b3a8eb9SGleb Smirnoff 				printf("set fingerprints \"%s\"\n", $3);
6433b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
6443b3a8eb9SGleb Smirnoff 				free($3);
6453b3a8eb9SGleb Smirnoff 				YYERROR;
6463b3a8eb9SGleb Smirnoff 			}
6473b3a8eb9SGleb Smirnoff 			if (!pf->anchor->name[0]) {
6483b3a8eb9SGleb Smirnoff 				if (pfctl_file_fingerprints(pf->dev,
6493b3a8eb9SGleb Smirnoff 				    pf->opts, $3)) {
6503b3a8eb9SGleb Smirnoff 					yyerror("error loading "
6513b3a8eb9SGleb Smirnoff 					    "fingerprints %s", $3);
6523b3a8eb9SGleb Smirnoff 					free($3);
6533b3a8eb9SGleb Smirnoff 					YYERROR;
6543b3a8eb9SGleb Smirnoff 				}
6553b3a8eb9SGleb Smirnoff 			}
6563b3a8eb9SGleb Smirnoff 			free($3);
6573b3a8eb9SGleb Smirnoff 		}
6583b3a8eb9SGleb Smirnoff 		| SET STATEPOLICY statelock {
6593b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
6603b3a8eb9SGleb Smirnoff 				switch ($3) {
6613b3a8eb9SGleb Smirnoff 				case 0:
6623b3a8eb9SGleb Smirnoff 					printf("set state-policy floating\n");
6633b3a8eb9SGleb Smirnoff 					break;
6643b3a8eb9SGleb Smirnoff 				case PFRULE_IFBOUND:
6653b3a8eb9SGleb Smirnoff 					printf("set state-policy if-bound\n");
6663b3a8eb9SGleb Smirnoff 					break;
6673b3a8eb9SGleb Smirnoff 				}
6683b3a8eb9SGleb Smirnoff 			default_statelock = $3;
6693b3a8eb9SGleb Smirnoff 		}
6703b3a8eb9SGleb Smirnoff 		| SET DEBUG STRING {
6713b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
6723b3a8eb9SGleb Smirnoff 				free($3);
6733b3a8eb9SGleb Smirnoff 				YYERROR;
6743b3a8eb9SGleb Smirnoff 			}
6753b3a8eb9SGleb Smirnoff 			if (pfctl_set_debug(pf, $3) != 0) {
6763b3a8eb9SGleb Smirnoff 				yyerror("error setting debuglevel %s", $3);
6773b3a8eb9SGleb Smirnoff 				free($3);
6783b3a8eb9SGleb Smirnoff 				YYERROR;
6793b3a8eb9SGleb Smirnoff 			}
6803b3a8eb9SGleb Smirnoff 			free($3);
6813b3a8eb9SGleb Smirnoff 		}
6823b3a8eb9SGleb Smirnoff 		| SET SKIP interface {
6833b3a8eb9SGleb Smirnoff 			if (expand_skip_interface($3) != 0) {
6843b3a8eb9SGleb Smirnoff 				yyerror("error setting skip interface(s)");
6853b3a8eb9SGleb Smirnoff 				YYERROR;
6863b3a8eb9SGleb Smirnoff 			}
6873b3a8eb9SGleb Smirnoff 		}
6883b3a8eb9SGleb Smirnoff 		| SET STATEDEFAULTS state_opt_list {
6893b3a8eb9SGleb Smirnoff 			if (keep_state_defaults != NULL) {
6903b3a8eb9SGleb Smirnoff 				yyerror("cannot redefine state-defaults");
6913b3a8eb9SGleb Smirnoff 				YYERROR;
6923b3a8eb9SGleb Smirnoff 			}
6933b3a8eb9SGleb Smirnoff 			keep_state_defaults = $3;
6943b3a8eb9SGleb Smirnoff 		}
6953b3a8eb9SGleb Smirnoff 		;
6963b3a8eb9SGleb Smirnoff 
6973b3a8eb9SGleb Smirnoff stringall	: STRING	{ $$ = $1; }
6983b3a8eb9SGleb Smirnoff 		| ALL		{
6993b3a8eb9SGleb Smirnoff 			if (($$ = strdup("all")) == NULL) {
7003b3a8eb9SGleb Smirnoff 				err(1, "stringall: strdup");
7013b3a8eb9SGleb Smirnoff 			}
7023b3a8eb9SGleb Smirnoff 		}
7033b3a8eb9SGleb Smirnoff 		;
7043b3a8eb9SGleb Smirnoff 
7053b3a8eb9SGleb Smirnoff string		: STRING string				{
7063b3a8eb9SGleb Smirnoff 			if (asprintf(&$$, "%s %s", $1, $2) == -1)
7073b3a8eb9SGleb Smirnoff 				err(1, "string: asprintf");
7083b3a8eb9SGleb Smirnoff 			free($1);
7093b3a8eb9SGleb Smirnoff 			free($2);
7103b3a8eb9SGleb Smirnoff 		}
7113b3a8eb9SGleb Smirnoff 		| STRING
7123b3a8eb9SGleb Smirnoff 		;
7133b3a8eb9SGleb Smirnoff 
7143b3a8eb9SGleb Smirnoff varstring	: numberstring varstring 		{
7153b3a8eb9SGleb Smirnoff 			if (asprintf(&$$, "%s %s", $1, $2) == -1)
7163b3a8eb9SGleb Smirnoff 				err(1, "string: asprintf");
7173b3a8eb9SGleb Smirnoff 			free($1);
7183b3a8eb9SGleb Smirnoff 			free($2);
7193b3a8eb9SGleb Smirnoff 		}
7203b3a8eb9SGleb Smirnoff 		| numberstring
7213b3a8eb9SGleb Smirnoff 		;
7223b3a8eb9SGleb Smirnoff 
7233b3a8eb9SGleb Smirnoff numberstring	: NUMBER				{
7243b3a8eb9SGleb Smirnoff 			char	*s;
7253b3a8eb9SGleb Smirnoff 			if (asprintf(&s, "%lld", (long long)$1) == -1) {
7263b3a8eb9SGleb Smirnoff 				yyerror("string: asprintf");
7273b3a8eb9SGleb Smirnoff 				YYERROR;
7283b3a8eb9SGleb Smirnoff 			}
7293b3a8eb9SGleb Smirnoff 			$$ = s;
7303b3a8eb9SGleb Smirnoff 		}
7313b3a8eb9SGleb Smirnoff 		| STRING
7323b3a8eb9SGleb Smirnoff 		;
7333b3a8eb9SGleb Smirnoff 
7343b3a8eb9SGleb Smirnoff varset		: STRING '=' varstring	{
7353b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
7363b3a8eb9SGleb Smirnoff 				printf("%s = \"%s\"\n", $1, $3);
7373b3a8eb9SGleb Smirnoff 			if (symset($1, $3, 0) == -1)
7383b3a8eb9SGleb Smirnoff 				err(1, "cannot store variable %s", $1);
7393b3a8eb9SGleb Smirnoff 			free($1);
7403b3a8eb9SGleb Smirnoff 			free($3);
7413b3a8eb9SGleb Smirnoff 		}
7423b3a8eb9SGleb Smirnoff 		;
7433b3a8eb9SGleb Smirnoff 
7443b3a8eb9SGleb Smirnoff anchorname	: STRING			{ $$ = $1; }
7453b3a8eb9SGleb Smirnoff 		| /* empty */			{ $$ = NULL; }
7463b3a8eb9SGleb Smirnoff 		;
7473b3a8eb9SGleb Smirnoff 
7483b3a8eb9SGleb Smirnoff pfa_anchorlist	: /* empty */
7493b3a8eb9SGleb Smirnoff 		| pfa_anchorlist '\n'
7503b3a8eb9SGleb Smirnoff 		| pfa_anchorlist pfrule '\n'
7513b3a8eb9SGleb Smirnoff 		| pfa_anchorlist anchorrule '\n'
7523b3a8eb9SGleb Smirnoff 		;
7533b3a8eb9SGleb Smirnoff 
7543b3a8eb9SGleb Smirnoff pfa_anchor	: '{'
7553b3a8eb9SGleb Smirnoff 		{
7563b3a8eb9SGleb Smirnoff 			char ta[PF_ANCHOR_NAME_SIZE];
7573b3a8eb9SGleb Smirnoff 			struct pf_ruleset *rs;
7583b3a8eb9SGleb Smirnoff 
7593b3a8eb9SGleb Smirnoff 			/* steping into a brace anchor */
7603b3a8eb9SGleb Smirnoff 			pf->asd++;
7613b3a8eb9SGleb Smirnoff 			pf->bn++;
7623b3a8eb9SGleb Smirnoff 			pf->brace = 1;
7633b3a8eb9SGleb Smirnoff 
7643b3a8eb9SGleb Smirnoff 			/* create a holding ruleset in the root */
7653b3a8eb9SGleb Smirnoff 			snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
7663b3a8eb9SGleb Smirnoff 			rs = pf_find_or_create_ruleset(ta);
7673b3a8eb9SGleb Smirnoff 			if (rs == NULL)
7683b3a8eb9SGleb Smirnoff 				err(1, "pfa_anchor: pf_find_or_create_ruleset");
7693b3a8eb9SGleb Smirnoff 			pf->astack[pf->asd] = rs->anchor;
7703b3a8eb9SGleb Smirnoff 			pf->anchor = rs->anchor;
7713b3a8eb9SGleb Smirnoff 		} '\n' pfa_anchorlist '}'
7723b3a8eb9SGleb Smirnoff 		{
7733b3a8eb9SGleb Smirnoff 			pf->alast = pf->anchor;
7743b3a8eb9SGleb Smirnoff 			pf->asd--;
7753b3a8eb9SGleb Smirnoff 			pf->anchor = pf->astack[pf->asd];
7763b3a8eb9SGleb Smirnoff 		}
7773b3a8eb9SGleb Smirnoff 		| /* empty */
7783b3a8eb9SGleb Smirnoff 		;
7793b3a8eb9SGleb Smirnoff 
7803b3a8eb9SGleb Smirnoff anchorrule	: ANCHOR anchorname dir quick interface af proto fromto
7813b3a8eb9SGleb Smirnoff 		    filter_opts pfa_anchor
7823b3a8eb9SGleb Smirnoff 		{
7833b3a8eb9SGleb Smirnoff 			struct pf_rule	r;
7843b3a8eb9SGleb Smirnoff 			struct node_proto	*proto;
7853b3a8eb9SGleb Smirnoff 
7863b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_FILTER)) {
7873b3a8eb9SGleb Smirnoff 				if ($2)
7883b3a8eb9SGleb Smirnoff 					free($2);
7893b3a8eb9SGleb Smirnoff 				YYERROR;
7903b3a8eb9SGleb Smirnoff 			}
7913b3a8eb9SGleb Smirnoff 
7923b3a8eb9SGleb Smirnoff 			if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
7933b3a8eb9SGleb Smirnoff 				free($2);
7943b3a8eb9SGleb Smirnoff 				yyerror("anchor names beginning with '_' "
7953b3a8eb9SGleb Smirnoff 				    "are reserved for internal use");
7963b3a8eb9SGleb Smirnoff 				YYERROR;
7973b3a8eb9SGleb Smirnoff 			}
7983b3a8eb9SGleb Smirnoff 
7993b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
8003b3a8eb9SGleb Smirnoff 			if (pf->astack[pf->asd + 1]) {
8013b3a8eb9SGleb Smirnoff 				/* move inline rules into relative location */
8023b3a8eb9SGleb Smirnoff 				pf_anchor_setup(&r,
8033b3a8eb9SGleb Smirnoff 				    &pf->astack[pf->asd]->ruleset,
8043b3a8eb9SGleb Smirnoff 				    $2 ? $2 : pf->alast->name);
8053b3a8eb9SGleb Smirnoff 
8063b3a8eb9SGleb Smirnoff 				if (r.anchor == NULL)
8073b3a8eb9SGleb Smirnoff 					err(1, "anchorrule: unable to "
8083b3a8eb9SGleb Smirnoff 					    "create ruleset");
8093b3a8eb9SGleb Smirnoff 
8103b3a8eb9SGleb Smirnoff 				if (pf->alast != r.anchor) {
8113b3a8eb9SGleb Smirnoff 					if (r.anchor->match) {
8123b3a8eb9SGleb Smirnoff 						yyerror("inline anchor '%s' "
8133b3a8eb9SGleb Smirnoff 						    "already exists",
8143b3a8eb9SGleb Smirnoff 						    r.anchor->name);
8153b3a8eb9SGleb Smirnoff 						YYERROR;
8163b3a8eb9SGleb Smirnoff 					}
8173b3a8eb9SGleb Smirnoff 					mv_rules(&pf->alast->ruleset,
8183b3a8eb9SGleb Smirnoff 					    &r.anchor->ruleset);
8193b3a8eb9SGleb Smirnoff 				}
8203b3a8eb9SGleb Smirnoff 				pf_remove_if_empty_ruleset(&pf->alast->ruleset);
8213b3a8eb9SGleb Smirnoff 				pf->alast = r.anchor;
8223b3a8eb9SGleb Smirnoff 			} else {
8233b3a8eb9SGleb Smirnoff 				if (!$2) {
8243b3a8eb9SGleb Smirnoff 					yyerror("anchors without explicit "
8253b3a8eb9SGleb Smirnoff 					    "rules must specify a name");
8263b3a8eb9SGleb Smirnoff 					YYERROR;
8273b3a8eb9SGleb Smirnoff 				}
8283b3a8eb9SGleb Smirnoff 			}
8293b3a8eb9SGleb Smirnoff 			r.direction = $3;
8303b3a8eb9SGleb Smirnoff 			r.quick = $4.quick;
8313b3a8eb9SGleb Smirnoff 			r.af = $6;
8323b3a8eb9SGleb Smirnoff 			r.prob = $9.prob;
8333b3a8eb9SGleb Smirnoff 			r.rtableid = $9.rtableid;
8343b3a8eb9SGleb Smirnoff 
8353b3a8eb9SGleb Smirnoff 			if ($9.tag)
8363b3a8eb9SGleb Smirnoff 				if (strlcpy(r.tagname, $9.tag,
8373b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
8383b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
8393b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
8403b3a8eb9SGleb Smirnoff 					YYERROR;
8413b3a8eb9SGleb Smirnoff 				}
8423b3a8eb9SGleb Smirnoff 			if ($9.match_tag)
8433b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $9.match_tag,
8443b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
8453b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
8463b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
8473b3a8eb9SGleb Smirnoff 					YYERROR;
8483b3a8eb9SGleb Smirnoff 				}
8493b3a8eb9SGleb Smirnoff 			r.match_tag_not = $9.match_tag_not;
8503b3a8eb9SGleb Smirnoff 			if (rule_label(&r, $9.label))
8513b3a8eb9SGleb Smirnoff 				YYERROR;
8523b3a8eb9SGleb Smirnoff 			free($9.label);
8533b3a8eb9SGleb Smirnoff 			r.flags = $9.flags.b1;
8543b3a8eb9SGleb Smirnoff 			r.flagset = $9.flags.b2;
8553b3a8eb9SGleb Smirnoff 			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
8563b3a8eb9SGleb Smirnoff 				yyerror("flags always false");
8573b3a8eb9SGleb Smirnoff 				YYERROR;
8583b3a8eb9SGleb Smirnoff 			}
8593b3a8eb9SGleb Smirnoff 			if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
8603b3a8eb9SGleb Smirnoff 				for (proto = $7; proto != NULL &&
8613b3a8eb9SGleb Smirnoff 				    proto->proto != IPPROTO_TCP;
8623b3a8eb9SGleb Smirnoff 				    proto = proto->next)
8633b3a8eb9SGleb Smirnoff 					;	/* nothing */
8643b3a8eb9SGleb Smirnoff 				if (proto == NULL && $7 != NULL) {
8653b3a8eb9SGleb Smirnoff 					if ($9.flags.b1 || $9.flags.b2)
8663b3a8eb9SGleb Smirnoff 						yyerror(
8673b3a8eb9SGleb Smirnoff 						    "flags only apply to tcp");
8683b3a8eb9SGleb Smirnoff 					if ($8.src_os)
8693b3a8eb9SGleb Smirnoff 						yyerror(
8703b3a8eb9SGleb Smirnoff 						    "OS fingerprinting only "
8713b3a8eb9SGleb Smirnoff 						    "applies to tcp");
8723b3a8eb9SGleb Smirnoff 					YYERROR;
8733b3a8eb9SGleb Smirnoff 				}
8743b3a8eb9SGleb Smirnoff 			}
8753b3a8eb9SGleb Smirnoff 
8763b3a8eb9SGleb Smirnoff 			r.tos = $9.tos;
8773b3a8eb9SGleb Smirnoff 
8783b3a8eb9SGleb Smirnoff 			if ($9.keep.action) {
8793b3a8eb9SGleb Smirnoff 				yyerror("cannot specify state handling "
8803b3a8eb9SGleb Smirnoff 				    "on anchors");
8813b3a8eb9SGleb Smirnoff 				YYERROR;
8823b3a8eb9SGleb Smirnoff 			}
8833b3a8eb9SGleb Smirnoff 
8843b3a8eb9SGleb Smirnoff 			if ($9.match_tag)
8853b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $9.match_tag,
8863b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
8873b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
8883b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
8893b3a8eb9SGleb Smirnoff 					YYERROR;
8903b3a8eb9SGleb Smirnoff 				}
8913b3a8eb9SGleb Smirnoff 			r.match_tag_not = $9.match_tag_not;
8923b3a8eb9SGleb Smirnoff 
8933b3a8eb9SGleb Smirnoff 			decide_address_family($8.src.host, &r.af);
8943b3a8eb9SGleb Smirnoff 			decide_address_family($8.dst.host, &r.af);
8953b3a8eb9SGleb Smirnoff 
8963b3a8eb9SGleb Smirnoff 			expand_rule(&r, $5, NULL, $7, $8.src_os,
8973b3a8eb9SGleb Smirnoff 			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
8983b3a8eb9SGleb Smirnoff 			    $9.uid, $9.gid, $9.icmpspec,
8993b3a8eb9SGleb Smirnoff 			    pf->astack[pf->asd + 1] ? pf->alast->name : $2);
9003b3a8eb9SGleb Smirnoff 			free($2);
9013b3a8eb9SGleb Smirnoff 			pf->astack[pf->asd + 1] = NULL;
9023b3a8eb9SGleb Smirnoff 		}
9033b3a8eb9SGleb Smirnoff 		| NATANCHOR string interface af proto fromto rtable {
9043b3a8eb9SGleb Smirnoff 			struct pf_rule	r;
9053b3a8eb9SGleb Smirnoff 
9063b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT)) {
9073b3a8eb9SGleb Smirnoff 				free($2);
9083b3a8eb9SGleb Smirnoff 				YYERROR;
9093b3a8eb9SGleb Smirnoff 			}
9103b3a8eb9SGleb Smirnoff 
9113b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
9123b3a8eb9SGleb Smirnoff 			r.action = PF_NAT;
9133b3a8eb9SGleb Smirnoff 			r.af = $4;
9143b3a8eb9SGleb Smirnoff 			r.rtableid = $7;
9153b3a8eb9SGleb Smirnoff 
9163b3a8eb9SGleb Smirnoff 			decide_address_family($6.src.host, &r.af);
9173b3a8eb9SGleb Smirnoff 			decide_address_family($6.dst.host, &r.af);
9183b3a8eb9SGleb Smirnoff 
9193b3a8eb9SGleb Smirnoff 			expand_rule(&r, $3, NULL, $5, $6.src_os,
9203b3a8eb9SGleb Smirnoff 			    $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
9213b3a8eb9SGleb Smirnoff 			    0, 0, 0, $2);
9223b3a8eb9SGleb Smirnoff 			free($2);
9233b3a8eb9SGleb Smirnoff 		}
9243b3a8eb9SGleb Smirnoff 		| RDRANCHOR string interface af proto fromto rtable {
9253b3a8eb9SGleb Smirnoff 			struct pf_rule	r;
9263b3a8eb9SGleb Smirnoff 
9273b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT)) {
9283b3a8eb9SGleb Smirnoff 				free($2);
9293b3a8eb9SGleb Smirnoff 				YYERROR;
9303b3a8eb9SGleb Smirnoff 			}
9313b3a8eb9SGleb Smirnoff 
9323b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
9333b3a8eb9SGleb Smirnoff 			r.action = PF_RDR;
9343b3a8eb9SGleb Smirnoff 			r.af = $4;
9353b3a8eb9SGleb Smirnoff 			r.rtableid = $7;
9363b3a8eb9SGleb Smirnoff 
9373b3a8eb9SGleb Smirnoff 			decide_address_family($6.src.host, &r.af);
9383b3a8eb9SGleb Smirnoff 			decide_address_family($6.dst.host, &r.af);
9393b3a8eb9SGleb Smirnoff 
9403b3a8eb9SGleb Smirnoff 			if ($6.src.port != NULL) {
9413b3a8eb9SGleb Smirnoff 				yyerror("source port parameter not supported"
9423b3a8eb9SGleb Smirnoff 				    " in rdr-anchor");
9433b3a8eb9SGleb Smirnoff 				YYERROR;
9443b3a8eb9SGleb Smirnoff 			}
9453b3a8eb9SGleb Smirnoff 			if ($6.dst.port != NULL) {
9463b3a8eb9SGleb Smirnoff 				if ($6.dst.port->next != NULL) {
9473b3a8eb9SGleb Smirnoff 					yyerror("destination port list "
9483b3a8eb9SGleb Smirnoff 					    "expansion not supported in "
9493b3a8eb9SGleb Smirnoff 					    "rdr-anchor");
9503b3a8eb9SGleb Smirnoff 					YYERROR;
9513b3a8eb9SGleb Smirnoff 				} else if ($6.dst.port->op != PF_OP_EQ) {
9523b3a8eb9SGleb Smirnoff 					yyerror("destination port operators"
9533b3a8eb9SGleb Smirnoff 					    " not supported in rdr-anchor");
9543b3a8eb9SGleb Smirnoff 					YYERROR;
9553b3a8eb9SGleb Smirnoff 				}
9563b3a8eb9SGleb Smirnoff 				r.dst.port[0] = $6.dst.port->port[0];
9573b3a8eb9SGleb Smirnoff 				r.dst.port[1] = $6.dst.port->port[1];
9583b3a8eb9SGleb Smirnoff 				r.dst.port_op = $6.dst.port->op;
9593b3a8eb9SGleb Smirnoff 			}
9603b3a8eb9SGleb Smirnoff 
9613b3a8eb9SGleb Smirnoff 			expand_rule(&r, $3, NULL, $5, $6.src_os,
9623b3a8eb9SGleb Smirnoff 			    $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
9633b3a8eb9SGleb Smirnoff 			    0, 0, 0, $2);
9643b3a8eb9SGleb Smirnoff 			free($2);
9653b3a8eb9SGleb Smirnoff 		}
9663b3a8eb9SGleb Smirnoff 		| BINATANCHOR string interface af proto fromto rtable {
9673b3a8eb9SGleb Smirnoff 			struct pf_rule	r;
9683b3a8eb9SGleb Smirnoff 
9693b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT)) {
9703b3a8eb9SGleb Smirnoff 				free($2);
9713b3a8eb9SGleb Smirnoff 				YYERROR;
9723b3a8eb9SGleb Smirnoff 			}
9733b3a8eb9SGleb Smirnoff 
9743b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
9753b3a8eb9SGleb Smirnoff 			r.action = PF_BINAT;
9763b3a8eb9SGleb Smirnoff 			r.af = $4;
9773b3a8eb9SGleb Smirnoff 			r.rtableid = $7;
9783b3a8eb9SGleb Smirnoff 			if ($5 != NULL) {
9793b3a8eb9SGleb Smirnoff 				if ($5->next != NULL) {
9803b3a8eb9SGleb Smirnoff 					yyerror("proto list expansion"
9813b3a8eb9SGleb Smirnoff 					    " not supported in binat-anchor");
9823b3a8eb9SGleb Smirnoff 					YYERROR;
9833b3a8eb9SGleb Smirnoff 				}
9843b3a8eb9SGleb Smirnoff 				r.proto = $5->proto;
9853b3a8eb9SGleb Smirnoff 				free($5);
9863b3a8eb9SGleb Smirnoff 			}
9873b3a8eb9SGleb Smirnoff 
9883b3a8eb9SGleb Smirnoff 			if ($6.src.host != NULL || $6.src.port != NULL ||
9893b3a8eb9SGleb Smirnoff 			    $6.dst.host != NULL || $6.dst.port != NULL) {
9903b3a8eb9SGleb Smirnoff 				yyerror("fromto parameter not supported"
9913b3a8eb9SGleb Smirnoff 				    " in binat-anchor");
9923b3a8eb9SGleb Smirnoff 				YYERROR;
9933b3a8eb9SGleb Smirnoff 			}
9943b3a8eb9SGleb Smirnoff 
9953b3a8eb9SGleb Smirnoff 			decide_address_family($6.src.host, &r.af);
9963b3a8eb9SGleb Smirnoff 			decide_address_family($6.dst.host, &r.af);
9973b3a8eb9SGleb Smirnoff 
9983b3a8eb9SGleb Smirnoff 			pfctl_add_rule(pf, &r, $2);
9993b3a8eb9SGleb Smirnoff 			free($2);
10003b3a8eb9SGleb Smirnoff 		}
10013b3a8eb9SGleb Smirnoff 		;
10023b3a8eb9SGleb Smirnoff 
10033b3a8eb9SGleb Smirnoff loadrule	: LOAD ANCHOR string FROM string	{
10043b3a8eb9SGleb Smirnoff 			struct loadanchors	*loadanchor;
10053b3a8eb9SGleb Smirnoff 
10063b3a8eb9SGleb Smirnoff 			if (strlen(pf->anchor->name) + 1 +
10073b3a8eb9SGleb Smirnoff 			    strlen($3) >= MAXPATHLEN) {
10083b3a8eb9SGleb Smirnoff 				yyerror("anchorname %s too long, max %u\n",
10093b3a8eb9SGleb Smirnoff 				    $3, MAXPATHLEN - 1);
10103b3a8eb9SGleb Smirnoff 				free($3);
10113b3a8eb9SGleb Smirnoff 				YYERROR;
10123b3a8eb9SGleb Smirnoff 			}
10133b3a8eb9SGleb Smirnoff 			loadanchor = calloc(1, sizeof(struct loadanchors));
10143b3a8eb9SGleb Smirnoff 			if (loadanchor == NULL)
10153b3a8eb9SGleb Smirnoff 				err(1, "loadrule: calloc");
10163b3a8eb9SGleb Smirnoff 			if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
10173b3a8eb9SGleb Smirnoff 			    NULL)
10183b3a8eb9SGleb Smirnoff 				err(1, "loadrule: malloc");
10193b3a8eb9SGleb Smirnoff 			if (pf->anchor->name[0])
10203b3a8eb9SGleb Smirnoff 				snprintf(loadanchor->anchorname, MAXPATHLEN,
10213b3a8eb9SGleb Smirnoff 				    "%s/%s", pf->anchor->name, $3);
10223b3a8eb9SGleb Smirnoff 			else
10233b3a8eb9SGleb Smirnoff 				strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
10243b3a8eb9SGleb Smirnoff 			if ((loadanchor->filename = strdup($5)) == NULL)
10253b3a8eb9SGleb Smirnoff 				err(1, "loadrule: strdup");
10263b3a8eb9SGleb Smirnoff 
10273b3a8eb9SGleb Smirnoff 			TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
10283b3a8eb9SGleb Smirnoff 			    entries);
10293b3a8eb9SGleb Smirnoff 
10303b3a8eb9SGleb Smirnoff 			free($3);
10313b3a8eb9SGleb Smirnoff 			free($5);
10323b3a8eb9SGleb Smirnoff 		};
10333b3a8eb9SGleb Smirnoff 
10343b3a8eb9SGleb Smirnoff scrubaction	: no SCRUB {
10353b3a8eb9SGleb Smirnoff 			$$.b2 = $$.w = 0;
10363b3a8eb9SGleb Smirnoff 			if ($1)
10373b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NOSCRUB;
10383b3a8eb9SGleb Smirnoff 			else
10393b3a8eb9SGleb Smirnoff 				$$.b1 = PF_SCRUB;
10403b3a8eb9SGleb Smirnoff 		}
10413b3a8eb9SGleb Smirnoff 		;
10423b3a8eb9SGleb Smirnoff 
10433b3a8eb9SGleb Smirnoff scrubrule	: scrubaction dir logquick interface af proto fromto scrub_opts
10443b3a8eb9SGleb Smirnoff 		{
10453b3a8eb9SGleb Smirnoff 			struct pf_rule	r;
10463b3a8eb9SGleb Smirnoff 
10473b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_SCRUB))
10483b3a8eb9SGleb Smirnoff 				YYERROR;
10493b3a8eb9SGleb Smirnoff 
10503b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
10513b3a8eb9SGleb Smirnoff 
10523b3a8eb9SGleb Smirnoff 			r.action = $1.b1;
10533b3a8eb9SGleb Smirnoff 			r.direction = $2;
10543b3a8eb9SGleb Smirnoff 
10553b3a8eb9SGleb Smirnoff 			r.log = $3.log;
10563b3a8eb9SGleb Smirnoff 			r.logif = $3.logif;
10573b3a8eb9SGleb Smirnoff 			if ($3.quick) {
10583b3a8eb9SGleb Smirnoff 				yyerror("scrub rules do not support 'quick'");
10593b3a8eb9SGleb Smirnoff 				YYERROR;
10603b3a8eb9SGleb Smirnoff 			}
10613b3a8eb9SGleb Smirnoff 
10623b3a8eb9SGleb Smirnoff 			r.af = $5;
10633b3a8eb9SGleb Smirnoff 			if ($8.nodf)
10643b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_NODF;
10653b3a8eb9SGleb Smirnoff 			if ($8.randomid)
10663b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RANDOMID;
10673b3a8eb9SGleb Smirnoff 			if ($8.reassemble_tcp) {
10683b3a8eb9SGleb Smirnoff 				if (r.direction != PF_INOUT) {
10693b3a8eb9SGleb Smirnoff 					yyerror("reassemble tcp rules can not "
10703b3a8eb9SGleb Smirnoff 					    "specify direction");
10713b3a8eb9SGleb Smirnoff 					YYERROR;
10723b3a8eb9SGleb Smirnoff 				}
10733b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_REASSEMBLE_TCP;
10743b3a8eb9SGleb Smirnoff 			}
10753b3a8eb9SGleb Smirnoff 			if ($8.minttl)
10763b3a8eb9SGleb Smirnoff 				r.min_ttl = $8.minttl;
10773b3a8eb9SGleb Smirnoff 			if ($8.maxmss)
10783b3a8eb9SGleb Smirnoff 				r.max_mss = $8.maxmss;
10793b3a8eb9SGleb Smirnoff 			if ($8.marker & SOM_SETTOS) {
10803b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_SET_TOS;
10813b3a8eb9SGleb Smirnoff 				r.set_tos = $8.settos;
10823b3a8eb9SGleb Smirnoff 			}
10833b3a8eb9SGleb Smirnoff 			if ($8.fragcache)
10843b3a8eb9SGleb Smirnoff 				r.rule_flag |= $8.fragcache;
10853b3a8eb9SGleb Smirnoff 			if ($8.match_tag)
10863b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $8.match_tag,
10873b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
10883b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
10893b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
10903b3a8eb9SGleb Smirnoff 					YYERROR;
10913b3a8eb9SGleb Smirnoff 				}
10923b3a8eb9SGleb Smirnoff 			r.match_tag_not = $8.match_tag_not;
10933b3a8eb9SGleb Smirnoff 			r.rtableid = $8.rtableid;
10943b3a8eb9SGleb Smirnoff 
10953b3a8eb9SGleb Smirnoff 			expand_rule(&r, $4, NULL, $6, $7.src_os,
10963b3a8eb9SGleb Smirnoff 			    $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
10973b3a8eb9SGleb Smirnoff 			    NULL, NULL, NULL, "");
10983b3a8eb9SGleb Smirnoff 		}
10993b3a8eb9SGleb Smirnoff 		;
11003b3a8eb9SGleb Smirnoff 
11013b3a8eb9SGleb Smirnoff scrub_opts	:	{
11023b3a8eb9SGleb Smirnoff 				bzero(&scrub_opts, sizeof scrub_opts);
11033b3a8eb9SGleb Smirnoff 				scrub_opts.rtableid = -1;
11043b3a8eb9SGleb Smirnoff 			}
11053b3a8eb9SGleb Smirnoff 		    scrub_opts_l
11063b3a8eb9SGleb Smirnoff 			{ $$ = scrub_opts; }
11073b3a8eb9SGleb Smirnoff 		| /* empty */ {
11083b3a8eb9SGleb Smirnoff 			bzero(&scrub_opts, sizeof scrub_opts);
11093b3a8eb9SGleb Smirnoff 			scrub_opts.rtableid = -1;
11103b3a8eb9SGleb Smirnoff 			$$ = scrub_opts;
11113b3a8eb9SGleb Smirnoff 		}
11123b3a8eb9SGleb Smirnoff 		;
11133b3a8eb9SGleb Smirnoff 
11143b3a8eb9SGleb Smirnoff scrub_opts_l	: scrub_opts_l scrub_opt
11153b3a8eb9SGleb Smirnoff 		| scrub_opt
11163b3a8eb9SGleb Smirnoff 		;
11173b3a8eb9SGleb Smirnoff 
11183b3a8eb9SGleb Smirnoff scrub_opt	: NODF	{
11193b3a8eb9SGleb Smirnoff 			if (scrub_opts.nodf) {
11203b3a8eb9SGleb Smirnoff 				yyerror("no-df cannot be respecified");
11213b3a8eb9SGleb Smirnoff 				YYERROR;
11223b3a8eb9SGleb Smirnoff 			}
11233b3a8eb9SGleb Smirnoff 			scrub_opts.nodf = 1;
11243b3a8eb9SGleb Smirnoff 		}
11253b3a8eb9SGleb Smirnoff 		| MINTTL NUMBER {
11263b3a8eb9SGleb Smirnoff 			if (scrub_opts.marker & SOM_MINTTL) {
11273b3a8eb9SGleb Smirnoff 				yyerror("min-ttl cannot be respecified");
11283b3a8eb9SGleb Smirnoff 				YYERROR;
11293b3a8eb9SGleb Smirnoff 			}
11303b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 255) {
11313b3a8eb9SGleb Smirnoff 				yyerror("illegal min-ttl value %d", $2);
11323b3a8eb9SGleb Smirnoff 				YYERROR;
11333b3a8eb9SGleb Smirnoff 			}
11343b3a8eb9SGleb Smirnoff 			scrub_opts.marker |= SOM_MINTTL;
11353b3a8eb9SGleb Smirnoff 			scrub_opts.minttl = $2;
11363b3a8eb9SGleb Smirnoff 		}
11373b3a8eb9SGleb Smirnoff 		| MAXMSS NUMBER {
11383b3a8eb9SGleb Smirnoff 			if (scrub_opts.marker & SOM_MAXMSS) {
11393b3a8eb9SGleb Smirnoff 				yyerror("max-mss cannot be respecified");
11403b3a8eb9SGleb Smirnoff 				YYERROR;
11413b3a8eb9SGleb Smirnoff 			}
11423b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 65535) {
11433b3a8eb9SGleb Smirnoff 				yyerror("illegal max-mss value %d", $2);
11443b3a8eb9SGleb Smirnoff 				YYERROR;
11453b3a8eb9SGleb Smirnoff 			}
11463b3a8eb9SGleb Smirnoff 			scrub_opts.marker |= SOM_MAXMSS;
11473b3a8eb9SGleb Smirnoff 			scrub_opts.maxmss = $2;
11483b3a8eb9SGleb Smirnoff 		}
11493b3a8eb9SGleb Smirnoff 		| SETTOS tos {
11503b3a8eb9SGleb Smirnoff 			if (scrub_opts.marker & SOM_SETTOS) {
11513b3a8eb9SGleb Smirnoff 				yyerror("set-tos cannot be respecified");
11523b3a8eb9SGleb Smirnoff 				YYERROR;
11533b3a8eb9SGleb Smirnoff 			}
11543b3a8eb9SGleb Smirnoff 			scrub_opts.marker |= SOM_SETTOS;
11553b3a8eb9SGleb Smirnoff 			scrub_opts.settos = $2;
11563b3a8eb9SGleb Smirnoff 		}
11573b3a8eb9SGleb Smirnoff 		| fragcache {
11583b3a8eb9SGleb Smirnoff 			if (scrub_opts.marker & SOM_FRAGCACHE) {
11593b3a8eb9SGleb Smirnoff 				yyerror("fragcache cannot be respecified");
11603b3a8eb9SGleb Smirnoff 				YYERROR;
11613b3a8eb9SGleb Smirnoff 			}
11623b3a8eb9SGleb Smirnoff 			scrub_opts.marker |= SOM_FRAGCACHE;
11633b3a8eb9SGleb Smirnoff 			scrub_opts.fragcache = $1;
11643b3a8eb9SGleb Smirnoff 		}
11653b3a8eb9SGleb Smirnoff 		| REASSEMBLE STRING {
11663b3a8eb9SGleb Smirnoff 			if (strcasecmp($2, "tcp") != 0) {
11673b3a8eb9SGleb Smirnoff 				yyerror("scrub reassemble supports only tcp, "
11683b3a8eb9SGleb Smirnoff 				    "not '%s'", $2);
11693b3a8eb9SGleb Smirnoff 				free($2);
11703b3a8eb9SGleb Smirnoff 				YYERROR;
11713b3a8eb9SGleb Smirnoff 			}
11723b3a8eb9SGleb Smirnoff 			free($2);
11733b3a8eb9SGleb Smirnoff 			if (scrub_opts.reassemble_tcp) {
11743b3a8eb9SGleb Smirnoff 				yyerror("reassemble tcp cannot be respecified");
11753b3a8eb9SGleb Smirnoff 				YYERROR;
11763b3a8eb9SGleb Smirnoff 			}
11773b3a8eb9SGleb Smirnoff 			scrub_opts.reassemble_tcp = 1;
11783b3a8eb9SGleb Smirnoff 		}
11793b3a8eb9SGleb Smirnoff 		| RANDOMID {
11803b3a8eb9SGleb Smirnoff 			if (scrub_opts.randomid) {
11813b3a8eb9SGleb Smirnoff 				yyerror("random-id cannot be respecified");
11823b3a8eb9SGleb Smirnoff 				YYERROR;
11833b3a8eb9SGleb Smirnoff 			}
11843b3a8eb9SGleb Smirnoff 			scrub_opts.randomid = 1;
11853b3a8eb9SGleb Smirnoff 		}
11863b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER				{
11873b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
11883b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
11893b3a8eb9SGleb Smirnoff 				YYERROR;
11903b3a8eb9SGleb Smirnoff 			}
11913b3a8eb9SGleb Smirnoff 			scrub_opts.rtableid = $2;
11923b3a8eb9SGleb Smirnoff 		}
11933b3a8eb9SGleb Smirnoff 		| not TAGGED string			{
11943b3a8eb9SGleb Smirnoff 			scrub_opts.match_tag = $3;
11953b3a8eb9SGleb Smirnoff 			scrub_opts.match_tag_not = $1;
11963b3a8eb9SGleb Smirnoff 		}
11973b3a8eb9SGleb Smirnoff 		;
11983b3a8eb9SGleb Smirnoff 
11993b3a8eb9SGleb Smirnoff fragcache	: FRAGMENT REASSEMBLE	{ $$ = 0; /* default */ }
120064b3b4d6SKristof Provost 		| FRAGMENT FRAGCROP	{ $$ = 0; }
120164b3b4d6SKristof Provost 		| FRAGMENT FRAGDROP	{ $$ = 0; }
12023b3a8eb9SGleb Smirnoff 		;
12033b3a8eb9SGleb Smirnoff 
12043b3a8eb9SGleb Smirnoff antispoof	: ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
12053b3a8eb9SGleb Smirnoff 			struct pf_rule		 r;
12063b3a8eb9SGleb Smirnoff 			struct node_host	*h = NULL, *hh;
12073b3a8eb9SGleb Smirnoff 			struct node_if		*i, *j;
12083b3a8eb9SGleb Smirnoff 
12093b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_FILTER))
12103b3a8eb9SGleb Smirnoff 				YYERROR;
12113b3a8eb9SGleb Smirnoff 
12123b3a8eb9SGleb Smirnoff 			for (i = $3; i; i = i->next) {
12133b3a8eb9SGleb Smirnoff 				bzero(&r, sizeof(r));
12143b3a8eb9SGleb Smirnoff 
12153b3a8eb9SGleb Smirnoff 				r.action = PF_DROP;
12163b3a8eb9SGleb Smirnoff 				r.direction = PF_IN;
12173b3a8eb9SGleb Smirnoff 				r.log = $2.log;
12183b3a8eb9SGleb Smirnoff 				r.logif = $2.logif;
12193b3a8eb9SGleb Smirnoff 				r.quick = $2.quick;
12203b3a8eb9SGleb Smirnoff 				r.af = $4;
12213b3a8eb9SGleb Smirnoff 				if (rule_label(&r, $5.label))
12223b3a8eb9SGleb Smirnoff 					YYERROR;
12233b3a8eb9SGleb Smirnoff 				r.rtableid = $5.rtableid;
12243b3a8eb9SGleb Smirnoff 				j = calloc(1, sizeof(struct node_if));
12253b3a8eb9SGleb Smirnoff 				if (j == NULL)
12263b3a8eb9SGleb Smirnoff 					err(1, "antispoof: calloc");
12273b3a8eb9SGleb Smirnoff 				if (strlcpy(j->ifname, i->ifname,
12283b3a8eb9SGleb Smirnoff 				    sizeof(j->ifname)) >= sizeof(j->ifname)) {
12293b3a8eb9SGleb Smirnoff 					free(j);
12303b3a8eb9SGleb Smirnoff 					yyerror("interface name too long");
12313b3a8eb9SGleb Smirnoff 					YYERROR;
12323b3a8eb9SGleb Smirnoff 				}
12333b3a8eb9SGleb Smirnoff 				j->not = 1;
12343b3a8eb9SGleb Smirnoff 				if (i->dynamic) {
12353b3a8eb9SGleb Smirnoff 					h = calloc(1, sizeof(*h));
12363b3a8eb9SGleb Smirnoff 					if (h == NULL)
12373b3a8eb9SGleb Smirnoff 						err(1, "address: calloc");
12383b3a8eb9SGleb Smirnoff 					h->addr.type = PF_ADDR_DYNIFTL;
12393b3a8eb9SGleb Smirnoff 					set_ipmask(h, 128);
12403b3a8eb9SGleb Smirnoff 					if (strlcpy(h->addr.v.ifname, i->ifname,
12413b3a8eb9SGleb Smirnoff 					    sizeof(h->addr.v.ifname)) >=
12423b3a8eb9SGleb Smirnoff 					    sizeof(h->addr.v.ifname)) {
12433b3a8eb9SGleb Smirnoff 						free(h);
12443b3a8eb9SGleb Smirnoff 						yyerror(
12453b3a8eb9SGleb Smirnoff 						    "interface name too long");
12463b3a8eb9SGleb Smirnoff 						YYERROR;
12473b3a8eb9SGleb Smirnoff 					}
12483b3a8eb9SGleb Smirnoff 					hh = malloc(sizeof(*hh));
12493b3a8eb9SGleb Smirnoff 					if (hh == NULL)
12503b3a8eb9SGleb Smirnoff 						 err(1, "address: malloc");
12513b3a8eb9SGleb Smirnoff 					bcopy(h, hh, sizeof(*hh));
12523b3a8eb9SGleb Smirnoff 					h->addr.iflags = PFI_AFLAG_NETWORK;
12533b3a8eb9SGleb Smirnoff 				} else {
12543b3a8eb9SGleb Smirnoff 					h = ifa_lookup(j->ifname,
12553b3a8eb9SGleb Smirnoff 					    PFI_AFLAG_NETWORK);
12563b3a8eb9SGleb Smirnoff 					hh = NULL;
12573b3a8eb9SGleb Smirnoff 				}
12583b3a8eb9SGleb Smirnoff 
12593b3a8eb9SGleb Smirnoff 				if (h != NULL)
12603b3a8eb9SGleb Smirnoff 					expand_rule(&r, j, NULL, NULL, NULL, h,
12613b3a8eb9SGleb Smirnoff 					    NULL, NULL, NULL, NULL, NULL,
12623b3a8eb9SGleb Smirnoff 					    NULL, "");
12633b3a8eb9SGleb Smirnoff 
12643b3a8eb9SGleb Smirnoff 				if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
12653b3a8eb9SGleb Smirnoff 					bzero(&r, sizeof(r));
12663b3a8eb9SGleb Smirnoff 
12673b3a8eb9SGleb Smirnoff 					r.action = PF_DROP;
12683b3a8eb9SGleb Smirnoff 					r.direction = PF_IN;
12693b3a8eb9SGleb Smirnoff 					r.log = $2.log;
12703b3a8eb9SGleb Smirnoff 					r.logif = $2.logif;
12713b3a8eb9SGleb Smirnoff 					r.quick = $2.quick;
12723b3a8eb9SGleb Smirnoff 					r.af = $4;
12733b3a8eb9SGleb Smirnoff 					if (rule_label(&r, $5.label))
12743b3a8eb9SGleb Smirnoff 						YYERROR;
12753b3a8eb9SGleb Smirnoff 					r.rtableid = $5.rtableid;
12763b3a8eb9SGleb Smirnoff 					if (hh != NULL)
12773b3a8eb9SGleb Smirnoff 						h = hh;
12783b3a8eb9SGleb Smirnoff 					else
12793b3a8eb9SGleb Smirnoff 						h = ifa_lookup(i->ifname, 0);
12803b3a8eb9SGleb Smirnoff 					if (h != NULL)
12813b3a8eb9SGleb Smirnoff 						expand_rule(&r, NULL, NULL,
12823b3a8eb9SGleb Smirnoff 						    NULL, NULL, h, NULL, NULL,
12833b3a8eb9SGleb Smirnoff 						    NULL, NULL, NULL, NULL, "");
12843b3a8eb9SGleb Smirnoff 				} else
12853b3a8eb9SGleb Smirnoff 					free(hh);
12863b3a8eb9SGleb Smirnoff 			}
12873b3a8eb9SGleb Smirnoff 			free($5.label);
12883b3a8eb9SGleb Smirnoff 		}
12893b3a8eb9SGleb Smirnoff 		;
12903b3a8eb9SGleb Smirnoff 
12913b3a8eb9SGleb Smirnoff antispoof_ifspc	: FOR antispoof_if			{ $$ = $2; }
12923b3a8eb9SGleb Smirnoff 		| FOR '{' optnl antispoof_iflst '}'	{ $$ = $4; }
12933b3a8eb9SGleb Smirnoff 		;
12943b3a8eb9SGleb Smirnoff 
12953b3a8eb9SGleb Smirnoff antispoof_iflst	: antispoof_if optnl			{ $$ = $1; }
12963b3a8eb9SGleb Smirnoff 		| antispoof_iflst comma antispoof_if optnl {
12973b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
12983b3a8eb9SGleb Smirnoff 			$1->tail = $3;
12993b3a8eb9SGleb Smirnoff 			$$ = $1;
13003b3a8eb9SGleb Smirnoff 		}
13013b3a8eb9SGleb Smirnoff 		;
13023b3a8eb9SGleb Smirnoff 
13033b3a8eb9SGleb Smirnoff antispoof_if	: if_item				{ $$ = $1; }
13043b3a8eb9SGleb Smirnoff 		| '(' if_item ')'			{
13053b3a8eb9SGleb Smirnoff 			$2->dynamic = 1;
13063b3a8eb9SGleb Smirnoff 			$$ = $2;
13073b3a8eb9SGleb Smirnoff 		}
13083b3a8eb9SGleb Smirnoff 		;
13093b3a8eb9SGleb Smirnoff 
13103b3a8eb9SGleb Smirnoff antispoof_opts	:	{
13113b3a8eb9SGleb Smirnoff 				bzero(&antispoof_opts, sizeof antispoof_opts);
13123b3a8eb9SGleb Smirnoff 				antispoof_opts.rtableid = -1;
13133b3a8eb9SGleb Smirnoff 			}
13143b3a8eb9SGleb Smirnoff 		    antispoof_opts_l
13153b3a8eb9SGleb Smirnoff 			{ $$ = antispoof_opts; }
13163b3a8eb9SGleb Smirnoff 		| /* empty */	{
13173b3a8eb9SGleb Smirnoff 			bzero(&antispoof_opts, sizeof antispoof_opts);
13183b3a8eb9SGleb Smirnoff 			antispoof_opts.rtableid = -1;
13193b3a8eb9SGleb Smirnoff 			$$ = antispoof_opts;
13203b3a8eb9SGleb Smirnoff 		}
13213b3a8eb9SGleb Smirnoff 		;
13223b3a8eb9SGleb Smirnoff 
13233b3a8eb9SGleb Smirnoff antispoof_opts_l	: antispoof_opts_l antispoof_opt
13243b3a8eb9SGleb Smirnoff 			| antispoof_opt
13253b3a8eb9SGleb Smirnoff 			;
13263b3a8eb9SGleb Smirnoff 
13273b3a8eb9SGleb Smirnoff antispoof_opt	: label	{
13283b3a8eb9SGleb Smirnoff 			if (antispoof_opts.label) {
13293b3a8eb9SGleb Smirnoff 				yyerror("label cannot be redefined");
13303b3a8eb9SGleb Smirnoff 				YYERROR;
13313b3a8eb9SGleb Smirnoff 			}
13323b3a8eb9SGleb Smirnoff 			antispoof_opts.label = $1;
13333b3a8eb9SGleb Smirnoff 		}
13343b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER				{
13353b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
13363b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
13373b3a8eb9SGleb Smirnoff 				YYERROR;
13383b3a8eb9SGleb Smirnoff 			}
13393b3a8eb9SGleb Smirnoff 			antispoof_opts.rtableid = $2;
13403b3a8eb9SGleb Smirnoff 		}
13413b3a8eb9SGleb Smirnoff 		;
13423b3a8eb9SGleb Smirnoff 
13433b3a8eb9SGleb Smirnoff not		: '!'		{ $$ = 1; }
13443b3a8eb9SGleb Smirnoff 		| /* empty */	{ $$ = 0; }
13453b3a8eb9SGleb Smirnoff 		;
13463b3a8eb9SGleb Smirnoff 
13473b3a8eb9SGleb Smirnoff tabledef	: TABLE '<' STRING '>' table_opts {
13483b3a8eb9SGleb Smirnoff 			struct node_host	 *h, *nh;
13493b3a8eb9SGleb Smirnoff 			struct node_tinit	 *ti, *nti;
13503b3a8eb9SGleb Smirnoff 
13513b3a8eb9SGleb Smirnoff 			if (strlen($3) >= PF_TABLE_NAME_SIZE) {
13523b3a8eb9SGleb Smirnoff 				yyerror("table name too long, max %d chars",
13533b3a8eb9SGleb Smirnoff 				    PF_TABLE_NAME_SIZE - 1);
13543b3a8eb9SGleb Smirnoff 				free($3);
13553b3a8eb9SGleb Smirnoff 				YYERROR;
13563b3a8eb9SGleb Smirnoff 			}
13573b3a8eb9SGleb Smirnoff 			if (pf->loadopt & PFCTL_FLAG_TABLE)
13583b3a8eb9SGleb Smirnoff 				if (process_tabledef($3, &$5)) {
13593b3a8eb9SGleb Smirnoff 					free($3);
13603b3a8eb9SGleb Smirnoff 					YYERROR;
13613b3a8eb9SGleb Smirnoff 				}
13623b3a8eb9SGleb Smirnoff 			free($3);
13633b3a8eb9SGleb Smirnoff 			for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
13643b3a8eb9SGleb Smirnoff 			    ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
13653b3a8eb9SGleb Smirnoff 				if (ti->file)
13663b3a8eb9SGleb Smirnoff 					free(ti->file);
13673b3a8eb9SGleb Smirnoff 				for (h = ti->host; h != NULL; h = nh) {
13683b3a8eb9SGleb Smirnoff 					nh = h->next;
13693b3a8eb9SGleb Smirnoff 					free(h);
13703b3a8eb9SGleb Smirnoff 				}
13713b3a8eb9SGleb Smirnoff 				nti = SIMPLEQ_NEXT(ti, entries);
13723b3a8eb9SGleb Smirnoff 				free(ti);
13733b3a8eb9SGleb Smirnoff 			}
13743b3a8eb9SGleb Smirnoff 		}
13753b3a8eb9SGleb Smirnoff 		;
13763b3a8eb9SGleb Smirnoff 
13773b3a8eb9SGleb Smirnoff table_opts	:	{
13783b3a8eb9SGleb Smirnoff 			bzero(&table_opts, sizeof table_opts);
13793b3a8eb9SGleb Smirnoff 			SIMPLEQ_INIT(&table_opts.init_nodes);
13803b3a8eb9SGleb Smirnoff 		}
13813b3a8eb9SGleb Smirnoff 		    table_opts_l
13823b3a8eb9SGleb Smirnoff 			{ $$ = table_opts; }
13833b3a8eb9SGleb Smirnoff 		| /* empty */
13843b3a8eb9SGleb Smirnoff 			{
13853b3a8eb9SGleb Smirnoff 			bzero(&table_opts, sizeof table_opts);
13863b3a8eb9SGleb Smirnoff 			SIMPLEQ_INIT(&table_opts.init_nodes);
13873b3a8eb9SGleb Smirnoff 			$$ = table_opts;
13883b3a8eb9SGleb Smirnoff 		}
13893b3a8eb9SGleb Smirnoff 		;
13903b3a8eb9SGleb Smirnoff 
13913b3a8eb9SGleb Smirnoff table_opts_l	: table_opts_l table_opt
13923b3a8eb9SGleb Smirnoff 		| table_opt
13933b3a8eb9SGleb Smirnoff 		;
13943b3a8eb9SGleb Smirnoff 
13953b3a8eb9SGleb Smirnoff table_opt	: STRING		{
13963b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "const"))
13973b3a8eb9SGleb Smirnoff 				table_opts.flags |= PFR_TFLAG_CONST;
13983b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "persist"))
13993b3a8eb9SGleb Smirnoff 				table_opts.flags |= PFR_TFLAG_PERSIST;
14003b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "counters"))
14013b3a8eb9SGleb Smirnoff 				table_opts.flags |= PFR_TFLAG_COUNTERS;
14023b3a8eb9SGleb Smirnoff 			else {
14033b3a8eb9SGleb Smirnoff 				yyerror("invalid table option '%s'", $1);
14043b3a8eb9SGleb Smirnoff 				free($1);
14053b3a8eb9SGleb Smirnoff 				YYERROR;
14063b3a8eb9SGleb Smirnoff 			}
14073b3a8eb9SGleb Smirnoff 			free($1);
14083b3a8eb9SGleb Smirnoff 		}
14093b3a8eb9SGleb Smirnoff 		| '{' optnl '}'		{ table_opts.init_addr = 1; }
14103b3a8eb9SGleb Smirnoff 		| '{' optnl host_list '}'	{
14113b3a8eb9SGleb Smirnoff 			struct node_host	*n;
14123b3a8eb9SGleb Smirnoff 			struct node_tinit	*ti;
14133b3a8eb9SGleb Smirnoff 
14143b3a8eb9SGleb Smirnoff 			for (n = $3; n != NULL; n = n->next) {
14153b3a8eb9SGleb Smirnoff 				switch (n->addr.type) {
14163b3a8eb9SGleb Smirnoff 				case PF_ADDR_ADDRMASK:
14173b3a8eb9SGleb Smirnoff 					continue; /* ok */
14183b3a8eb9SGleb Smirnoff 				case PF_ADDR_RANGE:
14193b3a8eb9SGleb Smirnoff 					yyerror("address ranges are not "
14203b3a8eb9SGleb Smirnoff 					    "permitted inside tables");
14213b3a8eb9SGleb Smirnoff 					break;
14223b3a8eb9SGleb Smirnoff 				case PF_ADDR_DYNIFTL:
14233b3a8eb9SGleb Smirnoff 					yyerror("dynamic addresses are not "
14243b3a8eb9SGleb Smirnoff 					    "permitted inside tables");
14253b3a8eb9SGleb Smirnoff 					break;
14263b3a8eb9SGleb Smirnoff 				case PF_ADDR_TABLE:
14273b3a8eb9SGleb Smirnoff 					yyerror("tables cannot contain tables");
14283b3a8eb9SGleb Smirnoff 					break;
14293b3a8eb9SGleb Smirnoff 				case PF_ADDR_NOROUTE:
14303b3a8eb9SGleb Smirnoff 					yyerror("\"no-route\" is not permitted "
14313b3a8eb9SGleb Smirnoff 					    "inside tables");
14323b3a8eb9SGleb Smirnoff 					break;
14333b3a8eb9SGleb Smirnoff 				case PF_ADDR_URPFFAILED:
14343b3a8eb9SGleb Smirnoff 					yyerror("\"urpf-failed\" is not "
14353b3a8eb9SGleb Smirnoff 					    "permitted inside tables");
14363b3a8eb9SGleb Smirnoff 					break;
14373b3a8eb9SGleb Smirnoff 				default:
14383b3a8eb9SGleb Smirnoff 					yyerror("unknown address type %d",
14393b3a8eb9SGleb Smirnoff 					    n->addr.type);
14403b3a8eb9SGleb Smirnoff 				}
14413b3a8eb9SGleb Smirnoff 				YYERROR;
14423b3a8eb9SGleb Smirnoff 			}
14433b3a8eb9SGleb Smirnoff 			if (!(ti = calloc(1, sizeof(*ti))))
14443b3a8eb9SGleb Smirnoff 				err(1, "table_opt: calloc");
14453b3a8eb9SGleb Smirnoff 			ti->host = $3;
14463b3a8eb9SGleb Smirnoff 			SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
14473b3a8eb9SGleb Smirnoff 			    entries);
14483b3a8eb9SGleb Smirnoff 			table_opts.init_addr = 1;
14493b3a8eb9SGleb Smirnoff 		}
14503b3a8eb9SGleb Smirnoff 		| FILENAME STRING	{
14513b3a8eb9SGleb Smirnoff 			struct node_tinit	*ti;
14523b3a8eb9SGleb Smirnoff 
14533b3a8eb9SGleb Smirnoff 			if (!(ti = calloc(1, sizeof(*ti))))
14543b3a8eb9SGleb Smirnoff 				err(1, "table_opt: calloc");
14553b3a8eb9SGleb Smirnoff 			ti->file = $2;
14563b3a8eb9SGleb Smirnoff 			SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
14573b3a8eb9SGleb Smirnoff 			    entries);
14583b3a8eb9SGleb Smirnoff 			table_opts.init_addr = 1;
14593b3a8eb9SGleb Smirnoff 		}
14603b3a8eb9SGleb Smirnoff 		;
14613b3a8eb9SGleb Smirnoff 
14623b3a8eb9SGleb Smirnoff altqif		: ALTQ interface queue_opts QUEUE qassign {
14633b3a8eb9SGleb Smirnoff 			struct pf_altq	a;
14643b3a8eb9SGleb Smirnoff 
14653b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_QUEUE))
14663b3a8eb9SGleb Smirnoff 				YYERROR;
14673b3a8eb9SGleb Smirnoff 
14683b3a8eb9SGleb Smirnoff 			memset(&a, 0, sizeof(a));
14693b3a8eb9SGleb Smirnoff 			if ($3.scheduler.qtype == ALTQT_NONE) {
14703b3a8eb9SGleb Smirnoff 				yyerror("no scheduler specified!");
14713b3a8eb9SGleb Smirnoff 				YYERROR;
14723b3a8eb9SGleb Smirnoff 			}
14733b3a8eb9SGleb Smirnoff 			a.scheduler = $3.scheduler.qtype;
14743b3a8eb9SGleb Smirnoff 			a.qlimit = $3.qlimit;
14753b3a8eb9SGleb Smirnoff 			a.tbrsize = $3.tbrsize;
14760a70aaf8SLuiz Otavio O Souza 			if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
14773b3a8eb9SGleb Smirnoff 				yyerror("no child queues specified");
14783b3a8eb9SGleb Smirnoff 				YYERROR;
14793b3a8eb9SGleb Smirnoff 			}
14803b3a8eb9SGleb Smirnoff 			if (expand_altq(&a, $2, $5, $3.queue_bwspec,
14813b3a8eb9SGleb Smirnoff 			    &$3.scheduler))
14823b3a8eb9SGleb Smirnoff 				YYERROR;
14833b3a8eb9SGleb Smirnoff 		}
14843b3a8eb9SGleb Smirnoff 		;
14853b3a8eb9SGleb Smirnoff 
14863b3a8eb9SGleb Smirnoff queuespec	: QUEUE STRING interface queue_opts qassign {
14873b3a8eb9SGleb Smirnoff 			struct pf_altq	a;
14883b3a8eb9SGleb Smirnoff 
14893b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_QUEUE)) {
14903b3a8eb9SGleb Smirnoff 				free($2);
14913b3a8eb9SGleb Smirnoff 				YYERROR;
14923b3a8eb9SGleb Smirnoff 			}
14933b3a8eb9SGleb Smirnoff 
14943b3a8eb9SGleb Smirnoff 			memset(&a, 0, sizeof(a));
14953b3a8eb9SGleb Smirnoff 
14963b3a8eb9SGleb Smirnoff 			if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
14973b3a8eb9SGleb Smirnoff 			    sizeof(a.qname)) {
14983b3a8eb9SGleb Smirnoff 				yyerror("queue name too long (max "
14993b3a8eb9SGleb Smirnoff 				    "%d chars)", PF_QNAME_SIZE-1);
15003b3a8eb9SGleb Smirnoff 				free($2);
15013b3a8eb9SGleb Smirnoff 				YYERROR;
15023b3a8eb9SGleb Smirnoff 			}
15033b3a8eb9SGleb Smirnoff 			free($2);
15043b3a8eb9SGleb Smirnoff 			if ($4.tbrsize) {
15053b3a8eb9SGleb Smirnoff 				yyerror("cannot specify tbrsize for queue");
15063b3a8eb9SGleb Smirnoff 				YYERROR;
15073b3a8eb9SGleb Smirnoff 			}
15083b3a8eb9SGleb Smirnoff 			if ($4.priority > 255) {
15093b3a8eb9SGleb Smirnoff 				yyerror("priority out of range: max 255");
15103b3a8eb9SGleb Smirnoff 				YYERROR;
15113b3a8eb9SGleb Smirnoff 			}
15123b3a8eb9SGleb Smirnoff 			a.priority = $4.priority;
15133b3a8eb9SGleb Smirnoff 			a.qlimit = $4.qlimit;
15143b3a8eb9SGleb Smirnoff 			a.scheduler = $4.scheduler.qtype;
15153b3a8eb9SGleb Smirnoff 			if (expand_queue(&a, $3, $5, $4.queue_bwspec,
15163b3a8eb9SGleb Smirnoff 			    &$4.scheduler)) {
15173b3a8eb9SGleb Smirnoff 				yyerror("errors in queue definition");
15183b3a8eb9SGleb Smirnoff 				YYERROR;
15193b3a8eb9SGleb Smirnoff 			}
15203b3a8eb9SGleb Smirnoff 		}
15213b3a8eb9SGleb Smirnoff 		;
15223b3a8eb9SGleb Smirnoff 
15233b3a8eb9SGleb Smirnoff queue_opts	:	{
15243b3a8eb9SGleb Smirnoff 			bzero(&queue_opts, sizeof queue_opts);
15253b3a8eb9SGleb Smirnoff 			queue_opts.priority = DEFAULT_PRIORITY;
15263b3a8eb9SGleb Smirnoff 			queue_opts.qlimit = DEFAULT_QLIMIT;
15273b3a8eb9SGleb Smirnoff 			queue_opts.scheduler.qtype = ALTQT_NONE;
15283b3a8eb9SGleb Smirnoff 			queue_opts.queue_bwspec.bw_percent = 100;
15293b3a8eb9SGleb Smirnoff 		}
15303b3a8eb9SGleb Smirnoff 		    queue_opts_l
15313b3a8eb9SGleb Smirnoff 			{ $$ = queue_opts; }
15323b3a8eb9SGleb Smirnoff 		| /* empty */ {
15333b3a8eb9SGleb Smirnoff 			bzero(&queue_opts, sizeof queue_opts);
15343b3a8eb9SGleb Smirnoff 			queue_opts.priority = DEFAULT_PRIORITY;
15353b3a8eb9SGleb Smirnoff 			queue_opts.qlimit = DEFAULT_QLIMIT;
15363b3a8eb9SGleb Smirnoff 			queue_opts.scheduler.qtype = ALTQT_NONE;
15373b3a8eb9SGleb Smirnoff 			queue_opts.queue_bwspec.bw_percent = 100;
15383b3a8eb9SGleb Smirnoff 			$$ = queue_opts;
15393b3a8eb9SGleb Smirnoff 		}
15403b3a8eb9SGleb Smirnoff 		;
15413b3a8eb9SGleb Smirnoff 
15423b3a8eb9SGleb Smirnoff queue_opts_l	: queue_opts_l queue_opt
15433b3a8eb9SGleb Smirnoff 		| queue_opt
15443b3a8eb9SGleb Smirnoff 		;
15453b3a8eb9SGleb Smirnoff 
15463b3a8eb9SGleb Smirnoff queue_opt	: BANDWIDTH bandwidth	{
15473b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_BWSPEC) {
15483b3a8eb9SGleb Smirnoff 				yyerror("bandwidth cannot be respecified");
15493b3a8eb9SGleb Smirnoff 				YYERROR;
15503b3a8eb9SGleb Smirnoff 			}
15513b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_BWSPEC;
15523b3a8eb9SGleb Smirnoff 			queue_opts.queue_bwspec = $2;
15533b3a8eb9SGleb Smirnoff 		}
15543b3a8eb9SGleb Smirnoff 		| PRIORITY NUMBER	{
15553b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_PRIORITY) {
15563b3a8eb9SGleb Smirnoff 				yyerror("priority cannot be respecified");
15573b3a8eb9SGleb Smirnoff 				YYERROR;
15583b3a8eb9SGleb Smirnoff 			}
15593b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 255) {
15603b3a8eb9SGleb Smirnoff 				yyerror("priority out of range: max 255");
15613b3a8eb9SGleb Smirnoff 				YYERROR;
15623b3a8eb9SGleb Smirnoff 			}
15633b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_PRIORITY;
15643b3a8eb9SGleb Smirnoff 			queue_opts.priority = $2;
15653b3a8eb9SGleb Smirnoff 		}
15663b3a8eb9SGleb Smirnoff 		| QLIMIT NUMBER	{
15673b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_QLIMIT) {
15683b3a8eb9SGleb Smirnoff 				yyerror("qlimit cannot be respecified");
15693b3a8eb9SGleb Smirnoff 				YYERROR;
15703b3a8eb9SGleb Smirnoff 			}
15713b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 65535) {
15723b3a8eb9SGleb Smirnoff 				yyerror("qlimit out of range: max 65535");
15733b3a8eb9SGleb Smirnoff 				YYERROR;
15743b3a8eb9SGleb Smirnoff 			}
15753b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_QLIMIT;
15763b3a8eb9SGleb Smirnoff 			queue_opts.qlimit = $2;
15773b3a8eb9SGleb Smirnoff 		}
15783b3a8eb9SGleb Smirnoff 		| scheduler	{
15793b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_SCHEDULER) {
15803b3a8eb9SGleb Smirnoff 				yyerror("scheduler cannot be respecified");
15813b3a8eb9SGleb Smirnoff 				YYERROR;
15823b3a8eb9SGleb Smirnoff 			}
15833b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_SCHEDULER;
15843b3a8eb9SGleb Smirnoff 			queue_opts.scheduler = $1;
15853b3a8eb9SGleb Smirnoff 		}
15863b3a8eb9SGleb Smirnoff 		| TBRSIZE NUMBER	{
15873b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_TBRSIZE) {
15883b3a8eb9SGleb Smirnoff 				yyerror("tbrsize cannot be respecified");
15893b3a8eb9SGleb Smirnoff 				YYERROR;
15903b3a8eb9SGleb Smirnoff 			}
15913b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 65535) {
15923b3a8eb9SGleb Smirnoff 				yyerror("tbrsize too big: max 65535");
15933b3a8eb9SGleb Smirnoff 				YYERROR;
15943b3a8eb9SGleb Smirnoff 			}
15953b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_TBRSIZE;
15963b3a8eb9SGleb Smirnoff 			queue_opts.tbrsize = $2;
15973b3a8eb9SGleb Smirnoff 		}
15983b3a8eb9SGleb Smirnoff 		;
15993b3a8eb9SGleb Smirnoff 
16003b3a8eb9SGleb Smirnoff bandwidth	: STRING {
16013b3a8eb9SGleb Smirnoff 			double	 bps;
16023b3a8eb9SGleb Smirnoff 			char	*cp;
16033b3a8eb9SGleb Smirnoff 
16043b3a8eb9SGleb Smirnoff 			$$.bw_percent = 0;
16053b3a8eb9SGleb Smirnoff 
16063b3a8eb9SGleb Smirnoff 			bps = strtod($1, &cp);
16073b3a8eb9SGleb Smirnoff 			if (cp != NULL) {
1608*db1bbde6SLuiz Otavio O Souza 				if (strlen(cp) > 1) {
1609*db1bbde6SLuiz Otavio O Souza 					char *cu = cp + 1;
1610*db1bbde6SLuiz Otavio O Souza 					if (!strcmp(cu, "Bit") ||
1611*db1bbde6SLuiz Otavio O Souza 					    !strcmp(cu, "B") ||
1612*db1bbde6SLuiz Otavio O Souza 					    !strcmp(cu, "bit") ||
1613*db1bbde6SLuiz Otavio O Souza 					    !strcmp(cu, "b")) {
1614*db1bbde6SLuiz Otavio O Souza 						*cu = 0;
1615*db1bbde6SLuiz Otavio O Souza 					}
1616*db1bbde6SLuiz Otavio O Souza 				}
16173b3a8eb9SGleb Smirnoff 				if (!strcmp(cp, "b"))
16183b3a8eb9SGleb Smirnoff 					; /* nothing */
1619*db1bbde6SLuiz Otavio O Souza 				else if (!strcmp(cp, "K"))
16203b3a8eb9SGleb Smirnoff 					bps *= 1000;
1621*db1bbde6SLuiz Otavio O Souza 				else if (!strcmp(cp, "M"))
16223b3a8eb9SGleb Smirnoff 					bps *= 1000 * 1000;
1623*db1bbde6SLuiz Otavio O Souza 				else if (!strcmp(cp, "G"))
16243b3a8eb9SGleb Smirnoff 					bps *= 1000 * 1000 * 1000;
16253b3a8eb9SGleb Smirnoff 				else if (!strcmp(cp, "%")) {
16263b3a8eb9SGleb Smirnoff 					if (bps < 0 || bps > 100) {
16273b3a8eb9SGleb Smirnoff 						yyerror("bandwidth spec "
16283b3a8eb9SGleb Smirnoff 						    "out of range");
16293b3a8eb9SGleb Smirnoff 						free($1);
16303b3a8eb9SGleb Smirnoff 						YYERROR;
16313b3a8eb9SGleb Smirnoff 					}
16323b3a8eb9SGleb Smirnoff 					$$.bw_percent = bps;
16333b3a8eb9SGleb Smirnoff 					bps = 0;
16343b3a8eb9SGleb Smirnoff 				} else {
16353b3a8eb9SGleb Smirnoff 					yyerror("unknown unit %s", cp);
16363b3a8eb9SGleb Smirnoff 					free($1);
16373b3a8eb9SGleb Smirnoff 					YYERROR;
16383b3a8eb9SGleb Smirnoff 				}
16393b3a8eb9SGleb Smirnoff 			}
16403b3a8eb9SGleb Smirnoff 			free($1);
16413b3a8eb9SGleb Smirnoff 			$$.bw_absolute = (u_int32_t)bps;
16423b3a8eb9SGleb Smirnoff 		}
16433b3a8eb9SGleb Smirnoff 		| NUMBER {
16443b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > UINT_MAX) {
16453b3a8eb9SGleb Smirnoff 				yyerror("bandwidth number too big");
16463b3a8eb9SGleb Smirnoff 				YYERROR;
16473b3a8eb9SGleb Smirnoff 			}
16483b3a8eb9SGleb Smirnoff 			$$.bw_percent = 0;
16493b3a8eb9SGleb Smirnoff 			$$.bw_absolute = $1;
16503b3a8eb9SGleb Smirnoff 		}
16513b3a8eb9SGleb Smirnoff 		;
16523b3a8eb9SGleb Smirnoff 
16533b3a8eb9SGleb Smirnoff scheduler	: CBQ				{
16543b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_CBQ;
16553b3a8eb9SGleb Smirnoff 			$$.data.cbq_opts.flags = 0;
16563b3a8eb9SGleb Smirnoff 		}
16573b3a8eb9SGleb Smirnoff 		| CBQ '(' cbqflags_list ')'	{
16583b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_CBQ;
16593b3a8eb9SGleb Smirnoff 			$$.data.cbq_opts.flags = $3;
16603b3a8eb9SGleb Smirnoff 		}
16613b3a8eb9SGleb Smirnoff 		| PRIQ				{
16623b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_PRIQ;
16633b3a8eb9SGleb Smirnoff 			$$.data.priq_opts.flags = 0;
16643b3a8eb9SGleb Smirnoff 		}
16653b3a8eb9SGleb Smirnoff 		| PRIQ '(' priqflags_list ')'	{
16663b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_PRIQ;
16673b3a8eb9SGleb Smirnoff 			$$.data.priq_opts.flags = $3;
16683b3a8eb9SGleb Smirnoff 		}
16693b3a8eb9SGleb Smirnoff 		| HFSC				{
16703b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_HFSC;
16713b3a8eb9SGleb Smirnoff 			bzero(&$$.data.hfsc_opts,
16723b3a8eb9SGleb Smirnoff 			    sizeof(struct node_hfsc_opts));
16733b3a8eb9SGleb Smirnoff 		}
16743b3a8eb9SGleb Smirnoff 		| HFSC '(' hfsc_opts ')'	{
16753b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_HFSC;
16763b3a8eb9SGleb Smirnoff 			$$.data.hfsc_opts = $3;
16773b3a8eb9SGleb Smirnoff 		}
1678a5b789f6SErmal Luçi 		| FAIRQ				{
1679a5b789f6SErmal Luçi 			$$.qtype = ALTQT_FAIRQ;
1680a5b789f6SErmal Luçi 			bzero(&$$.data.fairq_opts,
1681a5b789f6SErmal Luçi 				sizeof(struct node_fairq_opts));
1682a5b789f6SErmal Luçi 		}
1683a5b789f6SErmal Luçi 		| FAIRQ '(' fairq_opts ')'      {
1684a5b789f6SErmal Luçi 			$$.qtype = ALTQT_FAIRQ;
1685a5b789f6SErmal Luçi 			$$.data.fairq_opts = $3;
1686a5b789f6SErmal Luçi 		}
16870a70aaf8SLuiz Otavio O Souza 		| CODEL				{
16880a70aaf8SLuiz Otavio O Souza 			$$.qtype = ALTQT_CODEL;
16890a70aaf8SLuiz Otavio O Souza 			bzero(&$$.data.codel_opts,
16900a70aaf8SLuiz Otavio O Souza 				sizeof(struct codel_opts));
16910a70aaf8SLuiz Otavio O Souza 		}
16920a70aaf8SLuiz Otavio O Souza 		| CODEL '(' codel_opts ')'	{
16930a70aaf8SLuiz Otavio O Souza 			$$.qtype = ALTQT_CODEL;
16940a70aaf8SLuiz Otavio O Souza 			$$.data.codel_opts = $3;
16950a70aaf8SLuiz Otavio O Souza 		}
16963b3a8eb9SGleb Smirnoff 		;
16973b3a8eb9SGleb Smirnoff 
16983b3a8eb9SGleb Smirnoff cbqflags_list	: cbqflags_item				{ $$ |= $1; }
16993b3a8eb9SGleb Smirnoff 		| cbqflags_list comma cbqflags_item	{ $$ |= $3; }
17003b3a8eb9SGleb Smirnoff 		;
17013b3a8eb9SGleb Smirnoff 
17023b3a8eb9SGleb Smirnoff cbqflags_item	: STRING	{
17033b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "default"))
17043b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_DEFCLASS;
17053b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "borrow"))
17063b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_BORROW;
17073b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "red"))
17083b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_RED;
17093b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "ecn"))
17103b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_RED|CBQCLF_ECN;
17113b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "rio"))
17123b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_RIO;
17130a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
17140a70aaf8SLuiz Otavio O Souza 				$$ = CBQCLF_CODEL;
17153b3a8eb9SGleb Smirnoff 			else {
17163b3a8eb9SGleb Smirnoff 				yyerror("unknown cbq flag \"%s\"", $1);
17173b3a8eb9SGleb Smirnoff 				free($1);
17183b3a8eb9SGleb Smirnoff 				YYERROR;
17193b3a8eb9SGleb Smirnoff 			}
17203b3a8eb9SGleb Smirnoff 			free($1);
17213b3a8eb9SGleb Smirnoff 		}
17223b3a8eb9SGleb Smirnoff 		;
17233b3a8eb9SGleb Smirnoff 
17243b3a8eb9SGleb Smirnoff priqflags_list	: priqflags_item			{ $$ |= $1; }
17253b3a8eb9SGleb Smirnoff 		| priqflags_list comma priqflags_item	{ $$ |= $3; }
17263b3a8eb9SGleb Smirnoff 		;
17273b3a8eb9SGleb Smirnoff 
17283b3a8eb9SGleb Smirnoff priqflags_item	: STRING	{
17293b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "default"))
17303b3a8eb9SGleb Smirnoff 				$$ = PRCF_DEFAULTCLASS;
17313b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "red"))
17323b3a8eb9SGleb Smirnoff 				$$ = PRCF_RED;
17333b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "ecn"))
17343b3a8eb9SGleb Smirnoff 				$$ = PRCF_RED|PRCF_ECN;
17353b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "rio"))
17363b3a8eb9SGleb Smirnoff 				$$ = PRCF_RIO;
17370a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
17380a70aaf8SLuiz Otavio O Souza 				$$ = PRCF_CODEL;
17393b3a8eb9SGleb Smirnoff 			else {
17403b3a8eb9SGleb Smirnoff 				yyerror("unknown priq flag \"%s\"", $1);
17413b3a8eb9SGleb Smirnoff 				free($1);
17423b3a8eb9SGleb Smirnoff 				YYERROR;
17433b3a8eb9SGleb Smirnoff 			}
17443b3a8eb9SGleb Smirnoff 			free($1);
17453b3a8eb9SGleb Smirnoff 		}
17463b3a8eb9SGleb Smirnoff 		;
17473b3a8eb9SGleb Smirnoff 
17483b3a8eb9SGleb Smirnoff hfsc_opts	:	{
17493b3a8eb9SGleb Smirnoff 				bzero(&hfsc_opts,
17503b3a8eb9SGleb Smirnoff 				    sizeof(struct node_hfsc_opts));
17513b3a8eb9SGleb Smirnoff 			}
17523b3a8eb9SGleb Smirnoff 		    hfscopts_list				{
17533b3a8eb9SGleb Smirnoff 			$$ = hfsc_opts;
17543b3a8eb9SGleb Smirnoff 		}
17553b3a8eb9SGleb Smirnoff 		;
17563b3a8eb9SGleb Smirnoff 
17573b3a8eb9SGleb Smirnoff hfscopts_list	: hfscopts_item
17583b3a8eb9SGleb Smirnoff 		| hfscopts_list comma hfscopts_item
17593b3a8eb9SGleb Smirnoff 		;
17603b3a8eb9SGleb Smirnoff 
17613b3a8eb9SGleb Smirnoff hfscopts_item	: LINKSHARE bandwidth				{
17623b3a8eb9SGleb Smirnoff 			if (hfsc_opts.linkshare.used) {
17633b3a8eb9SGleb Smirnoff 				yyerror("linkshare already specified");
17643b3a8eb9SGleb Smirnoff 				YYERROR;
17653b3a8eb9SGleb Smirnoff 			}
17663b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.m2 = $2;
17673b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.used = 1;
17683b3a8eb9SGleb Smirnoff 		}
17693b3a8eb9SGleb Smirnoff 		| LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'
17703b3a8eb9SGleb Smirnoff 		    {
17713b3a8eb9SGleb Smirnoff 			if ($5 < 0 || $5 > INT_MAX) {
17723b3a8eb9SGleb Smirnoff 				yyerror("timing in curve out of range");
17733b3a8eb9SGleb Smirnoff 				YYERROR;
17743b3a8eb9SGleb Smirnoff 			}
17753b3a8eb9SGleb Smirnoff 			if (hfsc_opts.linkshare.used) {
17763b3a8eb9SGleb Smirnoff 				yyerror("linkshare already specified");
17773b3a8eb9SGleb Smirnoff 				YYERROR;
17783b3a8eb9SGleb Smirnoff 			}
17793b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.m1 = $3;
17803b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.d = $5;
17813b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.m2 = $7;
17823b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.used = 1;
17833b3a8eb9SGleb Smirnoff 		}
17843b3a8eb9SGleb Smirnoff 		| REALTIME bandwidth				{
17853b3a8eb9SGleb Smirnoff 			if (hfsc_opts.realtime.used) {
17863b3a8eb9SGleb Smirnoff 				yyerror("realtime already specified");
17873b3a8eb9SGleb Smirnoff 				YYERROR;
17883b3a8eb9SGleb Smirnoff 			}
17893b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.m2 = $2;
17903b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.used = 1;
17913b3a8eb9SGleb Smirnoff 		}
17923b3a8eb9SGleb Smirnoff 		| REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'
17933b3a8eb9SGleb Smirnoff 		    {
17943b3a8eb9SGleb Smirnoff 			if ($5 < 0 || $5 > INT_MAX) {
17953b3a8eb9SGleb Smirnoff 				yyerror("timing in curve out of range");
17963b3a8eb9SGleb Smirnoff 				YYERROR;
17973b3a8eb9SGleb Smirnoff 			}
17983b3a8eb9SGleb Smirnoff 			if (hfsc_opts.realtime.used) {
17993b3a8eb9SGleb Smirnoff 				yyerror("realtime already specified");
18003b3a8eb9SGleb Smirnoff 				YYERROR;
18013b3a8eb9SGleb Smirnoff 			}
18023b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.m1 = $3;
18033b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.d = $5;
18043b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.m2 = $7;
18053b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.used = 1;
18063b3a8eb9SGleb Smirnoff 		}
18073b3a8eb9SGleb Smirnoff 		| UPPERLIMIT bandwidth				{
18083b3a8eb9SGleb Smirnoff 			if (hfsc_opts.upperlimit.used) {
18093b3a8eb9SGleb Smirnoff 				yyerror("upperlimit already specified");
18103b3a8eb9SGleb Smirnoff 				YYERROR;
18113b3a8eb9SGleb Smirnoff 			}
18123b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.m2 = $2;
18133b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.used = 1;
18143b3a8eb9SGleb Smirnoff 		}
18153b3a8eb9SGleb Smirnoff 		| UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'
18163b3a8eb9SGleb Smirnoff 		    {
18173b3a8eb9SGleb Smirnoff 			if ($5 < 0 || $5 > INT_MAX) {
18183b3a8eb9SGleb Smirnoff 				yyerror("timing in curve out of range");
18193b3a8eb9SGleb Smirnoff 				YYERROR;
18203b3a8eb9SGleb Smirnoff 			}
18213b3a8eb9SGleb Smirnoff 			if (hfsc_opts.upperlimit.used) {
18223b3a8eb9SGleb Smirnoff 				yyerror("upperlimit already specified");
18233b3a8eb9SGleb Smirnoff 				YYERROR;
18243b3a8eb9SGleb Smirnoff 			}
18253b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.m1 = $3;
18263b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.d = $5;
18273b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.m2 = $7;
18283b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.used = 1;
18293b3a8eb9SGleb Smirnoff 		}
18303b3a8eb9SGleb Smirnoff 		| STRING	{
18313b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "default"))
18323b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_DEFAULTCLASS;
18333b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "red"))
18343b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_RED;
18353b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "ecn"))
18363b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
18373b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "rio"))
18383b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_RIO;
18390a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
18400a70aaf8SLuiz Otavio O Souza 				hfsc_opts.flags |= HFCF_CODEL;
18413b3a8eb9SGleb Smirnoff 			else {
18423b3a8eb9SGleb Smirnoff 				yyerror("unknown hfsc flag \"%s\"", $1);
18433b3a8eb9SGleb Smirnoff 				free($1);
18443b3a8eb9SGleb Smirnoff 				YYERROR;
18453b3a8eb9SGleb Smirnoff 			}
18463b3a8eb9SGleb Smirnoff 			free($1);
18473b3a8eb9SGleb Smirnoff 		}
18483b3a8eb9SGleb Smirnoff 		;
18493b3a8eb9SGleb Smirnoff 
1850a5b789f6SErmal Luçi fairq_opts	:	{
1851a5b789f6SErmal Luçi 				bzero(&fairq_opts,
1852a5b789f6SErmal Luçi 				    sizeof(struct node_fairq_opts));
1853a5b789f6SErmal Luçi 			}
1854a5b789f6SErmal Luçi 		    fairqopts_list				{
1855a5b789f6SErmal Luçi 			$$ = fairq_opts;
1856a5b789f6SErmal Luçi 		}
1857a5b789f6SErmal Luçi 		;
1858a5b789f6SErmal Luçi 
1859a5b789f6SErmal Luçi fairqopts_list	: fairqopts_item
1860a5b789f6SErmal Luçi 		| fairqopts_list comma fairqopts_item
1861a5b789f6SErmal Luçi 		;
1862a5b789f6SErmal Luçi 
1863a5b789f6SErmal Luçi fairqopts_item	: LINKSHARE bandwidth				{
1864a5b789f6SErmal Luçi 			if (fairq_opts.linkshare.used) {
1865a5b789f6SErmal Luçi 				yyerror("linkshare already specified");
1866a5b789f6SErmal Luçi 				YYERROR;
1867a5b789f6SErmal Luçi 			}
1868a5b789f6SErmal Luçi 			fairq_opts.linkshare.m2 = $2;
1869a5b789f6SErmal Luçi 			fairq_opts.linkshare.used = 1;
1870a5b789f6SErmal Luçi 		}
1871a5b789f6SErmal Luçi 		| LINKSHARE '(' bandwidth number bandwidth ')'	{
1872a5b789f6SErmal Luçi 			if (fairq_opts.linkshare.used) {
1873a5b789f6SErmal Luçi 				yyerror("linkshare already specified");
1874a5b789f6SErmal Luçi 				YYERROR;
1875a5b789f6SErmal Luçi 			}
1876a5b789f6SErmal Luçi 			fairq_opts.linkshare.m1 = $3;
1877a5b789f6SErmal Luçi 			fairq_opts.linkshare.d = $4;
1878a5b789f6SErmal Luçi 			fairq_opts.linkshare.m2 = $5;
1879a5b789f6SErmal Luçi 			fairq_opts.linkshare.used = 1;
1880a5b789f6SErmal Luçi 		}
1881a5b789f6SErmal Luçi 		| HOGS bandwidth {
1882a5b789f6SErmal Luçi 			fairq_opts.hogs_bw = $2;
1883a5b789f6SErmal Luçi 		}
1884a5b789f6SErmal Luçi 		| BUCKETS number {
1885a5b789f6SErmal Luçi 			fairq_opts.nbuckets = $2;
1886a5b789f6SErmal Luçi 		}
1887a5b789f6SErmal Luçi 		| STRING	{
1888a5b789f6SErmal Luçi 			if (!strcmp($1, "default"))
1889a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_DEFAULTCLASS;
1890a5b789f6SErmal Luçi 			else if (!strcmp($1, "red"))
1891a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_RED;
1892a5b789f6SErmal Luçi 			else if (!strcmp($1, "ecn"))
1893a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_RED|FARF_ECN;
1894a5b789f6SErmal Luçi 			else if (!strcmp($1, "rio"))
1895a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_RIO;
18960a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
18970a70aaf8SLuiz Otavio O Souza 				fairq_opts.flags |= FARF_CODEL;
1898a5b789f6SErmal Luçi 			else {
1899a5b789f6SErmal Luçi 				yyerror("unknown fairq flag \"%s\"", $1);
1900a5b789f6SErmal Luçi 				free($1);
1901a5b789f6SErmal Luçi 				YYERROR;
1902a5b789f6SErmal Luçi 			}
1903a5b789f6SErmal Luçi 			free($1);
1904a5b789f6SErmal Luçi 		}
1905a5b789f6SErmal Luçi 		;
1906a5b789f6SErmal Luçi 
19070a70aaf8SLuiz Otavio O Souza codel_opts	:	{
19080a70aaf8SLuiz Otavio O Souza 				bzero(&codel_opts,
19090a70aaf8SLuiz Otavio O Souza 				    sizeof(struct codel_opts));
19100a70aaf8SLuiz Otavio O Souza 			}
19110a70aaf8SLuiz Otavio O Souza 		    codelopts_list				{
19120a70aaf8SLuiz Otavio O Souza 			$$ = codel_opts;
19130a70aaf8SLuiz Otavio O Souza 		}
19140a70aaf8SLuiz Otavio O Souza 		;
19150a70aaf8SLuiz Otavio O Souza 
19160a70aaf8SLuiz Otavio O Souza codelopts_list	: codelopts_item
19170a70aaf8SLuiz Otavio O Souza 		| codelopts_list comma codelopts_item
19180a70aaf8SLuiz Otavio O Souza 		;
19190a70aaf8SLuiz Otavio O Souza 
19200a70aaf8SLuiz Otavio O Souza codelopts_item	: INTERVAL number				{
19210a70aaf8SLuiz Otavio O Souza 			if (codel_opts.interval) {
19220a70aaf8SLuiz Otavio O Souza 				yyerror("interval already specified");
19230a70aaf8SLuiz Otavio O Souza 				YYERROR;
19240a70aaf8SLuiz Otavio O Souza 			}
19250a70aaf8SLuiz Otavio O Souza 			codel_opts.interval = $2;
19260a70aaf8SLuiz Otavio O Souza 		}
19270a70aaf8SLuiz Otavio O Souza 		| TARGET number					{
19280a70aaf8SLuiz Otavio O Souza 			if (codel_opts.target) {
19290a70aaf8SLuiz Otavio O Souza 				yyerror("target already specified");
19300a70aaf8SLuiz Otavio O Souza 				YYERROR;
19310a70aaf8SLuiz Otavio O Souza 			}
19320a70aaf8SLuiz Otavio O Souza 			codel_opts.target = $2;
19330a70aaf8SLuiz Otavio O Souza 		}
19340a70aaf8SLuiz Otavio O Souza 		| STRING					{
19350a70aaf8SLuiz Otavio O Souza 			if (!strcmp($1, "ecn"))
19360a70aaf8SLuiz Otavio O Souza 				codel_opts.ecn = 1;
19370a70aaf8SLuiz Otavio O Souza 			else {
19380a70aaf8SLuiz Otavio O Souza 				yyerror("unknown codel option \"%s\"", $1);
19390a70aaf8SLuiz Otavio O Souza 				free($1);
19400a70aaf8SLuiz Otavio O Souza 				YYERROR;
19410a70aaf8SLuiz Otavio O Souza 			}
19420a70aaf8SLuiz Otavio O Souza 			free($1);
19430a70aaf8SLuiz Otavio O Souza 		}
19440a70aaf8SLuiz Otavio O Souza 		;
19450a70aaf8SLuiz Otavio O Souza 
19463b3a8eb9SGleb Smirnoff qassign		: /* empty */		{ $$ = NULL; }
19473b3a8eb9SGleb Smirnoff 		| qassign_item		{ $$ = $1; }
19483b3a8eb9SGleb Smirnoff 		| '{' optnl qassign_list '}'	{ $$ = $3; }
19493b3a8eb9SGleb Smirnoff 		;
19503b3a8eb9SGleb Smirnoff 
19513b3a8eb9SGleb Smirnoff qassign_list	: qassign_item optnl		{ $$ = $1; }
19523b3a8eb9SGleb Smirnoff 		| qassign_list comma qassign_item optnl	{
19533b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
19543b3a8eb9SGleb Smirnoff 			$1->tail = $3;
19553b3a8eb9SGleb Smirnoff 			$$ = $1;
19563b3a8eb9SGleb Smirnoff 		}
19573b3a8eb9SGleb Smirnoff 		;
19583b3a8eb9SGleb Smirnoff 
19593b3a8eb9SGleb Smirnoff qassign_item	: STRING			{
19603b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_queue));
19613b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
19623b3a8eb9SGleb Smirnoff 				err(1, "qassign_item: calloc");
19633b3a8eb9SGleb Smirnoff 			if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
19643b3a8eb9SGleb Smirnoff 			    sizeof($$->queue)) {
19653b3a8eb9SGleb Smirnoff 				yyerror("queue name '%s' too long (max "
19663b3a8eb9SGleb Smirnoff 				    "%d chars)", $1, sizeof($$->queue)-1);
19673b3a8eb9SGleb Smirnoff 				free($1);
19683b3a8eb9SGleb Smirnoff 				free($$);
19693b3a8eb9SGleb Smirnoff 				YYERROR;
19703b3a8eb9SGleb Smirnoff 			}
19713b3a8eb9SGleb Smirnoff 			free($1);
19723b3a8eb9SGleb Smirnoff 			$$->next = NULL;
19733b3a8eb9SGleb Smirnoff 			$$->tail = $$;
19743b3a8eb9SGleb Smirnoff 		}
19753b3a8eb9SGleb Smirnoff 		;
19763b3a8eb9SGleb Smirnoff 
19773b3a8eb9SGleb Smirnoff pfrule		: action dir logquick interface route af proto fromto
19783b3a8eb9SGleb Smirnoff 		    filter_opts
19793b3a8eb9SGleb Smirnoff 		{
19803b3a8eb9SGleb Smirnoff 			struct pf_rule		 r;
19813b3a8eb9SGleb Smirnoff 			struct node_state_opt	*o;
19823b3a8eb9SGleb Smirnoff 			struct node_proto	*proto;
19833b3a8eb9SGleb Smirnoff 			int			 srctrack = 0;
19843b3a8eb9SGleb Smirnoff 			int			 statelock = 0;
19853b3a8eb9SGleb Smirnoff 			int			 adaptive = 0;
19863b3a8eb9SGleb Smirnoff 			int			 defaults = 0;
19873b3a8eb9SGleb Smirnoff 
19883b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_FILTER))
19893b3a8eb9SGleb Smirnoff 				YYERROR;
19903b3a8eb9SGleb Smirnoff 
19913b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
19923b3a8eb9SGleb Smirnoff 
19933b3a8eb9SGleb Smirnoff 			r.action = $1.b1;
19943b3a8eb9SGleb Smirnoff 			switch ($1.b2) {
19953b3a8eb9SGleb Smirnoff 			case PFRULE_RETURNRST:
19963b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RETURNRST;
19973b3a8eb9SGleb Smirnoff 				r.return_ttl = $1.w;
19983b3a8eb9SGleb Smirnoff 				break;
19993b3a8eb9SGleb Smirnoff 			case PFRULE_RETURNICMP:
20003b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RETURNICMP;
20013b3a8eb9SGleb Smirnoff 				r.return_icmp = $1.w;
20023b3a8eb9SGleb Smirnoff 				r.return_icmp6 = $1.w2;
20033b3a8eb9SGleb Smirnoff 				break;
20043b3a8eb9SGleb Smirnoff 			case PFRULE_RETURN:
20053b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RETURN;
20063b3a8eb9SGleb Smirnoff 				r.return_icmp = $1.w;
20073b3a8eb9SGleb Smirnoff 				r.return_icmp6 = $1.w2;
20083b3a8eb9SGleb Smirnoff 				break;
20093b3a8eb9SGleb Smirnoff 			}
20103b3a8eb9SGleb Smirnoff 			r.direction = $2;
20113b3a8eb9SGleb Smirnoff 			r.log = $3.log;
20123b3a8eb9SGleb Smirnoff 			r.logif = $3.logif;
20133b3a8eb9SGleb Smirnoff 			r.quick = $3.quick;
20143b3a8eb9SGleb Smirnoff 			r.prob = $9.prob;
20153b3a8eb9SGleb Smirnoff 			r.rtableid = $9.rtableid;
20163b3a8eb9SGleb Smirnoff 
20173b3a8eb9SGleb Smirnoff 			r.af = $6;
20183b3a8eb9SGleb Smirnoff 			if ($9.tag)
20193b3a8eb9SGleb Smirnoff 				if (strlcpy(r.tagname, $9.tag,
20203b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
20213b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
20223b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
20233b3a8eb9SGleb Smirnoff 					YYERROR;
20243b3a8eb9SGleb Smirnoff 				}
20253b3a8eb9SGleb Smirnoff 			if ($9.match_tag)
20263b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $9.match_tag,
20273b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
20283b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
20293b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
20303b3a8eb9SGleb Smirnoff 					YYERROR;
20313b3a8eb9SGleb Smirnoff 				}
20323b3a8eb9SGleb Smirnoff 			r.match_tag_not = $9.match_tag_not;
20333b3a8eb9SGleb Smirnoff 			if (rule_label(&r, $9.label))
20343b3a8eb9SGleb Smirnoff 				YYERROR;
20353b3a8eb9SGleb Smirnoff 			free($9.label);
20363b3a8eb9SGleb Smirnoff 			r.flags = $9.flags.b1;
20373b3a8eb9SGleb Smirnoff 			r.flagset = $9.flags.b2;
20383b3a8eb9SGleb Smirnoff 			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
20393b3a8eb9SGleb Smirnoff 				yyerror("flags always false");
20403b3a8eb9SGleb Smirnoff 				YYERROR;
20413b3a8eb9SGleb Smirnoff 			}
20423b3a8eb9SGleb Smirnoff 			if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
20433b3a8eb9SGleb Smirnoff 				for (proto = $7; proto != NULL &&
20443b3a8eb9SGleb Smirnoff 				    proto->proto != IPPROTO_TCP;
20453b3a8eb9SGleb Smirnoff 				    proto = proto->next)
20463b3a8eb9SGleb Smirnoff 					;	/* nothing */
20473b3a8eb9SGleb Smirnoff 				if (proto == NULL && $7 != NULL) {
20483b3a8eb9SGleb Smirnoff 					if ($9.flags.b1 || $9.flags.b2)
20493b3a8eb9SGleb Smirnoff 						yyerror(
20503b3a8eb9SGleb Smirnoff 						    "flags only apply to tcp");
20513b3a8eb9SGleb Smirnoff 					if ($8.src_os)
20523b3a8eb9SGleb Smirnoff 						yyerror(
20533b3a8eb9SGleb Smirnoff 						    "OS fingerprinting only "
20543b3a8eb9SGleb Smirnoff 						    "apply to tcp");
20553b3a8eb9SGleb Smirnoff 					YYERROR;
20563b3a8eb9SGleb Smirnoff 				}
20573b3a8eb9SGleb Smirnoff #if 0
20583b3a8eb9SGleb Smirnoff 				if (($9.flags.b1 & parse_flags("S")) == 0 &&
20593b3a8eb9SGleb Smirnoff 				    $8.src_os) {
20603b3a8eb9SGleb Smirnoff 					yyerror("OS fingerprinting requires "
20613b3a8eb9SGleb Smirnoff 					    "the SYN TCP flag (flags S/SA)");
20623b3a8eb9SGleb Smirnoff 					YYERROR;
20633b3a8eb9SGleb Smirnoff 				}
20643b3a8eb9SGleb Smirnoff #endif
20653b3a8eb9SGleb Smirnoff 			}
20663b3a8eb9SGleb Smirnoff 
20673b3a8eb9SGleb Smirnoff 			r.tos = $9.tos;
20683b3a8eb9SGleb Smirnoff 			r.keep_state = $9.keep.action;
20693b3a8eb9SGleb Smirnoff 			o = $9.keep.options;
20703b3a8eb9SGleb Smirnoff 
20713b3a8eb9SGleb Smirnoff 			/* 'keep state' by default on pass rules. */
20723b3a8eb9SGleb Smirnoff 			if (!r.keep_state && !r.action &&
20733b3a8eb9SGleb Smirnoff 			    !($9.marker & FOM_KEEP)) {
20743b3a8eb9SGleb Smirnoff 				r.keep_state = PF_STATE_NORMAL;
20753b3a8eb9SGleb Smirnoff 				o = keep_state_defaults;
20763b3a8eb9SGleb Smirnoff 				defaults = 1;
20773b3a8eb9SGleb Smirnoff 			}
20783b3a8eb9SGleb Smirnoff 
20793b3a8eb9SGleb Smirnoff 			while (o) {
20803b3a8eb9SGleb Smirnoff 				struct node_state_opt	*p = o;
20813b3a8eb9SGleb Smirnoff 
20823b3a8eb9SGleb Smirnoff 				switch (o->type) {
20833b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX:
20843b3a8eb9SGleb Smirnoff 					if (r.max_states) {
20853b3a8eb9SGleb Smirnoff 						yyerror("state option 'max' "
20863b3a8eb9SGleb Smirnoff 						    "multiple definitions");
20873b3a8eb9SGleb Smirnoff 						YYERROR;
20883b3a8eb9SGleb Smirnoff 					}
20893b3a8eb9SGleb Smirnoff 					r.max_states = o->data.max_states;
20903b3a8eb9SGleb Smirnoff 					break;
20913b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_NOSYNC:
20923b3a8eb9SGleb Smirnoff 					if (r.rule_flag & PFRULE_NOSYNC) {
20933b3a8eb9SGleb Smirnoff 						yyerror("state option 'sync' "
20943b3a8eb9SGleb Smirnoff 						    "multiple definitions");
20953b3a8eb9SGleb Smirnoff 						YYERROR;
20963b3a8eb9SGleb Smirnoff 					}
20973b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_NOSYNC;
20983b3a8eb9SGleb Smirnoff 					break;
20993b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_SRCTRACK:
21003b3a8eb9SGleb Smirnoff 					if (srctrack) {
21013b3a8eb9SGleb Smirnoff 						yyerror("state option "
21023b3a8eb9SGleb Smirnoff 						    "'source-track' "
21033b3a8eb9SGleb Smirnoff 						    "multiple definitions");
21043b3a8eb9SGleb Smirnoff 						YYERROR;
21053b3a8eb9SGleb Smirnoff 					}
21063b3a8eb9SGleb Smirnoff 					srctrack =  o->data.src_track;
21073b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK;
21083b3a8eb9SGleb Smirnoff 					break;
21093b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_STATES:
21103b3a8eb9SGleb Smirnoff 					if (r.max_src_states) {
21113b3a8eb9SGleb Smirnoff 						yyerror("state option "
21123b3a8eb9SGleb Smirnoff 						    "'max-src-states' "
21133b3a8eb9SGleb Smirnoff 						    "multiple definitions");
21143b3a8eb9SGleb Smirnoff 						YYERROR;
21153b3a8eb9SGleb Smirnoff 					}
21163b3a8eb9SGleb Smirnoff 					if (o->data.max_src_states == 0) {
21173b3a8eb9SGleb Smirnoff 						yyerror("'max-src-states' must "
21183b3a8eb9SGleb Smirnoff 						    "be > 0");
21193b3a8eb9SGleb Smirnoff 						YYERROR;
21203b3a8eb9SGleb Smirnoff 					}
21213b3a8eb9SGleb Smirnoff 					r.max_src_states =
21223b3a8eb9SGleb Smirnoff 					    o->data.max_src_states;
21233b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK;
21243b3a8eb9SGleb Smirnoff 					break;
21253b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_OVERLOAD:
21263b3a8eb9SGleb Smirnoff 					if (r.overload_tblname[0]) {
21273b3a8eb9SGleb Smirnoff 						yyerror("multiple 'overload' "
21283b3a8eb9SGleb Smirnoff 						    "table definitions");
21293b3a8eb9SGleb Smirnoff 						YYERROR;
21303b3a8eb9SGleb Smirnoff 					}
21313b3a8eb9SGleb Smirnoff 					if (strlcpy(r.overload_tblname,
21323b3a8eb9SGleb Smirnoff 					    o->data.overload.tblname,
21333b3a8eb9SGleb Smirnoff 					    PF_TABLE_NAME_SIZE) >=
21343b3a8eb9SGleb Smirnoff 					    PF_TABLE_NAME_SIZE) {
21353b3a8eb9SGleb Smirnoff 						yyerror("state option: "
21363b3a8eb9SGleb Smirnoff 						    "strlcpy");
21373b3a8eb9SGleb Smirnoff 						YYERROR;
21383b3a8eb9SGleb Smirnoff 					}
21393b3a8eb9SGleb Smirnoff 					r.flush = o->data.overload.flush;
21403b3a8eb9SGleb Smirnoff 					break;
21413b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_CONN:
21423b3a8eb9SGleb Smirnoff 					if (r.max_src_conn) {
21433b3a8eb9SGleb Smirnoff 						yyerror("state option "
21443b3a8eb9SGleb Smirnoff 						    "'max-src-conn' "
21453b3a8eb9SGleb Smirnoff 						    "multiple definitions");
21463b3a8eb9SGleb Smirnoff 						YYERROR;
21473b3a8eb9SGleb Smirnoff 					}
21483b3a8eb9SGleb Smirnoff 					if (o->data.max_src_conn == 0) {
21493b3a8eb9SGleb Smirnoff 						yyerror("'max-src-conn' "
21503b3a8eb9SGleb Smirnoff 						    "must be > 0");
21513b3a8eb9SGleb Smirnoff 						YYERROR;
21523b3a8eb9SGleb Smirnoff 					}
21533b3a8eb9SGleb Smirnoff 					r.max_src_conn =
21543b3a8eb9SGleb Smirnoff 					    o->data.max_src_conn;
21553b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK |
21563b3a8eb9SGleb Smirnoff 					    PFRULE_RULESRCTRACK;
21573b3a8eb9SGleb Smirnoff 					break;
21583b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_CONN_RATE:
21593b3a8eb9SGleb Smirnoff 					if (r.max_src_conn_rate.limit) {
21603b3a8eb9SGleb Smirnoff 						yyerror("state option "
21613b3a8eb9SGleb Smirnoff 						    "'max-src-conn-rate' "
21623b3a8eb9SGleb Smirnoff 						    "multiple definitions");
21633b3a8eb9SGleb Smirnoff 						YYERROR;
21643b3a8eb9SGleb Smirnoff 					}
21653b3a8eb9SGleb Smirnoff 					if (!o->data.max_src_conn_rate.limit ||
21663b3a8eb9SGleb Smirnoff 					    !o->data.max_src_conn_rate.seconds) {
21673b3a8eb9SGleb Smirnoff 						yyerror("'max-src-conn-rate' "
21683b3a8eb9SGleb Smirnoff 						    "values must be > 0");
21693b3a8eb9SGleb Smirnoff 						YYERROR;
21703b3a8eb9SGleb Smirnoff 					}
21713b3a8eb9SGleb Smirnoff 					if (o->data.max_src_conn_rate.limit >
21723b3a8eb9SGleb Smirnoff 					    PF_THRESHOLD_MAX) {
21733b3a8eb9SGleb Smirnoff 						yyerror("'max-src-conn-rate' "
21743b3a8eb9SGleb Smirnoff 						    "maximum rate must be < %u",
21753b3a8eb9SGleb Smirnoff 						    PF_THRESHOLD_MAX);
21763b3a8eb9SGleb Smirnoff 						YYERROR;
21773b3a8eb9SGleb Smirnoff 					}
21783b3a8eb9SGleb Smirnoff 					r.max_src_conn_rate.limit =
21793b3a8eb9SGleb Smirnoff 					    o->data.max_src_conn_rate.limit;
21803b3a8eb9SGleb Smirnoff 					r.max_src_conn_rate.seconds =
21813b3a8eb9SGleb Smirnoff 					    o->data.max_src_conn_rate.seconds;
21823b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK |
21833b3a8eb9SGleb Smirnoff 					    PFRULE_RULESRCTRACK;
21843b3a8eb9SGleb Smirnoff 					break;
21853b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_NODES:
21863b3a8eb9SGleb Smirnoff 					if (r.max_src_nodes) {
21873b3a8eb9SGleb Smirnoff 						yyerror("state option "
21883b3a8eb9SGleb Smirnoff 						    "'max-src-nodes' "
21893b3a8eb9SGleb Smirnoff 						    "multiple definitions");
21903b3a8eb9SGleb Smirnoff 						YYERROR;
21913b3a8eb9SGleb Smirnoff 					}
21923b3a8eb9SGleb Smirnoff 					if (o->data.max_src_nodes == 0) {
21933b3a8eb9SGleb Smirnoff 						yyerror("'max-src-nodes' must "
21943b3a8eb9SGleb Smirnoff 						    "be > 0");
21953b3a8eb9SGleb Smirnoff 						YYERROR;
21963b3a8eb9SGleb Smirnoff 					}
21973b3a8eb9SGleb Smirnoff 					r.max_src_nodes =
21983b3a8eb9SGleb Smirnoff 					    o->data.max_src_nodes;
21993b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK |
22003b3a8eb9SGleb Smirnoff 					    PFRULE_RULESRCTRACK;
22013b3a8eb9SGleb Smirnoff 					break;
22023b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_STATELOCK:
22033b3a8eb9SGleb Smirnoff 					if (statelock) {
22043b3a8eb9SGleb Smirnoff 						yyerror("state locking option: "
22053b3a8eb9SGleb Smirnoff 						    "multiple definitions");
22063b3a8eb9SGleb Smirnoff 						YYERROR;
22073b3a8eb9SGleb Smirnoff 					}
22083b3a8eb9SGleb Smirnoff 					statelock = 1;
22093b3a8eb9SGleb Smirnoff 					r.rule_flag |= o->data.statelock;
22103b3a8eb9SGleb Smirnoff 					break;
22113b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_SLOPPY:
22123b3a8eb9SGleb Smirnoff 					if (r.rule_flag & PFRULE_STATESLOPPY) {
22133b3a8eb9SGleb Smirnoff 						yyerror("state sloppy option: "
22143b3a8eb9SGleb Smirnoff 						    "multiple definitions");
22153b3a8eb9SGleb Smirnoff 						YYERROR;
22163b3a8eb9SGleb Smirnoff 					}
22173b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_STATESLOPPY;
22183b3a8eb9SGleb Smirnoff 					break;
22193b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_TIMEOUT:
22203b3a8eb9SGleb Smirnoff 					if (o->data.timeout.number ==
22213b3a8eb9SGleb Smirnoff 					    PFTM_ADAPTIVE_START ||
22223b3a8eb9SGleb Smirnoff 					    o->data.timeout.number ==
22233b3a8eb9SGleb Smirnoff 					    PFTM_ADAPTIVE_END)
22243b3a8eb9SGleb Smirnoff 						adaptive = 1;
22253b3a8eb9SGleb Smirnoff 					if (r.timeout[o->data.timeout.number]) {
22263b3a8eb9SGleb Smirnoff 						yyerror("state timeout %s "
22273b3a8eb9SGleb Smirnoff 						    "multiple definitions",
22283b3a8eb9SGleb Smirnoff 						    pf_timeouts[o->data.
22293b3a8eb9SGleb Smirnoff 						    timeout.number].name);
22303b3a8eb9SGleb Smirnoff 						YYERROR;
22313b3a8eb9SGleb Smirnoff 					}
22323b3a8eb9SGleb Smirnoff 					r.timeout[o->data.timeout.number] =
22333b3a8eb9SGleb Smirnoff 					    o->data.timeout.seconds;
22343b3a8eb9SGleb Smirnoff 				}
22353b3a8eb9SGleb Smirnoff 				o = o->next;
22363b3a8eb9SGleb Smirnoff 				if (!defaults)
22373b3a8eb9SGleb Smirnoff 					free(p);
22383b3a8eb9SGleb Smirnoff 			}
22393b3a8eb9SGleb Smirnoff 
22403b3a8eb9SGleb Smirnoff 			/* 'flags S/SA' by default on stateful rules */
22413b3a8eb9SGleb Smirnoff 			if (!r.action && !r.flags && !r.flagset &&
22423b3a8eb9SGleb Smirnoff 			    !$9.fragment && !($9.marker & FOM_FLAGS) &&
22433b3a8eb9SGleb Smirnoff 			    r.keep_state) {
22443b3a8eb9SGleb Smirnoff 				r.flags = parse_flags("S");
22453b3a8eb9SGleb Smirnoff 				r.flagset =  parse_flags("SA");
22463b3a8eb9SGleb Smirnoff 			}
22473b3a8eb9SGleb Smirnoff 			if (!adaptive && r.max_states) {
22483b3a8eb9SGleb Smirnoff 				r.timeout[PFTM_ADAPTIVE_START] =
22493b3a8eb9SGleb Smirnoff 				    (r.max_states / 10) * 6;
22503b3a8eb9SGleb Smirnoff 				r.timeout[PFTM_ADAPTIVE_END] =
22513b3a8eb9SGleb Smirnoff 				    (r.max_states / 10) * 12;
22523b3a8eb9SGleb Smirnoff 			}
22533b3a8eb9SGleb Smirnoff 			if (r.rule_flag & PFRULE_SRCTRACK) {
22543b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_GLOBAL &&
22553b3a8eb9SGleb Smirnoff 				    r.max_src_nodes) {
22563b3a8eb9SGleb Smirnoff 					yyerror("'max-src-nodes' is "
22573b3a8eb9SGleb Smirnoff 					    "incompatible with "
22583b3a8eb9SGleb Smirnoff 					    "'source-track global'");
22593b3a8eb9SGleb Smirnoff 					YYERROR;
22603b3a8eb9SGleb Smirnoff 				}
22613b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_GLOBAL &&
22623b3a8eb9SGleb Smirnoff 				    r.max_src_conn) {
22633b3a8eb9SGleb Smirnoff 					yyerror("'max-src-conn' is "
22643b3a8eb9SGleb Smirnoff 					    "incompatible with "
22653b3a8eb9SGleb Smirnoff 					    "'source-track global'");
22663b3a8eb9SGleb Smirnoff 					YYERROR;
22673b3a8eb9SGleb Smirnoff 				}
22683b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_GLOBAL &&
22693b3a8eb9SGleb Smirnoff 				    r.max_src_conn_rate.seconds) {
22703b3a8eb9SGleb Smirnoff 					yyerror("'max-src-conn-rate' is "
22713b3a8eb9SGleb Smirnoff 					    "incompatible with "
22723b3a8eb9SGleb Smirnoff 					    "'source-track global'");
22733b3a8eb9SGleb Smirnoff 					YYERROR;
22743b3a8eb9SGleb Smirnoff 				}
22753b3a8eb9SGleb Smirnoff 				if (r.timeout[PFTM_SRC_NODE] <
22763b3a8eb9SGleb Smirnoff 				    r.max_src_conn_rate.seconds)
22773b3a8eb9SGleb Smirnoff 					r.timeout[PFTM_SRC_NODE] =
22783b3a8eb9SGleb Smirnoff 					    r.max_src_conn_rate.seconds;
22793b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_SRCTRACK;
22803b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_RULE)
22813b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_RULESRCTRACK;
22823b3a8eb9SGleb Smirnoff 			}
22833b3a8eb9SGleb Smirnoff 			if (r.keep_state && !statelock)
22843b3a8eb9SGleb Smirnoff 				r.rule_flag |= default_statelock;
22853b3a8eb9SGleb Smirnoff 
22863b3a8eb9SGleb Smirnoff 			if ($9.fragment)
22873b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_FRAGMENT;
22883b3a8eb9SGleb Smirnoff 			r.allow_opts = $9.allowopts;
22893b3a8eb9SGleb Smirnoff 
22903b3a8eb9SGleb Smirnoff 			decide_address_family($8.src.host, &r.af);
22913b3a8eb9SGleb Smirnoff 			decide_address_family($8.dst.host, &r.af);
22923b3a8eb9SGleb Smirnoff 
22933b3a8eb9SGleb Smirnoff 			if ($5.rt) {
22943b3a8eb9SGleb Smirnoff 				if (!r.direction) {
22953b3a8eb9SGleb Smirnoff 					yyerror("direction must be explicit "
22963b3a8eb9SGleb Smirnoff 					    "with rules that specify routing");
22973b3a8eb9SGleb Smirnoff 					YYERROR;
22983b3a8eb9SGleb Smirnoff 				}
22993b3a8eb9SGleb Smirnoff 				r.rt = $5.rt;
23003b3a8eb9SGleb Smirnoff 				r.rpool.opts = $5.pool_opts;
23013b3a8eb9SGleb Smirnoff 				if ($5.key != NULL)
23023b3a8eb9SGleb Smirnoff 					memcpy(&r.rpool.key, $5.key,
23033b3a8eb9SGleb Smirnoff 					    sizeof(struct pf_poolhashkey));
23043b3a8eb9SGleb Smirnoff 			}
23053b3a8eb9SGleb Smirnoff 			if (r.rt && r.rt != PF_FASTROUTE) {
23063b3a8eb9SGleb Smirnoff 				decide_address_family($5.host, &r.af);
23073b3a8eb9SGleb Smirnoff 				remove_invalid_hosts(&$5.host, &r.af);
23083b3a8eb9SGleb Smirnoff 				if ($5.host == NULL) {
23093b3a8eb9SGleb Smirnoff 					yyerror("no routing address with "
23103b3a8eb9SGleb Smirnoff 					    "matching address family found.");
23113b3a8eb9SGleb Smirnoff 					YYERROR;
23123b3a8eb9SGleb Smirnoff 				}
23133b3a8eb9SGleb Smirnoff 				if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
23143b3a8eb9SGleb Smirnoff 				    PF_POOL_NONE && ($5.host->next != NULL ||
23153b3a8eb9SGleb Smirnoff 				    $5.host->addr.type == PF_ADDR_TABLE ||
23163b3a8eb9SGleb Smirnoff 				    DYNIF_MULTIADDR($5.host->addr)))
23173b3a8eb9SGleb Smirnoff 					r.rpool.opts |= PF_POOL_ROUNDROBIN;
23183b3a8eb9SGleb Smirnoff 				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
23193b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
23203b3a8eb9SGleb Smirnoff 				    disallow_table($5.host, "tables are only "
23213b3a8eb9SGleb Smirnoff 				    "supported in round-robin routing pools"))
23223b3a8eb9SGleb Smirnoff 					YYERROR;
23233b3a8eb9SGleb Smirnoff 				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
23243b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
23253b3a8eb9SGleb Smirnoff 				    disallow_alias($5.host, "interface (%s) "
23263b3a8eb9SGleb Smirnoff 				    "is only supported in round-robin "
23273b3a8eb9SGleb Smirnoff 				    "routing pools"))
23283b3a8eb9SGleb Smirnoff 					YYERROR;
23293b3a8eb9SGleb Smirnoff 				if ($5.host->next != NULL) {
23303b3a8eb9SGleb Smirnoff 					if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
23313b3a8eb9SGleb Smirnoff 					    PF_POOL_ROUNDROBIN) {
23323b3a8eb9SGleb Smirnoff 						yyerror("r.rpool.opts must "
23333b3a8eb9SGleb Smirnoff 						    "be PF_POOL_ROUNDROBIN");
23343b3a8eb9SGleb Smirnoff 						YYERROR;
23353b3a8eb9SGleb Smirnoff 					}
23363b3a8eb9SGleb Smirnoff 				}
23373b3a8eb9SGleb Smirnoff 			}
23383b3a8eb9SGleb Smirnoff 			if ($9.queues.qname != NULL) {
23393b3a8eb9SGleb Smirnoff 				if (strlcpy(r.qname, $9.queues.qname,
23403b3a8eb9SGleb Smirnoff 				    sizeof(r.qname)) >= sizeof(r.qname)) {
23413b3a8eb9SGleb Smirnoff 					yyerror("rule qname too long (max "
23423b3a8eb9SGleb Smirnoff 					    "%d chars)", sizeof(r.qname)-1);
23433b3a8eb9SGleb Smirnoff 					YYERROR;
23443b3a8eb9SGleb Smirnoff 				}
23453b3a8eb9SGleb Smirnoff 				free($9.queues.qname);
23463b3a8eb9SGleb Smirnoff 			}
23473b3a8eb9SGleb Smirnoff 			if ($9.queues.pqname != NULL) {
23483b3a8eb9SGleb Smirnoff 				if (strlcpy(r.pqname, $9.queues.pqname,
23493b3a8eb9SGleb Smirnoff 				    sizeof(r.pqname)) >= sizeof(r.pqname)) {
23503b3a8eb9SGleb Smirnoff 					yyerror("rule pqname too long (max "
23513b3a8eb9SGleb Smirnoff 					    "%d chars)", sizeof(r.pqname)-1);
23523b3a8eb9SGleb Smirnoff 					YYERROR;
23533b3a8eb9SGleb Smirnoff 				}
23543b3a8eb9SGleb Smirnoff 				free($9.queues.pqname);
23553b3a8eb9SGleb Smirnoff 			}
23563b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
23573b3a8eb9SGleb Smirnoff 			r.divert.port = $9.divert.port;
23583b3a8eb9SGleb Smirnoff #else
23593b3a8eb9SGleb Smirnoff 			if ((r.divert.port = $9.divert.port)) {
23603b3a8eb9SGleb Smirnoff 				if (r.direction == PF_OUT) {
23613b3a8eb9SGleb Smirnoff 					if ($9.divert.addr) {
23623b3a8eb9SGleb Smirnoff 						yyerror("address specified "
23633b3a8eb9SGleb Smirnoff 						    "for outgoing divert");
23643b3a8eb9SGleb Smirnoff 						YYERROR;
23653b3a8eb9SGleb Smirnoff 					}
23663b3a8eb9SGleb Smirnoff 					bzero(&r.divert.addr,
23673b3a8eb9SGleb Smirnoff 					    sizeof(r.divert.addr));
23683b3a8eb9SGleb Smirnoff 				} else {
23693b3a8eb9SGleb Smirnoff 					if (!$9.divert.addr) {
23703b3a8eb9SGleb Smirnoff 						yyerror("no address specified "
23713b3a8eb9SGleb Smirnoff 						    "for incoming divert");
23723b3a8eb9SGleb Smirnoff 						YYERROR;
23733b3a8eb9SGleb Smirnoff 					}
23743b3a8eb9SGleb Smirnoff 					if ($9.divert.addr->af != r.af) {
23753b3a8eb9SGleb Smirnoff 						yyerror("address family "
23763b3a8eb9SGleb Smirnoff 						    "mismatch for divert");
23773b3a8eb9SGleb Smirnoff 						YYERROR;
23783b3a8eb9SGleb Smirnoff 					}
23793b3a8eb9SGleb Smirnoff 					r.divert.addr =
23803b3a8eb9SGleb Smirnoff 					    $9.divert.addr->addr.v.a.addr;
23813b3a8eb9SGleb Smirnoff 				}
23823b3a8eb9SGleb Smirnoff 			}
23833b3a8eb9SGleb Smirnoff #endif
23843b3a8eb9SGleb Smirnoff 
23853b3a8eb9SGleb Smirnoff 			expand_rule(&r, $4, $5.host, $7, $8.src_os,
23863b3a8eb9SGleb Smirnoff 			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
23873b3a8eb9SGleb Smirnoff 			    $9.uid, $9.gid, $9.icmpspec, "");
23883b3a8eb9SGleb Smirnoff 		}
23893b3a8eb9SGleb Smirnoff 		;
23903b3a8eb9SGleb Smirnoff 
23913b3a8eb9SGleb Smirnoff filter_opts	:	{
23923b3a8eb9SGleb Smirnoff 				bzero(&filter_opts, sizeof filter_opts);
23933b3a8eb9SGleb Smirnoff 				filter_opts.rtableid = -1;
23943b3a8eb9SGleb Smirnoff 			}
23953b3a8eb9SGleb Smirnoff 		    filter_opts_l
23963b3a8eb9SGleb Smirnoff 			{ $$ = filter_opts; }
23973b3a8eb9SGleb Smirnoff 		| /* empty */	{
23983b3a8eb9SGleb Smirnoff 			bzero(&filter_opts, sizeof filter_opts);
23993b3a8eb9SGleb Smirnoff 			filter_opts.rtableid = -1;
24003b3a8eb9SGleb Smirnoff 			$$ = filter_opts;
24013b3a8eb9SGleb Smirnoff 		}
24023b3a8eb9SGleb Smirnoff 		;
24033b3a8eb9SGleb Smirnoff 
24043b3a8eb9SGleb Smirnoff filter_opts_l	: filter_opts_l filter_opt
24053b3a8eb9SGleb Smirnoff 		| filter_opt
24063b3a8eb9SGleb Smirnoff 		;
24073b3a8eb9SGleb Smirnoff 
24083b3a8eb9SGleb Smirnoff filter_opt	: USER uids {
24093b3a8eb9SGleb Smirnoff 			if (filter_opts.uid)
24103b3a8eb9SGleb Smirnoff 				$2->tail->next = filter_opts.uid;
24113b3a8eb9SGleb Smirnoff 			filter_opts.uid = $2;
24123b3a8eb9SGleb Smirnoff 		}
24133b3a8eb9SGleb Smirnoff 		| GROUP gids {
24143b3a8eb9SGleb Smirnoff 			if (filter_opts.gid)
24153b3a8eb9SGleb Smirnoff 				$2->tail->next = filter_opts.gid;
24163b3a8eb9SGleb Smirnoff 			filter_opts.gid = $2;
24173b3a8eb9SGleb Smirnoff 		}
24183b3a8eb9SGleb Smirnoff 		| flags {
24193b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_FLAGS) {
24203b3a8eb9SGleb Smirnoff 				yyerror("flags cannot be redefined");
24213b3a8eb9SGleb Smirnoff 				YYERROR;
24223b3a8eb9SGleb Smirnoff 			}
24233b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_FLAGS;
24243b3a8eb9SGleb Smirnoff 			filter_opts.flags.b1 |= $1.b1;
24253b3a8eb9SGleb Smirnoff 			filter_opts.flags.b2 |= $1.b2;
24263b3a8eb9SGleb Smirnoff 			filter_opts.flags.w |= $1.w;
24273b3a8eb9SGleb Smirnoff 			filter_opts.flags.w2 |= $1.w2;
24283b3a8eb9SGleb Smirnoff 		}
24293b3a8eb9SGleb Smirnoff 		| icmpspec {
24303b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_ICMP) {
24313b3a8eb9SGleb Smirnoff 				yyerror("icmp-type cannot be redefined");
24323b3a8eb9SGleb Smirnoff 				YYERROR;
24333b3a8eb9SGleb Smirnoff 			}
24343b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_ICMP;
24353b3a8eb9SGleb Smirnoff 			filter_opts.icmpspec = $1;
24363b3a8eb9SGleb Smirnoff 		}
24373b3a8eb9SGleb Smirnoff 		| TOS tos {
24383b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_TOS) {
24393b3a8eb9SGleb Smirnoff 				yyerror("tos cannot be redefined");
24403b3a8eb9SGleb Smirnoff 				YYERROR;
24413b3a8eb9SGleb Smirnoff 			}
24423b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_TOS;
24433b3a8eb9SGleb Smirnoff 			filter_opts.tos = $2;
24443b3a8eb9SGleb Smirnoff 		}
24453b3a8eb9SGleb Smirnoff 		| keep {
24463b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_KEEP) {
24473b3a8eb9SGleb Smirnoff 				yyerror("modulate or keep cannot be redefined");
24483b3a8eb9SGleb Smirnoff 				YYERROR;
24493b3a8eb9SGleb Smirnoff 			}
24503b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_KEEP;
24513b3a8eb9SGleb Smirnoff 			filter_opts.keep.action = $1.action;
24523b3a8eb9SGleb Smirnoff 			filter_opts.keep.options = $1.options;
24533b3a8eb9SGleb Smirnoff 		}
24543b3a8eb9SGleb Smirnoff 		| FRAGMENT {
24553b3a8eb9SGleb Smirnoff 			filter_opts.fragment = 1;
24563b3a8eb9SGleb Smirnoff 		}
24573b3a8eb9SGleb Smirnoff 		| ALLOWOPTS {
24583b3a8eb9SGleb Smirnoff 			filter_opts.allowopts = 1;
24593b3a8eb9SGleb Smirnoff 		}
24603b3a8eb9SGleb Smirnoff 		| label	{
24613b3a8eb9SGleb Smirnoff 			if (filter_opts.label) {
24623b3a8eb9SGleb Smirnoff 				yyerror("label cannot be redefined");
24633b3a8eb9SGleb Smirnoff 				YYERROR;
24643b3a8eb9SGleb Smirnoff 			}
24653b3a8eb9SGleb Smirnoff 			filter_opts.label = $1;
24663b3a8eb9SGleb Smirnoff 		}
24673b3a8eb9SGleb Smirnoff 		| qname	{
24683b3a8eb9SGleb Smirnoff 			if (filter_opts.queues.qname) {
24693b3a8eb9SGleb Smirnoff 				yyerror("queue cannot be redefined");
24703b3a8eb9SGleb Smirnoff 				YYERROR;
24713b3a8eb9SGleb Smirnoff 			}
24723b3a8eb9SGleb Smirnoff 			filter_opts.queues = $1;
24733b3a8eb9SGleb Smirnoff 		}
24743b3a8eb9SGleb Smirnoff 		| TAG string				{
24753b3a8eb9SGleb Smirnoff 			filter_opts.tag = $2;
24763b3a8eb9SGleb Smirnoff 		}
24773b3a8eb9SGleb Smirnoff 		| not TAGGED string			{
24783b3a8eb9SGleb Smirnoff 			filter_opts.match_tag = $3;
24793b3a8eb9SGleb Smirnoff 			filter_opts.match_tag_not = $1;
24803b3a8eb9SGleb Smirnoff 		}
24813b3a8eb9SGleb Smirnoff 		| PROBABILITY probability		{
24823b3a8eb9SGleb Smirnoff 			double	p;
24833b3a8eb9SGleb Smirnoff 
24843b3a8eb9SGleb Smirnoff 			p = floor($2 * UINT_MAX + 0.5);
24853b3a8eb9SGleb Smirnoff 			if (p < 0.0 || p > UINT_MAX) {
24863b3a8eb9SGleb Smirnoff 				yyerror("invalid probability: %lf", p);
24873b3a8eb9SGleb Smirnoff 				YYERROR;
24883b3a8eb9SGleb Smirnoff 			}
24893b3a8eb9SGleb Smirnoff 			filter_opts.prob = (u_int32_t)p;
24903b3a8eb9SGleb Smirnoff 			if (filter_opts.prob == 0)
24913b3a8eb9SGleb Smirnoff 				filter_opts.prob = 1;
24923b3a8eb9SGleb Smirnoff 		}
24933b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER				{
24943b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
24953b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
24963b3a8eb9SGleb Smirnoff 				YYERROR;
24973b3a8eb9SGleb Smirnoff 			}
24983b3a8eb9SGleb Smirnoff 			filter_opts.rtableid = $2;
24993b3a8eb9SGleb Smirnoff 		}
25003b3a8eb9SGleb Smirnoff 		| DIVERTTO portplain {
25013b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
25023b3a8eb9SGleb Smirnoff 			filter_opts.divert.port = $2.a;
25033b3a8eb9SGleb Smirnoff 			if (!filter_opts.divert.port) {
25043b3a8eb9SGleb Smirnoff 				yyerror("invalid divert port: %u", ntohs($2.a));
25053b3a8eb9SGleb Smirnoff 				YYERROR;
25063b3a8eb9SGleb Smirnoff 			}
25073b3a8eb9SGleb Smirnoff #endif
25083b3a8eb9SGleb Smirnoff 		}
25093b3a8eb9SGleb Smirnoff 		| DIVERTTO STRING PORT portplain {
25103b3a8eb9SGleb Smirnoff #ifndef __FreeBSD__
25113b3a8eb9SGleb Smirnoff 			if ((filter_opts.divert.addr = host($2)) == NULL) {
25123b3a8eb9SGleb Smirnoff 				yyerror("could not parse divert address: %s",
25133b3a8eb9SGleb Smirnoff 				    $2);
25143b3a8eb9SGleb Smirnoff 				free($2);
25153b3a8eb9SGleb Smirnoff 				YYERROR;
25163b3a8eb9SGleb Smirnoff 			}
25173b3a8eb9SGleb Smirnoff #else
25183b3a8eb9SGleb Smirnoff 			if ($2)
25193b3a8eb9SGleb Smirnoff #endif
25203b3a8eb9SGleb Smirnoff 			free($2);
25213b3a8eb9SGleb Smirnoff 			filter_opts.divert.port = $4.a;
25223b3a8eb9SGleb Smirnoff 			if (!filter_opts.divert.port) {
25233b3a8eb9SGleb Smirnoff 				yyerror("invalid divert port: %u", ntohs($4.a));
25243b3a8eb9SGleb Smirnoff 				YYERROR;
25253b3a8eb9SGleb Smirnoff 			}
25263b3a8eb9SGleb Smirnoff 		}
25273b3a8eb9SGleb Smirnoff 		| DIVERTREPLY {
25283b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
25293b3a8eb9SGleb Smirnoff 			yyerror("divert-reply has no meaning in FreeBSD pf(4)");
25303b3a8eb9SGleb Smirnoff 			YYERROR;
25313b3a8eb9SGleb Smirnoff #else
25323b3a8eb9SGleb Smirnoff 			filter_opts.divert.port = 1;	/* some random value */
25333b3a8eb9SGleb Smirnoff #endif
25343b3a8eb9SGleb Smirnoff 		}
25353b3a8eb9SGleb Smirnoff 		;
25363b3a8eb9SGleb Smirnoff 
25373b3a8eb9SGleb Smirnoff probability	: STRING				{
25383b3a8eb9SGleb Smirnoff 			char	*e;
25393b3a8eb9SGleb Smirnoff 			double	 p = strtod($1, &e);
25403b3a8eb9SGleb Smirnoff 
25413b3a8eb9SGleb Smirnoff 			if (*e == '%') {
25423b3a8eb9SGleb Smirnoff 				p *= 0.01;
25433b3a8eb9SGleb Smirnoff 				e++;
25443b3a8eb9SGleb Smirnoff 			}
25453b3a8eb9SGleb Smirnoff 			if (*e) {
25463b3a8eb9SGleb Smirnoff 				yyerror("invalid probability: %s", $1);
25473b3a8eb9SGleb Smirnoff 				free($1);
25483b3a8eb9SGleb Smirnoff 				YYERROR;
25493b3a8eb9SGleb Smirnoff 			}
25503b3a8eb9SGleb Smirnoff 			free($1);
25513b3a8eb9SGleb Smirnoff 			$$ = p;
25523b3a8eb9SGleb Smirnoff 		}
25533b3a8eb9SGleb Smirnoff 		| NUMBER				{
25543b3a8eb9SGleb Smirnoff 			$$ = (double)$1;
25553b3a8eb9SGleb Smirnoff 		}
25563b3a8eb9SGleb Smirnoff 		;
25573b3a8eb9SGleb Smirnoff 
25583b3a8eb9SGleb Smirnoff 
25593b3a8eb9SGleb Smirnoff action		: PASS			{ $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
25603b3a8eb9SGleb Smirnoff 		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
25613b3a8eb9SGleb Smirnoff 		;
25623b3a8eb9SGleb Smirnoff 
25633b3a8eb9SGleb Smirnoff blockspec	: /* empty */		{
25643b3a8eb9SGleb Smirnoff 			$$.b2 = blockpolicy;
25653b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
25663b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
25673b3a8eb9SGleb Smirnoff 		}
25683b3a8eb9SGleb Smirnoff 		| DROP			{
25693b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_DROP;
25703b3a8eb9SGleb Smirnoff 			$$.w = 0;
25713b3a8eb9SGleb Smirnoff 			$$.w2 = 0;
25723b3a8eb9SGleb Smirnoff 		}
25733b3a8eb9SGleb Smirnoff 		| RETURNRST		{
25743b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNRST;
25753b3a8eb9SGleb Smirnoff 			$$.w = 0;
25763b3a8eb9SGleb Smirnoff 			$$.w2 = 0;
25773b3a8eb9SGleb Smirnoff 		}
25783b3a8eb9SGleb Smirnoff 		| RETURNRST '(' TTL NUMBER ')'	{
25793b3a8eb9SGleb Smirnoff 			if ($4 < 0 || $4 > 255) {
25803b3a8eb9SGleb Smirnoff 				yyerror("illegal ttl value %d", $4);
25813b3a8eb9SGleb Smirnoff 				YYERROR;
25823b3a8eb9SGleb Smirnoff 			}
25833b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNRST;
25843b3a8eb9SGleb Smirnoff 			$$.w = $4;
25853b3a8eb9SGleb Smirnoff 			$$.w2 = 0;
25863b3a8eb9SGleb Smirnoff 		}
25873b3a8eb9SGleb Smirnoff 		| RETURNICMP		{
25883b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
25893b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
25903b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
25913b3a8eb9SGleb Smirnoff 		}
25923b3a8eb9SGleb Smirnoff 		| RETURNICMP6		{
25933b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
25943b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
25953b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
25963b3a8eb9SGleb Smirnoff 		}
25973b3a8eb9SGleb Smirnoff 		| RETURNICMP '(' reticmpspec ')'	{
25983b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
25993b3a8eb9SGleb Smirnoff 			$$.w = $3;
26003b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmpdefault;
26013b3a8eb9SGleb Smirnoff 		}
26023b3a8eb9SGleb Smirnoff 		| RETURNICMP6 '(' reticmp6spec ')'	{
26033b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
26043b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
26053b3a8eb9SGleb Smirnoff 			$$.w2 = $3;
26063b3a8eb9SGleb Smirnoff 		}
26073b3a8eb9SGleb Smirnoff 		| RETURNICMP '(' reticmpspec comma reticmp6spec ')' {
26083b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
26093b3a8eb9SGleb Smirnoff 			$$.w = $3;
26103b3a8eb9SGleb Smirnoff 			$$.w2 = $5;
26113b3a8eb9SGleb Smirnoff 		}
26123b3a8eb9SGleb Smirnoff 		| RETURN {
26133b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURN;
26143b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
26153b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
26163b3a8eb9SGleb Smirnoff 		}
26173b3a8eb9SGleb Smirnoff 		;
26183b3a8eb9SGleb Smirnoff 
26193b3a8eb9SGleb Smirnoff reticmpspec	: STRING			{
26203b3a8eb9SGleb Smirnoff 			if (!($$ = parseicmpspec($1, AF_INET))) {
26213b3a8eb9SGleb Smirnoff 				free($1);
26223b3a8eb9SGleb Smirnoff 				YYERROR;
26233b3a8eb9SGleb Smirnoff 			}
26243b3a8eb9SGleb Smirnoff 			free($1);
26253b3a8eb9SGleb Smirnoff 		}
26263b3a8eb9SGleb Smirnoff 		| NUMBER			{
26273b3a8eb9SGleb Smirnoff 			u_int8_t		icmptype;
26283b3a8eb9SGleb Smirnoff 
26293b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
26303b3a8eb9SGleb Smirnoff 				yyerror("invalid icmp code %lu", $1);
26313b3a8eb9SGleb Smirnoff 				YYERROR;
26323b3a8eb9SGleb Smirnoff 			}
26333b3a8eb9SGleb Smirnoff 			icmptype = returnicmpdefault >> 8;
26343b3a8eb9SGleb Smirnoff 			$$ = (icmptype << 8 | $1);
26353b3a8eb9SGleb Smirnoff 		}
26363b3a8eb9SGleb Smirnoff 		;
26373b3a8eb9SGleb Smirnoff 
26383b3a8eb9SGleb Smirnoff reticmp6spec	: STRING			{
26393b3a8eb9SGleb Smirnoff 			if (!($$ = parseicmpspec($1, AF_INET6))) {
26403b3a8eb9SGleb Smirnoff 				free($1);
26413b3a8eb9SGleb Smirnoff 				YYERROR;
26423b3a8eb9SGleb Smirnoff 			}
26433b3a8eb9SGleb Smirnoff 			free($1);
26443b3a8eb9SGleb Smirnoff 		}
26453b3a8eb9SGleb Smirnoff 		| NUMBER			{
26463b3a8eb9SGleb Smirnoff 			u_int8_t		icmptype;
26473b3a8eb9SGleb Smirnoff 
26483b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
26493b3a8eb9SGleb Smirnoff 				yyerror("invalid icmp code %lu", $1);
26503b3a8eb9SGleb Smirnoff 				YYERROR;
26513b3a8eb9SGleb Smirnoff 			}
26523b3a8eb9SGleb Smirnoff 			icmptype = returnicmp6default >> 8;
26533b3a8eb9SGleb Smirnoff 			$$ = (icmptype << 8 | $1);
26543b3a8eb9SGleb Smirnoff 		}
26553b3a8eb9SGleb Smirnoff 		;
26563b3a8eb9SGleb Smirnoff 
26573b3a8eb9SGleb Smirnoff dir		: /* empty */			{ $$ = PF_INOUT; }
26583b3a8eb9SGleb Smirnoff 		| IN				{ $$ = PF_IN; }
26593b3a8eb9SGleb Smirnoff 		| OUT				{ $$ = PF_OUT; }
26603b3a8eb9SGleb Smirnoff 		;
26613b3a8eb9SGleb Smirnoff 
26623b3a8eb9SGleb Smirnoff quick		: /* empty */			{ $$.quick = 0; }
26633b3a8eb9SGleb Smirnoff 		| QUICK				{ $$.quick = 1; }
26643b3a8eb9SGleb Smirnoff 		;
26653b3a8eb9SGleb Smirnoff 
26663b3a8eb9SGleb Smirnoff logquick	: /* empty */	{ $$.log = 0; $$.quick = 0; $$.logif = 0; }
26673b3a8eb9SGleb Smirnoff 		| log		{ $$ = $1; $$.quick = 0; }
26683b3a8eb9SGleb Smirnoff 		| QUICK		{ $$.quick = 1; $$.log = 0; $$.logif = 0; }
26693b3a8eb9SGleb Smirnoff 		| log QUICK	{ $$ = $1; $$.quick = 1; }
26703b3a8eb9SGleb Smirnoff 		| QUICK log	{ $$ = $2; $$.quick = 1; }
26713b3a8eb9SGleb Smirnoff 		;
26723b3a8eb9SGleb Smirnoff 
26733b3a8eb9SGleb Smirnoff log		: LOG			{ $$.log = PF_LOG; $$.logif = 0; }
26743b3a8eb9SGleb Smirnoff 		| LOG '(' logopts ')'	{
26753b3a8eb9SGleb Smirnoff 			$$.log = PF_LOG | $3.log;
26763b3a8eb9SGleb Smirnoff 			$$.logif = $3.logif;
26773b3a8eb9SGleb Smirnoff 		}
26783b3a8eb9SGleb Smirnoff 		;
26793b3a8eb9SGleb Smirnoff 
26803b3a8eb9SGleb Smirnoff logopts		: logopt			{ $$ = $1; }
26813b3a8eb9SGleb Smirnoff 		| logopts comma logopt		{
26823b3a8eb9SGleb Smirnoff 			$$.log = $1.log | $3.log;
26833b3a8eb9SGleb Smirnoff 			$$.logif = $3.logif;
26843b3a8eb9SGleb Smirnoff 			if ($$.logif == 0)
26853b3a8eb9SGleb Smirnoff 				$$.logif = $1.logif;
26863b3a8eb9SGleb Smirnoff 		}
26873b3a8eb9SGleb Smirnoff 		;
26883b3a8eb9SGleb Smirnoff 
26893b3a8eb9SGleb Smirnoff logopt		: ALL		{ $$.log = PF_LOG_ALL; $$.logif = 0; }
26903b3a8eb9SGleb Smirnoff 		| USER		{ $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
26913b3a8eb9SGleb Smirnoff 		| GROUP		{ $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
26923b3a8eb9SGleb Smirnoff 		| TO string	{
26933b3a8eb9SGleb Smirnoff 			const char	*errstr;
26943b3a8eb9SGleb Smirnoff 			u_int		 i;
26953b3a8eb9SGleb Smirnoff 
26963b3a8eb9SGleb Smirnoff 			$$.log = 0;
26973b3a8eb9SGleb Smirnoff 			if (strncmp($2, "pflog", 5)) {
26983b3a8eb9SGleb Smirnoff 				yyerror("%s: should be a pflog interface", $2);
26993b3a8eb9SGleb Smirnoff 				free($2);
27003b3a8eb9SGleb Smirnoff 				YYERROR;
27013b3a8eb9SGleb Smirnoff 			}
27023b3a8eb9SGleb Smirnoff 			i = strtonum($2 + 5, 0, 255, &errstr);
27033b3a8eb9SGleb Smirnoff 			if (errstr) {
27043b3a8eb9SGleb Smirnoff 				yyerror("%s: %s", $2, errstr);
27053b3a8eb9SGleb Smirnoff 				free($2);
27063b3a8eb9SGleb Smirnoff 				YYERROR;
27073b3a8eb9SGleb Smirnoff 			}
27083b3a8eb9SGleb Smirnoff 			free($2);
27093b3a8eb9SGleb Smirnoff 			$$.logif = i;
27103b3a8eb9SGleb Smirnoff 		}
27113b3a8eb9SGleb Smirnoff 		;
27123b3a8eb9SGleb Smirnoff 
27133b3a8eb9SGleb Smirnoff interface	: /* empty */			{ $$ = NULL; }
27143b3a8eb9SGleb Smirnoff 		| ON if_item_not		{ $$ = $2; }
27153b3a8eb9SGleb Smirnoff 		| ON '{' optnl if_list '}'	{ $$ = $4; }
27163b3a8eb9SGleb Smirnoff 		;
27173b3a8eb9SGleb Smirnoff 
27183b3a8eb9SGleb Smirnoff if_list		: if_item_not optnl		{ $$ = $1; }
27193b3a8eb9SGleb Smirnoff 		| if_list comma if_item_not optnl	{
27203b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
27213b3a8eb9SGleb Smirnoff 			$1->tail = $3;
27223b3a8eb9SGleb Smirnoff 			$$ = $1;
27233b3a8eb9SGleb Smirnoff 		}
27243b3a8eb9SGleb Smirnoff 		;
27253b3a8eb9SGleb Smirnoff 
27263b3a8eb9SGleb Smirnoff if_item_not	: not if_item			{ $$ = $2; $$->not = $1; }
27273b3a8eb9SGleb Smirnoff 		;
27283b3a8eb9SGleb Smirnoff 
27293b3a8eb9SGleb Smirnoff if_item		: STRING			{
27303b3a8eb9SGleb Smirnoff 			struct node_host	*n;
27313b3a8eb9SGleb Smirnoff 
27323b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_if));
27333b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
27343b3a8eb9SGleb Smirnoff 				err(1, "if_item: calloc");
27353b3a8eb9SGleb Smirnoff 			if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
27363b3a8eb9SGleb Smirnoff 			    sizeof($$->ifname)) {
27373b3a8eb9SGleb Smirnoff 				free($1);
27383b3a8eb9SGleb Smirnoff 				free($$);
27393b3a8eb9SGleb Smirnoff 				yyerror("interface name too long");
27403b3a8eb9SGleb Smirnoff 				YYERROR;
27413b3a8eb9SGleb Smirnoff 			}
27423b3a8eb9SGleb Smirnoff 
27433b3a8eb9SGleb Smirnoff 			if ((n = ifa_exists($1)) != NULL)
27443b3a8eb9SGleb Smirnoff 				$$->ifa_flags = n->ifa_flags;
27453b3a8eb9SGleb Smirnoff 
27463b3a8eb9SGleb Smirnoff 			free($1);
27473b3a8eb9SGleb Smirnoff 			$$->not = 0;
27483b3a8eb9SGleb Smirnoff 			$$->next = NULL;
27493b3a8eb9SGleb Smirnoff 			$$->tail = $$;
27503b3a8eb9SGleb Smirnoff 		}
27513b3a8eb9SGleb Smirnoff 		;
27523b3a8eb9SGleb Smirnoff 
27533b3a8eb9SGleb Smirnoff af		: /* empty */			{ $$ = 0; }
27543b3a8eb9SGleb Smirnoff 		| INET				{ $$ = AF_INET; }
27553b3a8eb9SGleb Smirnoff 		| INET6				{ $$ = AF_INET6; }
27563b3a8eb9SGleb Smirnoff 		;
27573b3a8eb9SGleb Smirnoff 
27583b3a8eb9SGleb Smirnoff proto		: /* empty */				{ $$ = NULL; }
27593b3a8eb9SGleb Smirnoff 		| PROTO proto_item			{ $$ = $2; }
27603b3a8eb9SGleb Smirnoff 		| PROTO '{' optnl proto_list '}'	{ $$ = $4; }
27613b3a8eb9SGleb Smirnoff 		;
27623b3a8eb9SGleb Smirnoff 
27633b3a8eb9SGleb Smirnoff proto_list	: proto_item optnl		{ $$ = $1; }
27643b3a8eb9SGleb Smirnoff 		| proto_list comma proto_item optnl	{
27653b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
27663b3a8eb9SGleb Smirnoff 			$1->tail = $3;
27673b3a8eb9SGleb Smirnoff 			$$ = $1;
27683b3a8eb9SGleb Smirnoff 		}
27693b3a8eb9SGleb Smirnoff 		;
27703b3a8eb9SGleb Smirnoff 
27713b3a8eb9SGleb Smirnoff proto_item	: protoval			{
27723b3a8eb9SGleb Smirnoff 			u_int8_t	pr;
27733b3a8eb9SGleb Smirnoff 
27743b3a8eb9SGleb Smirnoff 			pr = (u_int8_t)$1;
27753b3a8eb9SGleb Smirnoff 			if (pr == 0) {
27763b3a8eb9SGleb Smirnoff 				yyerror("proto 0 cannot be used");
27773b3a8eb9SGleb Smirnoff 				YYERROR;
27783b3a8eb9SGleb Smirnoff 			}
27793b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_proto));
27803b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
27813b3a8eb9SGleb Smirnoff 				err(1, "proto_item: calloc");
27823b3a8eb9SGleb Smirnoff 			$$->proto = pr;
27833b3a8eb9SGleb Smirnoff 			$$->next = NULL;
27843b3a8eb9SGleb Smirnoff 			$$->tail = $$;
27853b3a8eb9SGleb Smirnoff 		}
27863b3a8eb9SGleb Smirnoff 		;
27873b3a8eb9SGleb Smirnoff 
27883b3a8eb9SGleb Smirnoff protoval	: STRING			{
27893b3a8eb9SGleb Smirnoff 			struct protoent	*p;
27903b3a8eb9SGleb Smirnoff 
27913b3a8eb9SGleb Smirnoff 			p = getprotobyname($1);
27923b3a8eb9SGleb Smirnoff 			if (p == NULL) {
27933b3a8eb9SGleb Smirnoff 				yyerror("unknown protocol %s", $1);
27943b3a8eb9SGleb Smirnoff 				free($1);
27953b3a8eb9SGleb Smirnoff 				YYERROR;
27963b3a8eb9SGleb Smirnoff 			}
27973b3a8eb9SGleb Smirnoff 			$$ = p->p_proto;
27983b3a8eb9SGleb Smirnoff 			free($1);
27993b3a8eb9SGleb Smirnoff 		}
28003b3a8eb9SGleb Smirnoff 		| NUMBER			{
28013b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
28023b3a8eb9SGleb Smirnoff 				yyerror("protocol outside range");
28033b3a8eb9SGleb Smirnoff 				YYERROR;
28043b3a8eb9SGleb Smirnoff 			}
28053b3a8eb9SGleb Smirnoff 		}
28063b3a8eb9SGleb Smirnoff 		;
28073b3a8eb9SGleb Smirnoff 
28083b3a8eb9SGleb Smirnoff fromto		: ALL				{
28093b3a8eb9SGleb Smirnoff 			$$.src.host = NULL;
28103b3a8eb9SGleb Smirnoff 			$$.src.port = NULL;
28113b3a8eb9SGleb Smirnoff 			$$.dst.host = NULL;
28123b3a8eb9SGleb Smirnoff 			$$.dst.port = NULL;
28133b3a8eb9SGleb Smirnoff 			$$.src_os = NULL;
28143b3a8eb9SGleb Smirnoff 		}
28153b3a8eb9SGleb Smirnoff 		| from os to			{
28163b3a8eb9SGleb Smirnoff 			$$.src = $1;
28173b3a8eb9SGleb Smirnoff 			$$.src_os = $2;
28183b3a8eb9SGleb Smirnoff 			$$.dst = $3;
28193b3a8eb9SGleb Smirnoff 		}
28203b3a8eb9SGleb Smirnoff 		;
28213b3a8eb9SGleb Smirnoff 
28223b3a8eb9SGleb Smirnoff os		: /* empty */			{ $$ = NULL; }
28233b3a8eb9SGleb Smirnoff 		| OS xos			{ $$ = $2; }
28243b3a8eb9SGleb Smirnoff 		| OS '{' optnl os_list '}'	{ $$ = $4; }
28253b3a8eb9SGleb Smirnoff 		;
28263b3a8eb9SGleb Smirnoff 
28273b3a8eb9SGleb Smirnoff xos		: STRING {
28283b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_os));
28293b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
28303b3a8eb9SGleb Smirnoff 				err(1, "os: calloc");
28313b3a8eb9SGleb Smirnoff 			$$->os = $1;
28323b3a8eb9SGleb Smirnoff 			$$->tail = $$;
28333b3a8eb9SGleb Smirnoff 		}
28343b3a8eb9SGleb Smirnoff 		;
28353b3a8eb9SGleb Smirnoff 
28363b3a8eb9SGleb Smirnoff os_list		: xos optnl 			{ $$ = $1; }
28373b3a8eb9SGleb Smirnoff 		| os_list comma xos optnl	{
28383b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
28393b3a8eb9SGleb Smirnoff 			$1->tail = $3;
28403b3a8eb9SGleb Smirnoff 			$$ = $1;
28413b3a8eb9SGleb Smirnoff 		}
28423b3a8eb9SGleb Smirnoff 		;
28433b3a8eb9SGleb Smirnoff 
28443b3a8eb9SGleb Smirnoff from		: /* empty */			{
28453b3a8eb9SGleb Smirnoff 			$$.host = NULL;
28463b3a8eb9SGleb Smirnoff 			$$.port = NULL;
28473b3a8eb9SGleb Smirnoff 		}
28483b3a8eb9SGleb Smirnoff 		| FROM ipportspec		{
28493b3a8eb9SGleb Smirnoff 			$$ = $2;
28503b3a8eb9SGleb Smirnoff 		}
28513b3a8eb9SGleb Smirnoff 		;
28523b3a8eb9SGleb Smirnoff 
28533b3a8eb9SGleb Smirnoff to		: /* empty */			{
28543b3a8eb9SGleb Smirnoff 			$$.host = NULL;
28553b3a8eb9SGleb Smirnoff 			$$.port = NULL;
28563b3a8eb9SGleb Smirnoff 		}
28573b3a8eb9SGleb Smirnoff 		| TO ipportspec		{
28583b3a8eb9SGleb Smirnoff 			if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
28593b3a8eb9SGleb Smirnoff 			    "not permitted in a destination address"))
28603b3a8eb9SGleb Smirnoff 				YYERROR;
28613b3a8eb9SGleb Smirnoff 			$$ = $2;
28623b3a8eb9SGleb Smirnoff 		}
28633b3a8eb9SGleb Smirnoff 		;
28643b3a8eb9SGleb Smirnoff 
28653b3a8eb9SGleb Smirnoff ipportspec	: ipspec			{
28663b3a8eb9SGleb Smirnoff 			$$.host = $1;
28673b3a8eb9SGleb Smirnoff 			$$.port = NULL;
28683b3a8eb9SGleb Smirnoff 		}
28693b3a8eb9SGleb Smirnoff 		| ipspec PORT portspec		{
28703b3a8eb9SGleb Smirnoff 			$$.host = $1;
28713b3a8eb9SGleb Smirnoff 			$$.port = $3;
28723b3a8eb9SGleb Smirnoff 		}
28733b3a8eb9SGleb Smirnoff 		| PORT portspec			{
28743b3a8eb9SGleb Smirnoff 			$$.host = NULL;
28753b3a8eb9SGleb Smirnoff 			$$.port = $2;
28763b3a8eb9SGleb Smirnoff 		}
28773b3a8eb9SGleb Smirnoff 		;
28783b3a8eb9SGleb Smirnoff 
28793b3a8eb9SGleb Smirnoff optnl		: '\n' optnl
28803b3a8eb9SGleb Smirnoff 		|
28813b3a8eb9SGleb Smirnoff 		;
28823b3a8eb9SGleb Smirnoff 
28833b3a8eb9SGleb Smirnoff ipspec		: ANY				{ $$ = NULL; }
28843b3a8eb9SGleb Smirnoff 		| xhost				{ $$ = $1; }
28853b3a8eb9SGleb Smirnoff 		| '{' optnl host_list '}'	{ $$ = $3; }
28863b3a8eb9SGleb Smirnoff 		;
28873b3a8eb9SGleb Smirnoff 
28883b3a8eb9SGleb Smirnoff toipspec	: TO ipspec			{ $$ = $2; }
28893b3a8eb9SGleb Smirnoff 		| /* empty */			{ $$ = NULL; }
28903b3a8eb9SGleb Smirnoff 		;
28913b3a8eb9SGleb Smirnoff 
28923b3a8eb9SGleb Smirnoff host_list	: ipspec optnl			{ $$ = $1; }
28933b3a8eb9SGleb Smirnoff 		| host_list comma ipspec optnl	{
28943b3a8eb9SGleb Smirnoff 			if ($3 == NULL)
28953b3a8eb9SGleb Smirnoff 				$$ = $1;
28963b3a8eb9SGleb Smirnoff 			else if ($1 == NULL)
28973b3a8eb9SGleb Smirnoff 				$$ = $3;
28983b3a8eb9SGleb Smirnoff 			else {
28993b3a8eb9SGleb Smirnoff 				$1->tail->next = $3;
29003b3a8eb9SGleb Smirnoff 				$1->tail = $3->tail;
29013b3a8eb9SGleb Smirnoff 				$$ = $1;
29023b3a8eb9SGleb Smirnoff 			}
29033b3a8eb9SGleb Smirnoff 		}
29043b3a8eb9SGleb Smirnoff 		;
29053b3a8eb9SGleb Smirnoff 
29063b3a8eb9SGleb Smirnoff xhost		: not host			{
29073b3a8eb9SGleb Smirnoff 			struct node_host	*n;
29083b3a8eb9SGleb Smirnoff 
29093b3a8eb9SGleb Smirnoff 			for (n = $2; n != NULL; n = n->next)
29103b3a8eb9SGleb Smirnoff 				n->not = $1;
29113b3a8eb9SGleb Smirnoff 			$$ = $2;
29123b3a8eb9SGleb Smirnoff 		}
29133b3a8eb9SGleb Smirnoff 		| not NOROUTE			{
29143b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
29153b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
29163b3a8eb9SGleb Smirnoff 				err(1, "xhost: calloc");
29173b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_NOROUTE;
29183b3a8eb9SGleb Smirnoff 			$$->next = NULL;
29193b3a8eb9SGleb Smirnoff 			$$->not = $1;
29203b3a8eb9SGleb Smirnoff 			$$->tail = $$;
29213b3a8eb9SGleb Smirnoff 		}
29223b3a8eb9SGleb Smirnoff 		| not URPFFAILED		{
29233b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
29243b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
29253b3a8eb9SGleb Smirnoff 				err(1, "xhost: calloc");
29263b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_URPFFAILED;
29273b3a8eb9SGleb Smirnoff 			$$->next = NULL;
29283b3a8eb9SGleb Smirnoff 			$$->not = $1;
29293b3a8eb9SGleb Smirnoff 			$$->tail = $$;
29303b3a8eb9SGleb Smirnoff 		}
29313b3a8eb9SGleb Smirnoff 		;
29323b3a8eb9SGleb Smirnoff 
29333b3a8eb9SGleb Smirnoff host		: STRING			{
29343b3a8eb9SGleb Smirnoff 			if (($$ = host($1)) == NULL)	{
29353b3a8eb9SGleb Smirnoff 				/* error. "any" is handled elsewhere */
29363b3a8eb9SGleb Smirnoff 				free($1);
29373b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
29383b3a8eb9SGleb Smirnoff 				YYERROR;
29393b3a8eb9SGleb Smirnoff 			}
29403b3a8eb9SGleb Smirnoff 			free($1);
29413b3a8eb9SGleb Smirnoff 
29423b3a8eb9SGleb Smirnoff 		}
29433b3a8eb9SGleb Smirnoff 		| STRING '-' STRING		{
29443b3a8eb9SGleb Smirnoff 			struct node_host *b, *e;
29453b3a8eb9SGleb Smirnoff 
29463b3a8eb9SGleb Smirnoff 			if ((b = host($1)) == NULL || (e = host($3)) == NULL) {
29473b3a8eb9SGleb Smirnoff 				free($1);
29483b3a8eb9SGleb Smirnoff 				free($3);
29493b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
29503b3a8eb9SGleb Smirnoff 				YYERROR;
29513b3a8eb9SGleb Smirnoff 			}
29523b3a8eb9SGleb Smirnoff 			if (b->af != e->af ||
29533b3a8eb9SGleb Smirnoff 			    b->addr.type != PF_ADDR_ADDRMASK ||
29543b3a8eb9SGleb Smirnoff 			    e->addr.type != PF_ADDR_ADDRMASK ||
29553b3a8eb9SGleb Smirnoff 			    unmask(&b->addr.v.a.mask, b->af) !=
29563b3a8eb9SGleb Smirnoff 			    (b->af == AF_INET ? 32 : 128) ||
29573b3a8eb9SGleb Smirnoff 			    unmask(&e->addr.v.a.mask, e->af) !=
29583b3a8eb9SGleb Smirnoff 			    (e->af == AF_INET ? 32 : 128) ||
29593b3a8eb9SGleb Smirnoff 			    b->next != NULL || b->not ||
29603b3a8eb9SGleb Smirnoff 			    e->next != NULL || e->not) {
29613b3a8eb9SGleb Smirnoff 				free(b);
29623b3a8eb9SGleb Smirnoff 				free(e);
29633b3a8eb9SGleb Smirnoff 				free($1);
29643b3a8eb9SGleb Smirnoff 				free($3);
29653b3a8eb9SGleb Smirnoff 				yyerror("invalid address range");
29663b3a8eb9SGleb Smirnoff 				YYERROR;
29673b3a8eb9SGleb Smirnoff 			}
29683b3a8eb9SGleb Smirnoff 			memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
29693b3a8eb9SGleb Smirnoff 			    sizeof(b->addr.v.a.mask));
29703b3a8eb9SGleb Smirnoff 			b->addr.type = PF_ADDR_RANGE;
29713b3a8eb9SGleb Smirnoff 			$$ = b;
29723b3a8eb9SGleb Smirnoff 			free(e);
29733b3a8eb9SGleb Smirnoff 			free($1);
29743b3a8eb9SGleb Smirnoff 			free($3);
29753b3a8eb9SGleb Smirnoff 		}
29763b3a8eb9SGleb Smirnoff 		| STRING '/' NUMBER		{
29773b3a8eb9SGleb Smirnoff 			char	*buf;
29783b3a8eb9SGleb Smirnoff 
29793b3a8eb9SGleb Smirnoff 			if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1)
29803b3a8eb9SGleb Smirnoff 				err(1, "host: asprintf");
29813b3a8eb9SGleb Smirnoff 			free($1);
29823b3a8eb9SGleb Smirnoff 			if (($$ = host(buf)) == NULL)	{
29833b3a8eb9SGleb Smirnoff 				/* error. "any" is handled elsewhere */
29843b3a8eb9SGleb Smirnoff 				free(buf);
29853b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
29863b3a8eb9SGleb Smirnoff 				YYERROR;
29873b3a8eb9SGleb Smirnoff 			}
29883b3a8eb9SGleb Smirnoff 			free(buf);
29893b3a8eb9SGleb Smirnoff 		}
29903b3a8eb9SGleb Smirnoff 		| NUMBER '/' NUMBER		{
29913b3a8eb9SGleb Smirnoff 			char	*buf;
29923b3a8eb9SGleb Smirnoff 
29933b3a8eb9SGleb Smirnoff 			/* ie. for 10/8 parsing */
29943b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
29953b3a8eb9SGleb Smirnoff 			if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1)
29963b3a8eb9SGleb Smirnoff #else
29973b3a8eb9SGleb Smirnoff 			if (asprintf(&buf, "%lld/%lld", $1, $3) == -1)
29983b3a8eb9SGleb Smirnoff #endif
29993b3a8eb9SGleb Smirnoff 				err(1, "host: asprintf");
30003b3a8eb9SGleb Smirnoff 			if (($$ = host(buf)) == NULL)	{
30013b3a8eb9SGleb Smirnoff 				/* error. "any" is handled elsewhere */
30023b3a8eb9SGleb Smirnoff 				free(buf);
30033b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
30043b3a8eb9SGleb Smirnoff 				YYERROR;
30053b3a8eb9SGleb Smirnoff 			}
30063b3a8eb9SGleb Smirnoff 			free(buf);
30073b3a8eb9SGleb Smirnoff 		}
30083b3a8eb9SGleb Smirnoff 		| dynaddr
30093b3a8eb9SGleb Smirnoff 		| dynaddr '/' NUMBER		{
30103b3a8eb9SGleb Smirnoff 			struct node_host	*n;
30113b3a8eb9SGleb Smirnoff 
30123b3a8eb9SGleb Smirnoff 			if ($3 < 0 || $3 > 128) {
30133b3a8eb9SGleb Smirnoff 				yyerror("bit number too big");
30143b3a8eb9SGleb Smirnoff 				YYERROR;
30153b3a8eb9SGleb Smirnoff 			}
30163b3a8eb9SGleb Smirnoff 			$$ = $1;
30173b3a8eb9SGleb Smirnoff 			for (n = $1; n != NULL; n = n->next)
30183b3a8eb9SGleb Smirnoff 				set_ipmask(n, $3);
30193b3a8eb9SGleb Smirnoff 		}
30203b3a8eb9SGleb Smirnoff 		| '<' STRING '>'	{
30213b3a8eb9SGleb Smirnoff 			if (strlen($2) >= PF_TABLE_NAME_SIZE) {
30223b3a8eb9SGleb Smirnoff 				yyerror("table name '%s' too long", $2);
30233b3a8eb9SGleb Smirnoff 				free($2);
30243b3a8eb9SGleb Smirnoff 				YYERROR;
30253b3a8eb9SGleb Smirnoff 			}
30263b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
30273b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
30283b3a8eb9SGleb Smirnoff 				err(1, "host: calloc");
30293b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_TABLE;
30303b3a8eb9SGleb Smirnoff 			if (strlcpy($$->addr.v.tblname, $2,
30313b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.tblname)) >=
30323b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.tblname))
30333b3a8eb9SGleb Smirnoff 				errx(1, "host: strlcpy");
30343b3a8eb9SGleb Smirnoff 			free($2);
30353b3a8eb9SGleb Smirnoff 			$$->next = NULL;
30363b3a8eb9SGleb Smirnoff 			$$->tail = $$;
30373b3a8eb9SGleb Smirnoff 		}
30383b3a8eb9SGleb Smirnoff 		;
30393b3a8eb9SGleb Smirnoff 
30403b3a8eb9SGleb Smirnoff number		: NUMBER
30413b3a8eb9SGleb Smirnoff 		| STRING		{
30423b3a8eb9SGleb Smirnoff 			u_long	ulval;
30433b3a8eb9SGleb Smirnoff 
30443b3a8eb9SGleb Smirnoff 			if (atoul($1, &ulval) == -1) {
30453b3a8eb9SGleb Smirnoff 				yyerror("%s is not a number", $1);
30463b3a8eb9SGleb Smirnoff 				free($1);
30473b3a8eb9SGleb Smirnoff 				YYERROR;
30483b3a8eb9SGleb Smirnoff 			} else
30493b3a8eb9SGleb Smirnoff 				$$ = ulval;
30503b3a8eb9SGleb Smirnoff 			free($1);
30513b3a8eb9SGleb Smirnoff 		}
30523b3a8eb9SGleb Smirnoff 		;
30533b3a8eb9SGleb Smirnoff 
30543b3a8eb9SGleb Smirnoff dynaddr		: '(' STRING ')'		{
30553b3a8eb9SGleb Smirnoff 			int	 flags = 0;
30563b3a8eb9SGleb Smirnoff 			char	*p, *op;
30573b3a8eb9SGleb Smirnoff 
30583b3a8eb9SGleb Smirnoff 			op = $2;
30593b3a8eb9SGleb Smirnoff 			if (!isalpha(op[0])) {
30603b3a8eb9SGleb Smirnoff 				yyerror("invalid interface name '%s'", op);
30613b3a8eb9SGleb Smirnoff 				free(op);
30623b3a8eb9SGleb Smirnoff 				YYERROR;
30633b3a8eb9SGleb Smirnoff 			}
30643b3a8eb9SGleb Smirnoff 			while ((p = strrchr($2, ':')) != NULL) {
30653b3a8eb9SGleb Smirnoff 				if (!strcmp(p+1, "network"))
30663b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_NETWORK;
30673b3a8eb9SGleb Smirnoff 				else if (!strcmp(p+1, "broadcast"))
30683b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_BROADCAST;
30693b3a8eb9SGleb Smirnoff 				else if (!strcmp(p+1, "peer"))
30703b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_PEER;
30713b3a8eb9SGleb Smirnoff 				else if (!strcmp(p+1, "0"))
30723b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_NOALIAS;
30733b3a8eb9SGleb Smirnoff 				else {
30743b3a8eb9SGleb Smirnoff 					yyerror("interface %s has bad modifier",
30753b3a8eb9SGleb Smirnoff 					    $2);
30763b3a8eb9SGleb Smirnoff 					free(op);
30773b3a8eb9SGleb Smirnoff 					YYERROR;
30783b3a8eb9SGleb Smirnoff 				}
30793b3a8eb9SGleb Smirnoff 				*p = '\0';
30803b3a8eb9SGleb Smirnoff 			}
30813b3a8eb9SGleb Smirnoff 			if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
30823b3a8eb9SGleb Smirnoff 				free(op);
30833b3a8eb9SGleb Smirnoff 				yyerror("illegal combination of "
30843b3a8eb9SGleb Smirnoff 				    "interface modifiers");
30853b3a8eb9SGleb Smirnoff 				YYERROR;
30863b3a8eb9SGleb Smirnoff 			}
30873b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
30883b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
30893b3a8eb9SGleb Smirnoff 				err(1, "address: calloc");
30903b3a8eb9SGleb Smirnoff 			$$->af = 0;
30913b3a8eb9SGleb Smirnoff 			set_ipmask($$, 128);
30923b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_DYNIFTL;
30933b3a8eb9SGleb Smirnoff 			$$->addr.iflags = flags;
30943b3a8eb9SGleb Smirnoff 			if (strlcpy($$->addr.v.ifname, $2,
30953b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.ifname)) >=
30963b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.ifname)) {
30973b3a8eb9SGleb Smirnoff 				free(op);
30983b3a8eb9SGleb Smirnoff 				free($$);
30993b3a8eb9SGleb Smirnoff 				yyerror("interface name too long");
31003b3a8eb9SGleb Smirnoff 				YYERROR;
31013b3a8eb9SGleb Smirnoff 			}
31023b3a8eb9SGleb Smirnoff 			free(op);
31033b3a8eb9SGleb Smirnoff 			$$->next = NULL;
31043b3a8eb9SGleb Smirnoff 			$$->tail = $$;
31053b3a8eb9SGleb Smirnoff 		}
31063b3a8eb9SGleb Smirnoff 		;
31073b3a8eb9SGleb Smirnoff 
31083b3a8eb9SGleb Smirnoff portspec	: port_item			{ $$ = $1; }
31093b3a8eb9SGleb Smirnoff 		| '{' optnl port_list '}'	{ $$ = $3; }
31103b3a8eb9SGleb Smirnoff 		;
31113b3a8eb9SGleb Smirnoff 
31123b3a8eb9SGleb Smirnoff port_list	: port_item optnl		{ $$ = $1; }
31133b3a8eb9SGleb Smirnoff 		| port_list comma port_item optnl	{
31143b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
31153b3a8eb9SGleb Smirnoff 			$1->tail = $3;
31163b3a8eb9SGleb Smirnoff 			$$ = $1;
31173b3a8eb9SGleb Smirnoff 		}
31183b3a8eb9SGleb Smirnoff 		;
31193b3a8eb9SGleb Smirnoff 
31203b3a8eb9SGleb Smirnoff port_item	: portrange			{
31213b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_port));
31223b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
31233b3a8eb9SGleb Smirnoff 				err(1, "port_item: calloc");
31243b3a8eb9SGleb Smirnoff 			$$->port[0] = $1.a;
31253b3a8eb9SGleb Smirnoff 			$$->port[1] = $1.b;
31263b3a8eb9SGleb Smirnoff 			if ($1.t)
31273b3a8eb9SGleb Smirnoff 				$$->op = PF_OP_RRG;
31283b3a8eb9SGleb Smirnoff 			else
31293b3a8eb9SGleb Smirnoff 				$$->op = PF_OP_EQ;
31303b3a8eb9SGleb Smirnoff 			$$->next = NULL;
31313b3a8eb9SGleb Smirnoff 			$$->tail = $$;
31323b3a8eb9SGleb Smirnoff 		}
31333b3a8eb9SGleb Smirnoff 		| unaryop portrange	{
31343b3a8eb9SGleb Smirnoff 			if ($2.t) {
31353b3a8eb9SGleb Smirnoff 				yyerror("':' cannot be used with an other "
31363b3a8eb9SGleb Smirnoff 				    "port operator");
31373b3a8eb9SGleb Smirnoff 				YYERROR;
31383b3a8eb9SGleb Smirnoff 			}
31393b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_port));
31403b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
31413b3a8eb9SGleb Smirnoff 				err(1, "port_item: calloc");
31423b3a8eb9SGleb Smirnoff 			$$->port[0] = $2.a;
31433b3a8eb9SGleb Smirnoff 			$$->port[1] = $2.b;
31443b3a8eb9SGleb Smirnoff 			$$->op = $1;
31453b3a8eb9SGleb Smirnoff 			$$->next = NULL;
31463b3a8eb9SGleb Smirnoff 			$$->tail = $$;
31473b3a8eb9SGleb Smirnoff 		}
31483b3a8eb9SGleb Smirnoff 		| portrange PORTBINARY portrange	{
31493b3a8eb9SGleb Smirnoff 			if ($1.t || $3.t) {
31503b3a8eb9SGleb Smirnoff 				yyerror("':' cannot be used with an other "
31513b3a8eb9SGleb Smirnoff 				    "port operator");
31523b3a8eb9SGleb Smirnoff 				YYERROR;
31533b3a8eb9SGleb Smirnoff 			}
31543b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_port));
31553b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
31563b3a8eb9SGleb Smirnoff 				err(1, "port_item: calloc");
31573b3a8eb9SGleb Smirnoff 			$$->port[0] = $1.a;
31583b3a8eb9SGleb Smirnoff 			$$->port[1] = $3.a;
31593b3a8eb9SGleb Smirnoff 			$$->op = $2;
31603b3a8eb9SGleb Smirnoff 			$$->next = NULL;
31613b3a8eb9SGleb Smirnoff 			$$->tail = $$;
31623b3a8eb9SGleb Smirnoff 		}
31633b3a8eb9SGleb Smirnoff 		;
31643b3a8eb9SGleb Smirnoff 
31653b3a8eb9SGleb Smirnoff portplain	: numberstring			{
31663b3a8eb9SGleb Smirnoff 			if (parseport($1, &$$, 0) == -1) {
31673b3a8eb9SGleb Smirnoff 				free($1);
31683b3a8eb9SGleb Smirnoff 				YYERROR;
31693b3a8eb9SGleb Smirnoff 			}
31703b3a8eb9SGleb Smirnoff 			free($1);
31713b3a8eb9SGleb Smirnoff 		}
31723b3a8eb9SGleb Smirnoff 		;
31733b3a8eb9SGleb Smirnoff 
31743b3a8eb9SGleb Smirnoff portrange	: numberstring			{
31753b3a8eb9SGleb Smirnoff 			if (parseport($1, &$$, PPORT_RANGE) == -1) {
31763b3a8eb9SGleb Smirnoff 				free($1);
31773b3a8eb9SGleb Smirnoff 				YYERROR;
31783b3a8eb9SGleb Smirnoff 			}
31793b3a8eb9SGleb Smirnoff 			free($1);
31803b3a8eb9SGleb Smirnoff 		}
31813b3a8eb9SGleb Smirnoff 		;
31823b3a8eb9SGleb Smirnoff 
31833b3a8eb9SGleb Smirnoff uids		: uid_item			{ $$ = $1; }
31843b3a8eb9SGleb Smirnoff 		| '{' optnl uid_list '}'	{ $$ = $3; }
31853b3a8eb9SGleb Smirnoff 		;
31863b3a8eb9SGleb Smirnoff 
31873b3a8eb9SGleb Smirnoff uid_list	: uid_item optnl		{ $$ = $1; }
31883b3a8eb9SGleb Smirnoff 		| uid_list comma uid_item optnl	{
31893b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
31903b3a8eb9SGleb Smirnoff 			$1->tail = $3;
31913b3a8eb9SGleb Smirnoff 			$$ = $1;
31923b3a8eb9SGleb Smirnoff 		}
31933b3a8eb9SGleb Smirnoff 		;
31943b3a8eb9SGleb Smirnoff 
31953b3a8eb9SGleb Smirnoff uid_item	: uid				{
31963b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_uid));
31973b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
31983b3a8eb9SGleb Smirnoff 				err(1, "uid_item: calloc");
31993b3a8eb9SGleb Smirnoff 			$$->uid[0] = $1;
32003b3a8eb9SGleb Smirnoff 			$$->uid[1] = $1;
32013b3a8eb9SGleb Smirnoff 			$$->op = PF_OP_EQ;
32023b3a8eb9SGleb Smirnoff 			$$->next = NULL;
32033b3a8eb9SGleb Smirnoff 			$$->tail = $$;
32043b3a8eb9SGleb Smirnoff 		}
32053b3a8eb9SGleb Smirnoff 		| unaryop uid			{
32063b3a8eb9SGleb Smirnoff 			if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
32073b3a8eb9SGleb Smirnoff 				yyerror("user unknown requires operator = or "
32083b3a8eb9SGleb Smirnoff 				    "!=");
32093b3a8eb9SGleb Smirnoff 				YYERROR;
32103b3a8eb9SGleb Smirnoff 			}
32113b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_uid));
32123b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
32133b3a8eb9SGleb Smirnoff 				err(1, "uid_item: calloc");
32143b3a8eb9SGleb Smirnoff 			$$->uid[0] = $2;
32153b3a8eb9SGleb Smirnoff 			$$->uid[1] = $2;
32163b3a8eb9SGleb Smirnoff 			$$->op = $1;
32173b3a8eb9SGleb Smirnoff 			$$->next = NULL;
32183b3a8eb9SGleb Smirnoff 			$$->tail = $$;
32193b3a8eb9SGleb Smirnoff 		}
32203b3a8eb9SGleb Smirnoff 		| uid PORTBINARY uid		{
32213b3a8eb9SGleb Smirnoff 			if ($1 == UID_MAX || $3 == UID_MAX) {
32223b3a8eb9SGleb Smirnoff 				yyerror("user unknown requires operator = or "
32233b3a8eb9SGleb Smirnoff 				    "!=");
32243b3a8eb9SGleb Smirnoff 				YYERROR;
32253b3a8eb9SGleb Smirnoff 			}
32263b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_uid));
32273b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
32283b3a8eb9SGleb Smirnoff 				err(1, "uid_item: calloc");
32293b3a8eb9SGleb Smirnoff 			$$->uid[0] = $1;
32303b3a8eb9SGleb Smirnoff 			$$->uid[1] = $3;
32313b3a8eb9SGleb Smirnoff 			$$->op = $2;
32323b3a8eb9SGleb Smirnoff 			$$->next = NULL;
32333b3a8eb9SGleb Smirnoff 			$$->tail = $$;
32343b3a8eb9SGleb Smirnoff 		}
32353b3a8eb9SGleb Smirnoff 		;
32363b3a8eb9SGleb Smirnoff 
32373b3a8eb9SGleb Smirnoff uid		: STRING			{
32383b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "unknown"))
32393b3a8eb9SGleb Smirnoff 				$$ = UID_MAX;
32403b3a8eb9SGleb Smirnoff 			else {
32413b3a8eb9SGleb Smirnoff 				struct passwd	*pw;
32423b3a8eb9SGleb Smirnoff 
32433b3a8eb9SGleb Smirnoff 				if ((pw = getpwnam($1)) == NULL) {
32443b3a8eb9SGleb Smirnoff 					yyerror("unknown user %s", $1);
32453b3a8eb9SGleb Smirnoff 					free($1);
32463b3a8eb9SGleb Smirnoff 					YYERROR;
32473b3a8eb9SGleb Smirnoff 				}
32483b3a8eb9SGleb Smirnoff 				$$ = pw->pw_uid;
32493b3a8eb9SGleb Smirnoff 			}
32503b3a8eb9SGleb Smirnoff 			free($1);
32513b3a8eb9SGleb Smirnoff 		}
32523b3a8eb9SGleb Smirnoff 		| NUMBER			{
32533b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 >= UID_MAX) {
32543b3a8eb9SGleb Smirnoff 				yyerror("illegal uid value %lu", $1);
32553b3a8eb9SGleb Smirnoff 				YYERROR;
32563b3a8eb9SGleb Smirnoff 			}
32573b3a8eb9SGleb Smirnoff 			$$ = $1;
32583b3a8eb9SGleb Smirnoff 		}
32593b3a8eb9SGleb Smirnoff 		;
32603b3a8eb9SGleb Smirnoff 
32613b3a8eb9SGleb Smirnoff gids		: gid_item			{ $$ = $1; }
32623b3a8eb9SGleb Smirnoff 		| '{' optnl gid_list '}'	{ $$ = $3; }
32633b3a8eb9SGleb Smirnoff 		;
32643b3a8eb9SGleb Smirnoff 
32653b3a8eb9SGleb Smirnoff gid_list	: gid_item optnl		{ $$ = $1; }
32663b3a8eb9SGleb Smirnoff 		| gid_list comma gid_item optnl	{
32673b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
32683b3a8eb9SGleb Smirnoff 			$1->tail = $3;
32693b3a8eb9SGleb Smirnoff 			$$ = $1;
32703b3a8eb9SGleb Smirnoff 		}
32713b3a8eb9SGleb Smirnoff 		;
32723b3a8eb9SGleb Smirnoff 
32733b3a8eb9SGleb Smirnoff gid_item	: gid				{
32743b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_gid));
32753b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
32763b3a8eb9SGleb Smirnoff 				err(1, "gid_item: calloc");
32773b3a8eb9SGleb Smirnoff 			$$->gid[0] = $1;
32783b3a8eb9SGleb Smirnoff 			$$->gid[1] = $1;
32793b3a8eb9SGleb Smirnoff 			$$->op = PF_OP_EQ;
32803b3a8eb9SGleb Smirnoff 			$$->next = NULL;
32813b3a8eb9SGleb Smirnoff 			$$->tail = $$;
32823b3a8eb9SGleb Smirnoff 		}
32833b3a8eb9SGleb Smirnoff 		| unaryop gid			{
32843b3a8eb9SGleb Smirnoff 			if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
32853b3a8eb9SGleb Smirnoff 				yyerror("group unknown requires operator = or "
32863b3a8eb9SGleb Smirnoff 				    "!=");
32873b3a8eb9SGleb Smirnoff 				YYERROR;
32883b3a8eb9SGleb Smirnoff 			}
32893b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_gid));
32903b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
32913b3a8eb9SGleb Smirnoff 				err(1, "gid_item: calloc");
32923b3a8eb9SGleb Smirnoff 			$$->gid[0] = $2;
32933b3a8eb9SGleb Smirnoff 			$$->gid[1] = $2;
32943b3a8eb9SGleb Smirnoff 			$$->op = $1;
32953b3a8eb9SGleb Smirnoff 			$$->next = NULL;
32963b3a8eb9SGleb Smirnoff 			$$->tail = $$;
32973b3a8eb9SGleb Smirnoff 		}
32983b3a8eb9SGleb Smirnoff 		| gid PORTBINARY gid		{
32993b3a8eb9SGleb Smirnoff 			if ($1 == GID_MAX || $3 == GID_MAX) {
33003b3a8eb9SGleb Smirnoff 				yyerror("group unknown requires operator = or "
33013b3a8eb9SGleb Smirnoff 				    "!=");
33023b3a8eb9SGleb Smirnoff 				YYERROR;
33033b3a8eb9SGleb Smirnoff 			}
33043b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_gid));
33053b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
33063b3a8eb9SGleb Smirnoff 				err(1, "gid_item: calloc");
33073b3a8eb9SGleb Smirnoff 			$$->gid[0] = $1;
33083b3a8eb9SGleb Smirnoff 			$$->gid[1] = $3;
33093b3a8eb9SGleb Smirnoff 			$$->op = $2;
33103b3a8eb9SGleb Smirnoff 			$$->next = NULL;
33113b3a8eb9SGleb Smirnoff 			$$->tail = $$;
33123b3a8eb9SGleb Smirnoff 		}
33133b3a8eb9SGleb Smirnoff 		;
33143b3a8eb9SGleb Smirnoff 
33153b3a8eb9SGleb Smirnoff gid		: STRING			{
33163b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "unknown"))
33173b3a8eb9SGleb Smirnoff 				$$ = GID_MAX;
33183b3a8eb9SGleb Smirnoff 			else {
33193b3a8eb9SGleb Smirnoff 				struct group	*grp;
33203b3a8eb9SGleb Smirnoff 
33213b3a8eb9SGleb Smirnoff 				if ((grp = getgrnam($1)) == NULL) {
33223b3a8eb9SGleb Smirnoff 					yyerror("unknown group %s", $1);
33233b3a8eb9SGleb Smirnoff 					free($1);
33243b3a8eb9SGleb Smirnoff 					YYERROR;
33253b3a8eb9SGleb Smirnoff 				}
33263b3a8eb9SGleb Smirnoff 				$$ = grp->gr_gid;
33273b3a8eb9SGleb Smirnoff 			}
33283b3a8eb9SGleb Smirnoff 			free($1);
33293b3a8eb9SGleb Smirnoff 		}
33303b3a8eb9SGleb Smirnoff 		| NUMBER			{
33313b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 >= GID_MAX) {
33323b3a8eb9SGleb Smirnoff 				yyerror("illegal gid value %lu", $1);
33333b3a8eb9SGleb Smirnoff 				YYERROR;
33343b3a8eb9SGleb Smirnoff 			}
33353b3a8eb9SGleb Smirnoff 			$$ = $1;
33363b3a8eb9SGleb Smirnoff 		}
33373b3a8eb9SGleb Smirnoff 		;
33383b3a8eb9SGleb Smirnoff 
33393b3a8eb9SGleb Smirnoff flag		: STRING			{
33403b3a8eb9SGleb Smirnoff 			int	f;
33413b3a8eb9SGleb Smirnoff 
33423b3a8eb9SGleb Smirnoff 			if ((f = parse_flags($1)) < 0) {
33433b3a8eb9SGleb Smirnoff 				yyerror("bad flags %s", $1);
33443b3a8eb9SGleb Smirnoff 				free($1);
33453b3a8eb9SGleb Smirnoff 				YYERROR;
33463b3a8eb9SGleb Smirnoff 			}
33473b3a8eb9SGleb Smirnoff 			free($1);
33483b3a8eb9SGleb Smirnoff 			$$.b1 = f;
33493b3a8eb9SGleb Smirnoff 		}
33503b3a8eb9SGleb Smirnoff 		;
33513b3a8eb9SGleb Smirnoff 
33523b3a8eb9SGleb Smirnoff flags		: FLAGS flag '/' flag	{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
33533b3a8eb9SGleb Smirnoff 		| FLAGS '/' flag	{ $$.b1 = 0; $$.b2 = $3.b1; }
33543b3a8eb9SGleb Smirnoff 		| FLAGS ANY		{ $$.b1 = 0; $$.b2 = 0; }
33553b3a8eb9SGleb Smirnoff 		;
33563b3a8eb9SGleb Smirnoff 
33573b3a8eb9SGleb Smirnoff icmpspec	: ICMPTYPE icmp_item			{ $$ = $2; }
33583b3a8eb9SGleb Smirnoff 		| ICMPTYPE '{' optnl icmp_list '}'	{ $$ = $4; }
33593b3a8eb9SGleb Smirnoff 		| ICMP6TYPE icmp6_item			{ $$ = $2; }
33603b3a8eb9SGleb Smirnoff 		| ICMP6TYPE '{' optnl icmp6_list '}'	{ $$ = $4; }
33613b3a8eb9SGleb Smirnoff 		;
33623b3a8eb9SGleb Smirnoff 
33633b3a8eb9SGleb Smirnoff icmp_list	: icmp_item optnl		{ $$ = $1; }
33643b3a8eb9SGleb Smirnoff 		| icmp_list comma icmp_item optnl {
33653b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
33663b3a8eb9SGleb Smirnoff 			$1->tail = $3;
33673b3a8eb9SGleb Smirnoff 			$$ = $1;
33683b3a8eb9SGleb Smirnoff 		}
33693b3a8eb9SGleb Smirnoff 		;
33703b3a8eb9SGleb Smirnoff 
33713b3a8eb9SGleb Smirnoff icmp6_list	: icmp6_item optnl		{ $$ = $1; }
33723b3a8eb9SGleb Smirnoff 		| icmp6_list comma icmp6_item optnl {
33733b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
33743b3a8eb9SGleb Smirnoff 			$1->tail = $3;
33753b3a8eb9SGleb Smirnoff 			$$ = $1;
33763b3a8eb9SGleb Smirnoff 		}
33773b3a8eb9SGleb Smirnoff 		;
33783b3a8eb9SGleb Smirnoff 
33793b3a8eb9SGleb Smirnoff icmp_item	: icmptype		{
33803b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
33813b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
33823b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
33833b3a8eb9SGleb Smirnoff 			$$->type = $1;
33843b3a8eb9SGleb Smirnoff 			$$->code = 0;
33853b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMP;
33863b3a8eb9SGleb Smirnoff 			$$->next = NULL;
33873b3a8eb9SGleb Smirnoff 			$$->tail = $$;
33883b3a8eb9SGleb Smirnoff 		}
33893b3a8eb9SGleb Smirnoff 		| icmptype CODE STRING	{
33903b3a8eb9SGleb Smirnoff 			const struct icmpcodeent	*p;
33913b3a8eb9SGleb Smirnoff 
33923b3a8eb9SGleb Smirnoff 			if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) {
33933b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp-code %s", $3);
33943b3a8eb9SGleb Smirnoff 				free($3);
33953b3a8eb9SGleb Smirnoff 				YYERROR;
33963b3a8eb9SGleb Smirnoff 			}
33973b3a8eb9SGleb Smirnoff 
33983b3a8eb9SGleb Smirnoff 			free($3);
33993b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
34003b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
34013b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
34023b3a8eb9SGleb Smirnoff 			$$->type = $1;
34033b3a8eb9SGleb Smirnoff 			$$->code = p->code + 1;
34043b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMP;
34053b3a8eb9SGleb Smirnoff 			$$->next = NULL;
34063b3a8eb9SGleb Smirnoff 			$$->tail = $$;
34073b3a8eb9SGleb Smirnoff 		}
34083b3a8eb9SGleb Smirnoff 		| icmptype CODE NUMBER	{
34093b3a8eb9SGleb Smirnoff 			if ($3 < 0 || $3 > 255) {
34103b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp-code %lu", $3);
34113b3a8eb9SGleb Smirnoff 				YYERROR;
34123b3a8eb9SGleb Smirnoff 			}
34133b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
34143b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
34153b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
34163b3a8eb9SGleb Smirnoff 			$$->type = $1;
34173b3a8eb9SGleb Smirnoff 			$$->code = $3 + 1;
34183b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMP;
34193b3a8eb9SGleb Smirnoff 			$$->next = NULL;
34203b3a8eb9SGleb Smirnoff 			$$->tail = $$;
34213b3a8eb9SGleb Smirnoff 		}
34223b3a8eb9SGleb Smirnoff 		;
34233b3a8eb9SGleb Smirnoff 
34243b3a8eb9SGleb Smirnoff icmp6_item	: icmp6type		{
34253b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
34263b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
34273b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
34283b3a8eb9SGleb Smirnoff 			$$->type = $1;
34293b3a8eb9SGleb Smirnoff 			$$->code = 0;
34303b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMPV6;
34313b3a8eb9SGleb Smirnoff 			$$->next = NULL;
34323b3a8eb9SGleb Smirnoff 			$$->tail = $$;
34333b3a8eb9SGleb Smirnoff 		}
34343b3a8eb9SGleb Smirnoff 		| icmp6type CODE STRING	{
34353b3a8eb9SGleb Smirnoff 			const struct icmpcodeent	*p;
34363b3a8eb9SGleb Smirnoff 
34373b3a8eb9SGleb Smirnoff 			if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) {
34383b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp6-code %s", $3);
34393b3a8eb9SGleb Smirnoff 				free($3);
34403b3a8eb9SGleb Smirnoff 				YYERROR;
34413b3a8eb9SGleb Smirnoff 			}
34423b3a8eb9SGleb Smirnoff 			free($3);
34433b3a8eb9SGleb Smirnoff 
34443b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
34453b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
34463b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
34473b3a8eb9SGleb Smirnoff 			$$->type = $1;
34483b3a8eb9SGleb Smirnoff 			$$->code = p->code + 1;
34493b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMPV6;
34503b3a8eb9SGleb Smirnoff 			$$->next = NULL;
34513b3a8eb9SGleb Smirnoff 			$$->tail = $$;
34523b3a8eb9SGleb Smirnoff 		}
34533b3a8eb9SGleb Smirnoff 		| icmp6type CODE NUMBER	{
34543b3a8eb9SGleb Smirnoff 			if ($3 < 0 || $3 > 255) {
34553b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp-code %lu", $3);
34563b3a8eb9SGleb Smirnoff 				YYERROR;
34573b3a8eb9SGleb Smirnoff 			}
34583b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
34593b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
34603b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
34613b3a8eb9SGleb Smirnoff 			$$->type = $1;
34623b3a8eb9SGleb Smirnoff 			$$->code = $3 + 1;
34633b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMPV6;
34643b3a8eb9SGleb Smirnoff 			$$->next = NULL;
34653b3a8eb9SGleb Smirnoff 			$$->tail = $$;
34663b3a8eb9SGleb Smirnoff 		}
34673b3a8eb9SGleb Smirnoff 		;
34683b3a8eb9SGleb Smirnoff 
34693b3a8eb9SGleb Smirnoff icmptype	: STRING			{
34703b3a8eb9SGleb Smirnoff 			const struct icmptypeent	*p;
34713b3a8eb9SGleb Smirnoff 
34723b3a8eb9SGleb Smirnoff 			if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
34733b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp-type %s", $1);
34743b3a8eb9SGleb Smirnoff 				free($1);
34753b3a8eb9SGleb Smirnoff 				YYERROR;
34763b3a8eb9SGleb Smirnoff 			}
34773b3a8eb9SGleb Smirnoff 			$$ = p->type + 1;
34783b3a8eb9SGleb Smirnoff 			free($1);
34793b3a8eb9SGleb Smirnoff 		}
34803b3a8eb9SGleb Smirnoff 		| NUMBER			{
34813b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
34823b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp-type %lu", $1);
34833b3a8eb9SGleb Smirnoff 				YYERROR;
34843b3a8eb9SGleb Smirnoff 			}
34853b3a8eb9SGleb Smirnoff 			$$ = $1 + 1;
34863b3a8eb9SGleb Smirnoff 		}
34873b3a8eb9SGleb Smirnoff 		;
34883b3a8eb9SGleb Smirnoff 
34893b3a8eb9SGleb Smirnoff icmp6type	: STRING			{
34903b3a8eb9SGleb Smirnoff 			const struct icmptypeent	*p;
34913b3a8eb9SGleb Smirnoff 
34923b3a8eb9SGleb Smirnoff 			if ((p = geticmptypebyname($1, AF_INET6)) ==
34933b3a8eb9SGleb Smirnoff 			    NULL) {
34943b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp6-type %s", $1);
34953b3a8eb9SGleb Smirnoff 				free($1);
34963b3a8eb9SGleb Smirnoff 				YYERROR;
34973b3a8eb9SGleb Smirnoff 			}
34983b3a8eb9SGleb Smirnoff 			$$ = p->type + 1;
34993b3a8eb9SGleb Smirnoff 			free($1);
35003b3a8eb9SGleb Smirnoff 		}
35013b3a8eb9SGleb Smirnoff 		| NUMBER			{
35023b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
35033b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp6-type %lu", $1);
35043b3a8eb9SGleb Smirnoff 				YYERROR;
35053b3a8eb9SGleb Smirnoff 			}
35063b3a8eb9SGleb Smirnoff 			$$ = $1 + 1;
35073b3a8eb9SGleb Smirnoff 		}
35083b3a8eb9SGleb Smirnoff 		;
35093b3a8eb9SGleb Smirnoff 
35103b3a8eb9SGleb Smirnoff tos	: STRING			{
35113b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "lowdelay"))
35123b3a8eb9SGleb Smirnoff 				$$ = IPTOS_LOWDELAY;
35133b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "throughput"))
35143b3a8eb9SGleb Smirnoff 				$$ = IPTOS_THROUGHPUT;
35153b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "reliability"))
35163b3a8eb9SGleb Smirnoff 				$$ = IPTOS_RELIABILITY;
35173b3a8eb9SGleb Smirnoff 			else if ($1[0] == '0' && $1[1] == 'x')
35183b3a8eb9SGleb Smirnoff 				$$ = strtoul($1, NULL, 16);
35193b3a8eb9SGleb Smirnoff 			else
35203b3a8eb9SGleb Smirnoff 				$$ = 0;		/* flag bad argument */
35213b3a8eb9SGleb Smirnoff 			if (!$$ || $$ > 255) {
35223b3a8eb9SGleb Smirnoff 				yyerror("illegal tos value %s", $1);
35233b3a8eb9SGleb Smirnoff 				free($1);
35243b3a8eb9SGleb Smirnoff 				YYERROR;
35253b3a8eb9SGleb Smirnoff 			}
35263b3a8eb9SGleb Smirnoff 			free($1);
35273b3a8eb9SGleb Smirnoff 		}
35283b3a8eb9SGleb Smirnoff 		| NUMBER			{
35293b3a8eb9SGleb Smirnoff 			$$ = $1;
35303b3a8eb9SGleb Smirnoff 			if (!$$ || $$ > 255) {
35313b3a8eb9SGleb Smirnoff 				yyerror("illegal tos value %s", $1);
35323b3a8eb9SGleb Smirnoff 				YYERROR;
35333b3a8eb9SGleb Smirnoff 			}
35343b3a8eb9SGleb Smirnoff 		}
35353b3a8eb9SGleb Smirnoff 		;
35363b3a8eb9SGleb Smirnoff 
35373b3a8eb9SGleb Smirnoff sourcetrack	: SOURCETRACK		{ $$ = PF_SRCTRACK; }
35383b3a8eb9SGleb Smirnoff 		| SOURCETRACK GLOBAL	{ $$ = PF_SRCTRACK_GLOBAL; }
35393b3a8eb9SGleb Smirnoff 		| SOURCETRACK RULE	{ $$ = PF_SRCTRACK_RULE; }
35403b3a8eb9SGleb Smirnoff 		;
35413b3a8eb9SGleb Smirnoff 
35423b3a8eb9SGleb Smirnoff statelock	: IFBOUND {
35433b3a8eb9SGleb Smirnoff 			$$ = PFRULE_IFBOUND;
35443b3a8eb9SGleb Smirnoff 		}
35453b3a8eb9SGleb Smirnoff 		| FLOATING {
35463b3a8eb9SGleb Smirnoff 			$$ = 0;
35473b3a8eb9SGleb Smirnoff 		}
35483b3a8eb9SGleb Smirnoff 		;
35493b3a8eb9SGleb Smirnoff 
35503b3a8eb9SGleb Smirnoff keep		: NO STATE			{
35513b3a8eb9SGleb Smirnoff 			$$.action = 0;
35523b3a8eb9SGleb Smirnoff 			$$.options = NULL;
35533b3a8eb9SGleb Smirnoff 		}
35543b3a8eb9SGleb Smirnoff 		| KEEP STATE state_opt_spec	{
35553b3a8eb9SGleb Smirnoff 			$$.action = PF_STATE_NORMAL;
35563b3a8eb9SGleb Smirnoff 			$$.options = $3;
35573b3a8eb9SGleb Smirnoff 		}
35583b3a8eb9SGleb Smirnoff 		| MODULATE STATE state_opt_spec {
35593b3a8eb9SGleb Smirnoff 			$$.action = PF_STATE_MODULATE;
35603b3a8eb9SGleb Smirnoff 			$$.options = $3;
35613b3a8eb9SGleb Smirnoff 		}
35623b3a8eb9SGleb Smirnoff 		| SYNPROXY STATE state_opt_spec {
35633b3a8eb9SGleb Smirnoff 			$$.action = PF_STATE_SYNPROXY;
35643b3a8eb9SGleb Smirnoff 			$$.options = $3;
35653b3a8eb9SGleb Smirnoff 		}
35663b3a8eb9SGleb Smirnoff 		;
35673b3a8eb9SGleb Smirnoff 
35683b3a8eb9SGleb Smirnoff flush		: /* empty */			{ $$ = 0; }
35693b3a8eb9SGleb Smirnoff 		| FLUSH				{ $$ = PF_FLUSH; }
35703b3a8eb9SGleb Smirnoff 		| FLUSH GLOBAL			{
35713b3a8eb9SGleb Smirnoff 			$$ = PF_FLUSH | PF_FLUSH_GLOBAL;
35723b3a8eb9SGleb Smirnoff 		}
35733b3a8eb9SGleb Smirnoff 		;
35743b3a8eb9SGleb Smirnoff 
35753b3a8eb9SGleb Smirnoff state_opt_spec	: '(' state_opt_list ')'	{ $$ = $2; }
35763b3a8eb9SGleb Smirnoff 		| /* empty */			{ $$ = NULL; }
35773b3a8eb9SGleb Smirnoff 		;
35783b3a8eb9SGleb Smirnoff 
35793b3a8eb9SGleb Smirnoff state_opt_list	: state_opt_item		{ $$ = $1; }
35803b3a8eb9SGleb Smirnoff 		| state_opt_list comma state_opt_item {
35813b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
35823b3a8eb9SGleb Smirnoff 			$1->tail = $3;
35833b3a8eb9SGleb Smirnoff 			$$ = $1;
35843b3a8eb9SGleb Smirnoff 		}
35853b3a8eb9SGleb Smirnoff 		;
35863b3a8eb9SGleb Smirnoff 
35873b3a8eb9SGleb Smirnoff state_opt_item	: MAXIMUM NUMBER		{
35883b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
35893b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
35903b3a8eb9SGleb Smirnoff 				YYERROR;
35913b3a8eb9SGleb Smirnoff 			}
35923b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
35933b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
35943b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
35953b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX;
35963b3a8eb9SGleb Smirnoff 			$$->data.max_states = $2;
35973b3a8eb9SGleb Smirnoff 			$$->next = NULL;
35983b3a8eb9SGleb Smirnoff 			$$->tail = $$;
35993b3a8eb9SGleb Smirnoff 		}
36003b3a8eb9SGleb Smirnoff 		| NOSYNC				{
36013b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36023b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36033b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36043b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_NOSYNC;
36053b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36063b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36073b3a8eb9SGleb Smirnoff 		}
36083b3a8eb9SGleb Smirnoff 		| MAXSRCSTATES NUMBER			{
36093b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
36103b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
36113b3a8eb9SGleb Smirnoff 				YYERROR;
36123b3a8eb9SGleb Smirnoff 			}
36133b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36143b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36153b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36163b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_STATES;
36173b3a8eb9SGleb Smirnoff 			$$->data.max_src_states = $2;
36183b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36193b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36203b3a8eb9SGleb Smirnoff 		}
36213b3a8eb9SGleb Smirnoff 		| MAXSRCCONN NUMBER			{
36223b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
36233b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
36243b3a8eb9SGleb Smirnoff 				YYERROR;
36253b3a8eb9SGleb Smirnoff 			}
36263b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36273b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36283b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36293b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_CONN;
36303b3a8eb9SGleb Smirnoff 			$$->data.max_src_conn = $2;
36313b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36323b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36333b3a8eb9SGleb Smirnoff 		}
36343b3a8eb9SGleb Smirnoff 		| MAXSRCCONNRATE NUMBER '/' NUMBER	{
36353b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX ||
36363b3a8eb9SGleb Smirnoff 			    $4 < 0 || $4 > UINT_MAX) {
36373b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
36383b3a8eb9SGleb Smirnoff 				YYERROR;
36393b3a8eb9SGleb Smirnoff 			}
36403b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36413b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36423b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36433b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
36443b3a8eb9SGleb Smirnoff 			$$->data.max_src_conn_rate.limit = $2;
36453b3a8eb9SGleb Smirnoff 			$$->data.max_src_conn_rate.seconds = $4;
36463b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36473b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36483b3a8eb9SGleb Smirnoff 		}
36493b3a8eb9SGleb Smirnoff 		| OVERLOAD '<' STRING '>' flush		{
36503b3a8eb9SGleb Smirnoff 			if (strlen($3) >= PF_TABLE_NAME_SIZE) {
36513b3a8eb9SGleb Smirnoff 				yyerror("table name '%s' too long", $3);
36523b3a8eb9SGleb Smirnoff 				free($3);
36533b3a8eb9SGleb Smirnoff 				YYERROR;
36543b3a8eb9SGleb Smirnoff 			}
36553b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36563b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36573b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36583b3a8eb9SGleb Smirnoff 			if (strlcpy($$->data.overload.tblname, $3,
36593b3a8eb9SGleb Smirnoff 			    PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
36603b3a8eb9SGleb Smirnoff 				errx(1, "state_opt_item: strlcpy");
36613b3a8eb9SGleb Smirnoff 			free($3);
36623b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_OVERLOAD;
36633b3a8eb9SGleb Smirnoff 			$$->data.overload.flush = $5;
36643b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36653b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36663b3a8eb9SGleb Smirnoff 		}
36673b3a8eb9SGleb Smirnoff 		| MAXSRCNODES NUMBER			{
36683b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
36693b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
36703b3a8eb9SGleb Smirnoff 				YYERROR;
36713b3a8eb9SGleb Smirnoff 			}
36723b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36733b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36743b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36753b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_NODES;
36763b3a8eb9SGleb Smirnoff 			$$->data.max_src_nodes = $2;
36773b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36783b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36793b3a8eb9SGleb Smirnoff 		}
36803b3a8eb9SGleb Smirnoff 		| sourcetrack {
36813b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36823b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36833b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36843b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_SRCTRACK;
36853b3a8eb9SGleb Smirnoff 			$$->data.src_track = $1;
36863b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36873b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36883b3a8eb9SGleb Smirnoff 		}
36893b3a8eb9SGleb Smirnoff 		| statelock {
36903b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
36913b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36923b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
36933b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_STATELOCK;
36943b3a8eb9SGleb Smirnoff 			$$->data.statelock = $1;
36953b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36963b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36973b3a8eb9SGleb Smirnoff 		}
36983b3a8eb9SGleb Smirnoff 		| SLOPPY {
36993b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
37003b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
37013b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
37023b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_SLOPPY;
37033b3a8eb9SGleb Smirnoff 			$$->next = NULL;
37043b3a8eb9SGleb Smirnoff 			$$->tail = $$;
37053b3a8eb9SGleb Smirnoff 		}
37063b3a8eb9SGleb Smirnoff 		| STRING NUMBER			{
37073b3a8eb9SGleb Smirnoff 			int	i;
37083b3a8eb9SGleb Smirnoff 
37093b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
37103b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
37113b3a8eb9SGleb Smirnoff 				YYERROR;
37123b3a8eb9SGleb Smirnoff 			}
37133b3a8eb9SGleb Smirnoff 			for (i = 0; pf_timeouts[i].name &&
37143b3a8eb9SGleb Smirnoff 			    strcmp(pf_timeouts[i].name, $1); ++i)
37153b3a8eb9SGleb Smirnoff 				;	/* nothing */
37163b3a8eb9SGleb Smirnoff 			if (!pf_timeouts[i].name) {
37173b3a8eb9SGleb Smirnoff 				yyerror("illegal timeout name %s", $1);
37183b3a8eb9SGleb Smirnoff 				free($1);
37193b3a8eb9SGleb Smirnoff 				YYERROR;
37203b3a8eb9SGleb Smirnoff 			}
37213b3a8eb9SGleb Smirnoff 			if (strchr(pf_timeouts[i].name, '.') == NULL) {
37223b3a8eb9SGleb Smirnoff 				yyerror("illegal state timeout %s", $1);
37233b3a8eb9SGleb Smirnoff 				free($1);
37243b3a8eb9SGleb Smirnoff 				YYERROR;
37253b3a8eb9SGleb Smirnoff 			}
37263b3a8eb9SGleb Smirnoff 			free($1);
37273b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
37283b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
37293b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
37303b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_TIMEOUT;
37313b3a8eb9SGleb Smirnoff 			$$->data.timeout.number = pf_timeouts[i].timeout;
37323b3a8eb9SGleb Smirnoff 			$$->data.timeout.seconds = $2;
37333b3a8eb9SGleb Smirnoff 			$$->next = NULL;
37343b3a8eb9SGleb Smirnoff 			$$->tail = $$;
37353b3a8eb9SGleb Smirnoff 		}
37363b3a8eb9SGleb Smirnoff 		;
37373b3a8eb9SGleb Smirnoff 
37383b3a8eb9SGleb Smirnoff label		: LABEL STRING			{
37393b3a8eb9SGleb Smirnoff 			$$ = $2;
37403b3a8eb9SGleb Smirnoff 		}
37413b3a8eb9SGleb Smirnoff 		;
37423b3a8eb9SGleb Smirnoff 
37433b3a8eb9SGleb Smirnoff qname		: QUEUE STRING				{
37443b3a8eb9SGleb Smirnoff 			$$.qname = $2;
37453b3a8eb9SGleb Smirnoff 			$$.pqname = NULL;
37463b3a8eb9SGleb Smirnoff 		}
37473b3a8eb9SGleb Smirnoff 		| QUEUE '(' STRING ')'			{
37483b3a8eb9SGleb Smirnoff 			$$.qname = $3;
37493b3a8eb9SGleb Smirnoff 			$$.pqname = NULL;
37503b3a8eb9SGleb Smirnoff 		}
37513b3a8eb9SGleb Smirnoff 		| QUEUE '(' STRING comma STRING ')'	{
37523b3a8eb9SGleb Smirnoff 			$$.qname = $3;
37533b3a8eb9SGleb Smirnoff 			$$.pqname = $5;
37543b3a8eb9SGleb Smirnoff 		}
37553b3a8eb9SGleb Smirnoff 		;
37563b3a8eb9SGleb Smirnoff 
37573b3a8eb9SGleb Smirnoff no		: /* empty */			{ $$ = 0; }
37583b3a8eb9SGleb Smirnoff 		| NO				{ $$ = 1; }
37593b3a8eb9SGleb Smirnoff 		;
37603b3a8eb9SGleb Smirnoff 
37613b3a8eb9SGleb Smirnoff portstar	: numberstring			{
37623b3a8eb9SGleb Smirnoff 			if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) {
37633b3a8eb9SGleb Smirnoff 				free($1);
37643b3a8eb9SGleb Smirnoff 				YYERROR;
37653b3a8eb9SGleb Smirnoff 			}
37663b3a8eb9SGleb Smirnoff 			free($1);
37673b3a8eb9SGleb Smirnoff 		}
37683b3a8eb9SGleb Smirnoff 		;
37693b3a8eb9SGleb Smirnoff 
37703b3a8eb9SGleb Smirnoff redirspec	: host				{ $$ = $1; }
37713b3a8eb9SGleb Smirnoff 		| '{' optnl redir_host_list '}'	{ $$ = $3; }
37723b3a8eb9SGleb Smirnoff 		;
37733b3a8eb9SGleb Smirnoff 
37743b3a8eb9SGleb Smirnoff redir_host_list	: host optnl			{ $$ = $1; }
37753b3a8eb9SGleb Smirnoff 		| redir_host_list comma host optnl {
37763b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
37773b3a8eb9SGleb Smirnoff 			$1->tail = $3->tail;
37783b3a8eb9SGleb Smirnoff 			$$ = $1;
37793b3a8eb9SGleb Smirnoff 		}
37803b3a8eb9SGleb Smirnoff 		;
37813b3a8eb9SGleb Smirnoff 
37823b3a8eb9SGleb Smirnoff redirpool	: /* empty */			{ $$ = NULL; }
37833b3a8eb9SGleb Smirnoff 		| ARROW redirspec		{
37843b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
37853b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
37863b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
37873b3a8eb9SGleb Smirnoff 			$$->host = $2;
37883b3a8eb9SGleb Smirnoff 			$$->rport.a = $$->rport.b = $$->rport.t = 0;
37893b3a8eb9SGleb Smirnoff 		}
37903b3a8eb9SGleb Smirnoff 		| ARROW redirspec PORT portstar	{
37913b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
37923b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
37933b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
37943b3a8eb9SGleb Smirnoff 			$$->host = $2;
37953b3a8eb9SGleb Smirnoff 			$$->rport = $4;
37963b3a8eb9SGleb Smirnoff 		}
37973b3a8eb9SGleb Smirnoff 		;
37983b3a8eb9SGleb Smirnoff 
37993b3a8eb9SGleb Smirnoff hashkey		: /* empty */
38003b3a8eb9SGleb Smirnoff 		{
38013b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct pf_poolhashkey));
38023b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
38033b3a8eb9SGleb Smirnoff 				err(1, "hashkey: calloc");
38043b3a8eb9SGleb Smirnoff 			$$->key32[0] = arc4random();
38053b3a8eb9SGleb Smirnoff 			$$->key32[1] = arc4random();
38063b3a8eb9SGleb Smirnoff 			$$->key32[2] = arc4random();
38073b3a8eb9SGleb Smirnoff 			$$->key32[3] = arc4random();
38083b3a8eb9SGleb Smirnoff 		}
38093b3a8eb9SGleb Smirnoff 		| string
38103b3a8eb9SGleb Smirnoff 		{
38113b3a8eb9SGleb Smirnoff 			if (!strncmp($1, "0x", 2)) {
38123b3a8eb9SGleb Smirnoff 				if (strlen($1) != 34) {
38133b3a8eb9SGleb Smirnoff 					free($1);
38143b3a8eb9SGleb Smirnoff 					yyerror("hex key must be 128 bits "
38153b3a8eb9SGleb Smirnoff 						"(32 hex digits) long");
38163b3a8eb9SGleb Smirnoff 					YYERROR;
38173b3a8eb9SGleb Smirnoff 				}
38183b3a8eb9SGleb Smirnoff 				$$ = calloc(1, sizeof(struct pf_poolhashkey));
38193b3a8eb9SGleb Smirnoff 				if ($$ == NULL)
38203b3a8eb9SGleb Smirnoff 					err(1, "hashkey: calloc");
38213b3a8eb9SGleb Smirnoff 
38223b3a8eb9SGleb Smirnoff 				if (sscanf($1, "0x%8x%8x%8x%8x",
38233b3a8eb9SGleb Smirnoff 				    &$$->key32[0], &$$->key32[1],
38243b3a8eb9SGleb Smirnoff 				    &$$->key32[2], &$$->key32[3]) != 4) {
38253b3a8eb9SGleb Smirnoff 					free($$);
38263b3a8eb9SGleb Smirnoff 					free($1);
38273b3a8eb9SGleb Smirnoff 					yyerror("invalid hex key");
38283b3a8eb9SGleb Smirnoff 					YYERROR;
38293b3a8eb9SGleb Smirnoff 				}
38303b3a8eb9SGleb Smirnoff 			} else {
38313b3a8eb9SGleb Smirnoff 				MD5_CTX	context;
38323b3a8eb9SGleb Smirnoff 
38333b3a8eb9SGleb Smirnoff 				$$ = calloc(1, sizeof(struct pf_poolhashkey));
38343b3a8eb9SGleb Smirnoff 				if ($$ == NULL)
38353b3a8eb9SGleb Smirnoff 					err(1, "hashkey: calloc");
38363b3a8eb9SGleb Smirnoff 				MD5Init(&context);
38373b3a8eb9SGleb Smirnoff 				MD5Update(&context, (unsigned char *)$1,
38383b3a8eb9SGleb Smirnoff 				    strlen($1));
38393b3a8eb9SGleb Smirnoff 				MD5Final((unsigned char *)$$, &context);
38403b3a8eb9SGleb Smirnoff 				HTONL($$->key32[0]);
38413b3a8eb9SGleb Smirnoff 				HTONL($$->key32[1]);
38423b3a8eb9SGleb Smirnoff 				HTONL($$->key32[2]);
38433b3a8eb9SGleb Smirnoff 				HTONL($$->key32[3]);
38443b3a8eb9SGleb Smirnoff 			}
38453b3a8eb9SGleb Smirnoff 			free($1);
38463b3a8eb9SGleb Smirnoff 		}
38473b3a8eb9SGleb Smirnoff 		;
38483b3a8eb9SGleb Smirnoff 
38493b3a8eb9SGleb Smirnoff pool_opts	:	{ bzero(&pool_opts, sizeof pool_opts); }
38503b3a8eb9SGleb Smirnoff 		    pool_opts_l
38513b3a8eb9SGleb Smirnoff 			{ $$ = pool_opts; }
38523b3a8eb9SGleb Smirnoff 		| /* empty */	{
38533b3a8eb9SGleb Smirnoff 			bzero(&pool_opts, sizeof pool_opts);
38543b3a8eb9SGleb Smirnoff 			$$ = pool_opts;
38553b3a8eb9SGleb Smirnoff 		}
38563b3a8eb9SGleb Smirnoff 		;
38573b3a8eb9SGleb Smirnoff 
38583b3a8eb9SGleb Smirnoff pool_opts_l	: pool_opts_l pool_opt
38593b3a8eb9SGleb Smirnoff 		| pool_opt
38603b3a8eb9SGleb Smirnoff 		;
38613b3a8eb9SGleb Smirnoff 
38623b3a8eb9SGleb Smirnoff pool_opt	: BITMASK	{
38633b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
38643b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
38653b3a8eb9SGleb Smirnoff 				YYERROR;
38663b3a8eb9SGleb Smirnoff 			}
38673b3a8eb9SGleb Smirnoff 			pool_opts.type =  PF_POOL_BITMASK;
38683b3a8eb9SGleb Smirnoff 		}
38693b3a8eb9SGleb Smirnoff 		| RANDOM	{
38703b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
38713b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
38723b3a8eb9SGleb Smirnoff 				YYERROR;
38733b3a8eb9SGleb Smirnoff 			}
38743b3a8eb9SGleb Smirnoff 			pool_opts.type = PF_POOL_RANDOM;
38753b3a8eb9SGleb Smirnoff 		}
38763b3a8eb9SGleb Smirnoff 		| SOURCEHASH hashkey {
38773b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
38783b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
38793b3a8eb9SGleb Smirnoff 				YYERROR;
38803b3a8eb9SGleb Smirnoff 			}
38813b3a8eb9SGleb Smirnoff 			pool_opts.type = PF_POOL_SRCHASH;
38823b3a8eb9SGleb Smirnoff 			pool_opts.key = $2;
38833b3a8eb9SGleb Smirnoff 		}
38843b3a8eb9SGleb Smirnoff 		| ROUNDROBIN	{
38853b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
38863b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
38873b3a8eb9SGleb Smirnoff 				YYERROR;
38883b3a8eb9SGleb Smirnoff 			}
38893b3a8eb9SGleb Smirnoff 			pool_opts.type = PF_POOL_ROUNDROBIN;
38903b3a8eb9SGleb Smirnoff 		}
38913b3a8eb9SGleb Smirnoff 		| STATICPORT	{
38923b3a8eb9SGleb Smirnoff 			if (pool_opts.staticport) {
38933b3a8eb9SGleb Smirnoff 				yyerror("static-port cannot be redefined");
38943b3a8eb9SGleb Smirnoff 				YYERROR;
38953b3a8eb9SGleb Smirnoff 			}
38963b3a8eb9SGleb Smirnoff 			pool_opts.staticport = 1;
38973b3a8eb9SGleb Smirnoff 		}
38983b3a8eb9SGleb Smirnoff 		| STICKYADDRESS	{
38993b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & POM_STICKYADDRESS) {
39003b3a8eb9SGleb Smirnoff 				yyerror("sticky-address cannot be redefined");
39013b3a8eb9SGleb Smirnoff 				YYERROR;
39023b3a8eb9SGleb Smirnoff 			}
39033b3a8eb9SGleb Smirnoff 			pool_opts.marker |= POM_STICKYADDRESS;
39043b3a8eb9SGleb Smirnoff 			pool_opts.opts |= PF_POOL_STICKYADDR;
39053b3a8eb9SGleb Smirnoff 		}
39063b3a8eb9SGleb Smirnoff 		;
39073b3a8eb9SGleb Smirnoff 
39083b3a8eb9SGleb Smirnoff redirection	: /* empty */			{ $$ = NULL; }
39093b3a8eb9SGleb Smirnoff 		| ARROW host			{
39103b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
39113b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
39123b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
39133b3a8eb9SGleb Smirnoff 			$$->host = $2;
39143b3a8eb9SGleb Smirnoff 			$$->rport.a = $$->rport.b = $$->rport.t = 0;
39153b3a8eb9SGleb Smirnoff 		}
39163b3a8eb9SGleb Smirnoff 		| ARROW host PORT portstar	{
39173b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
39183b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
39193b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
39203b3a8eb9SGleb Smirnoff 			$$->host = $2;
39213b3a8eb9SGleb Smirnoff 			$$->rport = $4;
39223b3a8eb9SGleb Smirnoff 		}
39233b3a8eb9SGleb Smirnoff 		;
39243b3a8eb9SGleb Smirnoff 
39253b3a8eb9SGleb Smirnoff natpasslog	: /* empty */	{ $$.b1 = $$.b2 = 0; $$.w2 = 0; }
39263b3a8eb9SGleb Smirnoff 		| PASS		{ $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
39273b3a8eb9SGleb Smirnoff 		| PASS log	{ $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
39283b3a8eb9SGleb Smirnoff 		| log		{ $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
39293b3a8eb9SGleb Smirnoff 		;
39303b3a8eb9SGleb Smirnoff 
39313b3a8eb9SGleb Smirnoff nataction	: no NAT natpasslog {
39323b3a8eb9SGleb Smirnoff 			if ($1 && $3.b1) {
39333b3a8eb9SGleb Smirnoff 				yyerror("\"pass\" not valid with \"no\"");
39343b3a8eb9SGleb Smirnoff 				YYERROR;
39353b3a8eb9SGleb Smirnoff 			}
39363b3a8eb9SGleb Smirnoff 			if ($1)
39373b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NONAT;
39383b3a8eb9SGleb Smirnoff 			else
39393b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NAT;
39403b3a8eb9SGleb Smirnoff 			$$.b2 = $3.b1;
39413b3a8eb9SGleb Smirnoff 			$$.w = $3.b2;
39423b3a8eb9SGleb Smirnoff 			$$.w2 = $3.w2;
39433b3a8eb9SGleb Smirnoff 		}
39443b3a8eb9SGleb Smirnoff 		| no RDR natpasslog {
39453b3a8eb9SGleb Smirnoff 			if ($1 && $3.b1) {
39463b3a8eb9SGleb Smirnoff 				yyerror("\"pass\" not valid with \"no\"");
39473b3a8eb9SGleb Smirnoff 				YYERROR;
39483b3a8eb9SGleb Smirnoff 			}
39493b3a8eb9SGleb Smirnoff 			if ($1)
39503b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NORDR;
39513b3a8eb9SGleb Smirnoff 			else
39523b3a8eb9SGleb Smirnoff 				$$.b1 = PF_RDR;
39533b3a8eb9SGleb Smirnoff 			$$.b2 = $3.b1;
39543b3a8eb9SGleb Smirnoff 			$$.w = $3.b2;
39553b3a8eb9SGleb Smirnoff 			$$.w2 = $3.w2;
39563b3a8eb9SGleb Smirnoff 		}
39573b3a8eb9SGleb Smirnoff 		;
39583b3a8eb9SGleb Smirnoff 
39593b3a8eb9SGleb Smirnoff natrule		: nataction interface af proto fromto tag tagged rtable
39603b3a8eb9SGleb Smirnoff 		    redirpool pool_opts
39613b3a8eb9SGleb Smirnoff 		{
39623b3a8eb9SGleb Smirnoff 			struct pf_rule	r;
39633b3a8eb9SGleb Smirnoff 
39643b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT))
39653b3a8eb9SGleb Smirnoff 				YYERROR;
39663b3a8eb9SGleb Smirnoff 
39673b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
39683b3a8eb9SGleb Smirnoff 
39693b3a8eb9SGleb Smirnoff 			r.action = $1.b1;
39703b3a8eb9SGleb Smirnoff 			r.natpass = $1.b2;
39713b3a8eb9SGleb Smirnoff 			r.log = $1.w;
39723b3a8eb9SGleb Smirnoff 			r.logif = $1.w2;
39733b3a8eb9SGleb Smirnoff 			r.af = $3;
39743b3a8eb9SGleb Smirnoff 
39753b3a8eb9SGleb Smirnoff 			if (!r.af) {
39763b3a8eb9SGleb Smirnoff 				if ($5.src.host && $5.src.host->af &&
39773b3a8eb9SGleb Smirnoff 				    !$5.src.host->ifindex)
39783b3a8eb9SGleb Smirnoff 					r.af = $5.src.host->af;
39793b3a8eb9SGleb Smirnoff 				else if ($5.dst.host && $5.dst.host->af &&
39803b3a8eb9SGleb Smirnoff 				    !$5.dst.host->ifindex)
39813b3a8eb9SGleb Smirnoff 					r.af = $5.dst.host->af;
39823b3a8eb9SGleb Smirnoff 			}
39833b3a8eb9SGleb Smirnoff 
39843b3a8eb9SGleb Smirnoff 			if ($6 != NULL)
39853b3a8eb9SGleb Smirnoff 				if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
39863b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) {
39873b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
39883b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
39893b3a8eb9SGleb Smirnoff 					YYERROR;
39903b3a8eb9SGleb Smirnoff 				}
39913b3a8eb9SGleb Smirnoff 
39923b3a8eb9SGleb Smirnoff 			if ($7.name)
39933b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $7.name,
39943b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
39953b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
39963b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
39973b3a8eb9SGleb Smirnoff 					YYERROR;
39983b3a8eb9SGleb Smirnoff 				}
39993b3a8eb9SGleb Smirnoff 			r.match_tag_not = $7.neg;
40003b3a8eb9SGleb Smirnoff 			r.rtableid = $8;
40013b3a8eb9SGleb Smirnoff 
40023b3a8eb9SGleb Smirnoff 			if (r.action == PF_NONAT || r.action == PF_NORDR) {
40033b3a8eb9SGleb Smirnoff 				if ($9 != NULL) {
40043b3a8eb9SGleb Smirnoff 					yyerror("translation rule with 'no' "
40053b3a8eb9SGleb Smirnoff 					    "does not need '->'");
40063b3a8eb9SGleb Smirnoff 					YYERROR;
40073b3a8eb9SGleb Smirnoff 				}
40083b3a8eb9SGleb Smirnoff 			} else {
40093b3a8eb9SGleb Smirnoff 				if ($9 == NULL || $9->host == NULL) {
40103b3a8eb9SGleb Smirnoff 					yyerror("translation rule requires '-> "
40113b3a8eb9SGleb Smirnoff 					    "address'");
40123b3a8eb9SGleb Smirnoff 					YYERROR;
40133b3a8eb9SGleb Smirnoff 				}
40143b3a8eb9SGleb Smirnoff 				if (!r.af && ! $9->host->ifindex)
40153b3a8eb9SGleb Smirnoff 					r.af = $9->host->af;
40163b3a8eb9SGleb Smirnoff 
40173b3a8eb9SGleb Smirnoff 				remove_invalid_hosts(&$9->host, &r.af);
40183b3a8eb9SGleb Smirnoff 				if (invalid_redirect($9->host, r.af))
40193b3a8eb9SGleb Smirnoff 					YYERROR;
40203b3a8eb9SGleb Smirnoff 				if (check_netmask($9->host, r.af))
40213b3a8eb9SGleb Smirnoff 					YYERROR;
40223b3a8eb9SGleb Smirnoff 
40233b3a8eb9SGleb Smirnoff 				r.rpool.proxy_port[0] = ntohs($9->rport.a);
40243b3a8eb9SGleb Smirnoff 
40253b3a8eb9SGleb Smirnoff 				switch (r.action) {
40263b3a8eb9SGleb Smirnoff 				case PF_RDR:
40273b3a8eb9SGleb Smirnoff 					if (!$9->rport.b && $9->rport.t &&
40283b3a8eb9SGleb Smirnoff 					    $5.dst.port != NULL) {
40293b3a8eb9SGleb Smirnoff 						r.rpool.proxy_port[1] =
40303b3a8eb9SGleb Smirnoff 						    ntohs($9->rport.a) +
40313b3a8eb9SGleb Smirnoff 						    (ntohs(
40323b3a8eb9SGleb Smirnoff 						    $5.dst.port->port[1]) -
40333b3a8eb9SGleb Smirnoff 						    ntohs(
40343b3a8eb9SGleb Smirnoff 						    $5.dst.port->port[0]));
40353b3a8eb9SGleb Smirnoff 					} else
40363b3a8eb9SGleb Smirnoff 						r.rpool.proxy_port[1] =
40373b3a8eb9SGleb Smirnoff 						    ntohs($9->rport.b);
40383b3a8eb9SGleb Smirnoff 					break;
40393b3a8eb9SGleb Smirnoff 				case PF_NAT:
40403b3a8eb9SGleb Smirnoff 					r.rpool.proxy_port[1] =
40413b3a8eb9SGleb Smirnoff 					    ntohs($9->rport.b);
40423b3a8eb9SGleb Smirnoff 					if (!r.rpool.proxy_port[0] &&
40433b3a8eb9SGleb Smirnoff 					    !r.rpool.proxy_port[1]) {
40443b3a8eb9SGleb Smirnoff 						r.rpool.proxy_port[0] =
40453b3a8eb9SGleb Smirnoff 						    PF_NAT_PROXY_PORT_LOW;
40463b3a8eb9SGleb Smirnoff 						r.rpool.proxy_port[1] =
40473b3a8eb9SGleb Smirnoff 						    PF_NAT_PROXY_PORT_HIGH;
40483b3a8eb9SGleb Smirnoff 					} else if (!r.rpool.proxy_port[1])
40493b3a8eb9SGleb Smirnoff 						r.rpool.proxy_port[1] =
40503b3a8eb9SGleb Smirnoff 						    r.rpool.proxy_port[0];
40513b3a8eb9SGleb Smirnoff 					break;
40523b3a8eb9SGleb Smirnoff 				default:
40533b3a8eb9SGleb Smirnoff 					break;
40543b3a8eb9SGleb Smirnoff 				}
40553b3a8eb9SGleb Smirnoff 
40563b3a8eb9SGleb Smirnoff 				r.rpool.opts = $10.type;
40573b3a8eb9SGleb Smirnoff 				if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
40583b3a8eb9SGleb Smirnoff 				    PF_POOL_NONE && ($9->host->next != NULL ||
40593b3a8eb9SGleb Smirnoff 				    $9->host->addr.type == PF_ADDR_TABLE ||
40603b3a8eb9SGleb Smirnoff 				    DYNIF_MULTIADDR($9->host->addr)))
40613b3a8eb9SGleb Smirnoff 					r.rpool.opts = PF_POOL_ROUNDROBIN;
40623b3a8eb9SGleb Smirnoff 				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
40633b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
40643b3a8eb9SGleb Smirnoff 				    disallow_table($9->host, "tables are only "
40653b3a8eb9SGleb Smirnoff 				    "supported in round-robin redirection "
40663b3a8eb9SGleb Smirnoff 				    "pools"))
40673b3a8eb9SGleb Smirnoff 					YYERROR;
40683b3a8eb9SGleb Smirnoff 				if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
40693b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
40703b3a8eb9SGleb Smirnoff 				    disallow_alias($9->host, "interface (%s) "
40713b3a8eb9SGleb Smirnoff 				    "is only supported in round-robin "
40723b3a8eb9SGleb Smirnoff 				    "redirection pools"))
40733b3a8eb9SGleb Smirnoff 					YYERROR;
40743b3a8eb9SGleb Smirnoff 				if ($9->host->next != NULL) {
40753b3a8eb9SGleb Smirnoff 					if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
40763b3a8eb9SGleb Smirnoff 					    PF_POOL_ROUNDROBIN) {
40773b3a8eb9SGleb Smirnoff 						yyerror("only round-robin "
40783b3a8eb9SGleb Smirnoff 						    "valid for multiple "
40793b3a8eb9SGleb Smirnoff 						    "redirection addresses");
40803b3a8eb9SGleb Smirnoff 						YYERROR;
40813b3a8eb9SGleb Smirnoff 					}
40823b3a8eb9SGleb Smirnoff 				}
40833b3a8eb9SGleb Smirnoff 			}
40843b3a8eb9SGleb Smirnoff 
40853b3a8eb9SGleb Smirnoff 			if ($10.key != NULL)
40863b3a8eb9SGleb Smirnoff 				memcpy(&r.rpool.key, $10.key,
40873b3a8eb9SGleb Smirnoff 				    sizeof(struct pf_poolhashkey));
40883b3a8eb9SGleb Smirnoff 
40893b3a8eb9SGleb Smirnoff 			 if ($10.opts)
40903b3a8eb9SGleb Smirnoff 				r.rpool.opts |= $10.opts;
40913b3a8eb9SGleb Smirnoff 
40923b3a8eb9SGleb Smirnoff 			if ($10.staticport) {
40933b3a8eb9SGleb Smirnoff 				if (r.action != PF_NAT) {
40943b3a8eb9SGleb Smirnoff 					yyerror("the 'static-port' option is "
40953b3a8eb9SGleb Smirnoff 					    "only valid with nat rules");
40963b3a8eb9SGleb Smirnoff 					YYERROR;
40973b3a8eb9SGleb Smirnoff 				}
40983b3a8eb9SGleb Smirnoff 				if (r.rpool.proxy_port[0] !=
40993b3a8eb9SGleb Smirnoff 				    PF_NAT_PROXY_PORT_LOW &&
41003b3a8eb9SGleb Smirnoff 				    r.rpool.proxy_port[1] !=
41013b3a8eb9SGleb Smirnoff 				    PF_NAT_PROXY_PORT_HIGH) {
41023b3a8eb9SGleb Smirnoff 					yyerror("the 'static-port' option can't"
41033b3a8eb9SGleb Smirnoff 					    " be used when specifying a port"
41043b3a8eb9SGleb Smirnoff 					    " range");
41053b3a8eb9SGleb Smirnoff 					YYERROR;
41063b3a8eb9SGleb Smirnoff 				}
41073b3a8eb9SGleb Smirnoff 				r.rpool.proxy_port[0] = 0;
41083b3a8eb9SGleb Smirnoff 				r.rpool.proxy_port[1] = 0;
41093b3a8eb9SGleb Smirnoff 			}
41103b3a8eb9SGleb Smirnoff 
41113b3a8eb9SGleb Smirnoff 			expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
41123b3a8eb9SGleb Smirnoff 			    $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
41133b3a8eb9SGleb Smirnoff 			    $5.dst.port, 0, 0, 0, "");
41143b3a8eb9SGleb Smirnoff 			free($9);
41153b3a8eb9SGleb Smirnoff 		}
41163b3a8eb9SGleb Smirnoff 		;
41173b3a8eb9SGleb Smirnoff 
41183b3a8eb9SGleb Smirnoff binatrule	: no BINAT natpasslog interface af proto FROM host toipspec tag
41193b3a8eb9SGleb Smirnoff 		    tagged rtable redirection
41203b3a8eb9SGleb Smirnoff 		{
41213b3a8eb9SGleb Smirnoff 			struct pf_rule		binat;
41223b3a8eb9SGleb Smirnoff 			struct pf_pooladdr	*pa;
41233b3a8eb9SGleb Smirnoff 
41243b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT))
41253b3a8eb9SGleb Smirnoff 				YYERROR;
41263b3a8eb9SGleb Smirnoff 			if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
41273b3a8eb9SGleb Smirnoff 			    "permitted as a binat destination"))
41283b3a8eb9SGleb Smirnoff 				YYERROR;
41293b3a8eb9SGleb Smirnoff 
41303b3a8eb9SGleb Smirnoff 			memset(&binat, 0, sizeof(binat));
41313b3a8eb9SGleb Smirnoff 
41323b3a8eb9SGleb Smirnoff 			if ($1 && $3.b1) {
41333b3a8eb9SGleb Smirnoff 				yyerror("\"pass\" not valid with \"no\"");
41343b3a8eb9SGleb Smirnoff 				YYERROR;
41353b3a8eb9SGleb Smirnoff 			}
41363b3a8eb9SGleb Smirnoff 			if ($1)
41373b3a8eb9SGleb Smirnoff 				binat.action = PF_NOBINAT;
41383b3a8eb9SGleb Smirnoff 			else
41393b3a8eb9SGleb Smirnoff 				binat.action = PF_BINAT;
41403b3a8eb9SGleb Smirnoff 			binat.natpass = $3.b1;
41413b3a8eb9SGleb Smirnoff 			binat.log = $3.b2;
41423b3a8eb9SGleb Smirnoff 			binat.logif = $3.w2;
41433b3a8eb9SGleb Smirnoff 			binat.af = $5;
41443b3a8eb9SGleb Smirnoff 			if (!binat.af && $8 != NULL && $8->af)
41453b3a8eb9SGleb Smirnoff 				binat.af = $8->af;
41463b3a8eb9SGleb Smirnoff 			if (!binat.af && $9 != NULL && $9->af)
41473b3a8eb9SGleb Smirnoff 				binat.af = $9->af;
41483b3a8eb9SGleb Smirnoff 
41493b3a8eb9SGleb Smirnoff 			if (!binat.af && $13 != NULL && $13->host)
41503b3a8eb9SGleb Smirnoff 				binat.af = $13->host->af;
41513b3a8eb9SGleb Smirnoff 			if (!binat.af) {
41523b3a8eb9SGleb Smirnoff 				yyerror("address family (inet/inet6) "
41533b3a8eb9SGleb Smirnoff 				    "undefined");
41543b3a8eb9SGleb Smirnoff 				YYERROR;
41553b3a8eb9SGleb Smirnoff 			}
41563b3a8eb9SGleb Smirnoff 
41573b3a8eb9SGleb Smirnoff 			if ($4 != NULL) {
41583b3a8eb9SGleb Smirnoff 				memcpy(binat.ifname, $4->ifname,
41593b3a8eb9SGleb Smirnoff 				    sizeof(binat.ifname));
41603b3a8eb9SGleb Smirnoff 				binat.ifnot = $4->not;
41613b3a8eb9SGleb Smirnoff 				free($4);
41623b3a8eb9SGleb Smirnoff 			}
41633b3a8eb9SGleb Smirnoff 
41643b3a8eb9SGleb Smirnoff 			if ($10 != NULL)
41653b3a8eb9SGleb Smirnoff 				if (strlcpy(binat.tagname, $10,
41663b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
41673b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
41683b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
41693b3a8eb9SGleb Smirnoff 					YYERROR;
41703b3a8eb9SGleb Smirnoff 				}
41713b3a8eb9SGleb Smirnoff 			if ($11.name)
41723b3a8eb9SGleb Smirnoff 				if (strlcpy(binat.match_tagname, $11.name,
41733b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
41743b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
41753b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
41763b3a8eb9SGleb Smirnoff 					YYERROR;
41773b3a8eb9SGleb Smirnoff 				}
41783b3a8eb9SGleb Smirnoff 			binat.match_tag_not = $11.neg;
41793b3a8eb9SGleb Smirnoff 			binat.rtableid = $12;
41803b3a8eb9SGleb Smirnoff 
41813b3a8eb9SGleb Smirnoff 			if ($6 != NULL) {
41823b3a8eb9SGleb Smirnoff 				binat.proto = $6->proto;
41833b3a8eb9SGleb Smirnoff 				free($6);
41843b3a8eb9SGleb Smirnoff 			}
41853b3a8eb9SGleb Smirnoff 
41863b3a8eb9SGleb Smirnoff 			if ($8 != NULL && disallow_table($8, "invalid use of "
41873b3a8eb9SGleb Smirnoff 			    "table <%s> as the source address of a binat rule"))
41883b3a8eb9SGleb Smirnoff 				YYERROR;
41893b3a8eb9SGleb Smirnoff 			if ($8 != NULL && disallow_alias($8, "invalid use of "
41903b3a8eb9SGleb Smirnoff 			    "interface (%s) as the source address of a binat "
41913b3a8eb9SGleb Smirnoff 			    "rule"))
41923b3a8eb9SGleb Smirnoff 				YYERROR;
41933b3a8eb9SGleb Smirnoff 			if ($13 != NULL && $13->host != NULL && disallow_table(
41943b3a8eb9SGleb Smirnoff 			    $13->host, "invalid use of table <%s> as the "
41953b3a8eb9SGleb Smirnoff 			    "redirect address of a binat rule"))
41963b3a8eb9SGleb Smirnoff 				YYERROR;
41973b3a8eb9SGleb Smirnoff 			if ($13 != NULL && $13->host != NULL && disallow_alias(
41983b3a8eb9SGleb Smirnoff 			    $13->host, "invalid use of interface (%s) as the "
41993b3a8eb9SGleb Smirnoff 			    "redirect address of a binat rule"))
42003b3a8eb9SGleb Smirnoff 				YYERROR;
42013b3a8eb9SGleb Smirnoff 
42023b3a8eb9SGleb Smirnoff 			if ($8 != NULL) {
42033b3a8eb9SGleb Smirnoff 				if ($8->next) {
42043b3a8eb9SGleb Smirnoff 					yyerror("multiple binat ip addresses");
42053b3a8eb9SGleb Smirnoff 					YYERROR;
42063b3a8eb9SGleb Smirnoff 				}
42073b3a8eb9SGleb Smirnoff 				if ($8->addr.type == PF_ADDR_DYNIFTL)
42083b3a8eb9SGleb Smirnoff 					$8->af = binat.af;
42093b3a8eb9SGleb Smirnoff 				if ($8->af != binat.af) {
42103b3a8eb9SGleb Smirnoff 					yyerror("binat ip versions must match");
42113b3a8eb9SGleb Smirnoff 					YYERROR;
42123b3a8eb9SGleb Smirnoff 				}
42133b3a8eb9SGleb Smirnoff 				if (check_netmask($8, binat.af))
42143b3a8eb9SGleb Smirnoff 					YYERROR;
42153b3a8eb9SGleb Smirnoff 				memcpy(&binat.src.addr, &$8->addr,
42163b3a8eb9SGleb Smirnoff 				    sizeof(binat.src.addr));
42173b3a8eb9SGleb Smirnoff 				free($8);
42183b3a8eb9SGleb Smirnoff 			}
42193b3a8eb9SGleb Smirnoff 			if ($9 != NULL) {
42203b3a8eb9SGleb Smirnoff 				if ($9->next) {
42213b3a8eb9SGleb Smirnoff 					yyerror("multiple binat ip addresses");
42223b3a8eb9SGleb Smirnoff 					YYERROR;
42233b3a8eb9SGleb Smirnoff 				}
42243b3a8eb9SGleb Smirnoff 				if ($9->af != binat.af && $9->af) {
42253b3a8eb9SGleb Smirnoff 					yyerror("binat ip versions must match");
42263b3a8eb9SGleb Smirnoff 					YYERROR;
42273b3a8eb9SGleb Smirnoff 				}
42283b3a8eb9SGleb Smirnoff 				if (check_netmask($9, binat.af))
42293b3a8eb9SGleb Smirnoff 					YYERROR;
42303b3a8eb9SGleb Smirnoff 				memcpy(&binat.dst.addr, &$9->addr,
42313b3a8eb9SGleb Smirnoff 				    sizeof(binat.dst.addr));
42323b3a8eb9SGleb Smirnoff 				binat.dst.neg = $9->not;
42333b3a8eb9SGleb Smirnoff 				free($9);
42343b3a8eb9SGleb Smirnoff 			}
42353b3a8eb9SGleb Smirnoff 
42363b3a8eb9SGleb Smirnoff 			if (binat.action == PF_NOBINAT) {
42373b3a8eb9SGleb Smirnoff 				if ($13 != NULL) {
42383b3a8eb9SGleb Smirnoff 					yyerror("'no binat' rule does not need"
42393b3a8eb9SGleb Smirnoff 					    " '->'");
42403b3a8eb9SGleb Smirnoff 					YYERROR;
42413b3a8eb9SGleb Smirnoff 				}
42423b3a8eb9SGleb Smirnoff 			} else {
42433b3a8eb9SGleb Smirnoff 				if ($13 == NULL || $13->host == NULL) {
42443b3a8eb9SGleb Smirnoff 					yyerror("'binat' rule requires"
42453b3a8eb9SGleb Smirnoff 					    " '-> address'");
42463b3a8eb9SGleb Smirnoff 					YYERROR;
42473b3a8eb9SGleb Smirnoff 				}
42483b3a8eb9SGleb Smirnoff 
42493b3a8eb9SGleb Smirnoff 				remove_invalid_hosts(&$13->host, &binat.af);
42503b3a8eb9SGleb Smirnoff 				if (invalid_redirect($13->host, binat.af))
42513b3a8eb9SGleb Smirnoff 					YYERROR;
42523b3a8eb9SGleb Smirnoff 				if ($13->host->next != NULL) {
42533b3a8eb9SGleb Smirnoff 					yyerror("binat rule must redirect to "
42543b3a8eb9SGleb Smirnoff 					    "a single address");
42553b3a8eb9SGleb Smirnoff 					YYERROR;
42563b3a8eb9SGleb Smirnoff 				}
42573b3a8eb9SGleb Smirnoff 				if (check_netmask($13->host, binat.af))
42583b3a8eb9SGleb Smirnoff 					YYERROR;
42593b3a8eb9SGleb Smirnoff 
42603b3a8eb9SGleb Smirnoff 				if (!PF_AZERO(&binat.src.addr.v.a.mask,
42613b3a8eb9SGleb Smirnoff 				    binat.af) &&
42623b3a8eb9SGleb Smirnoff 				    !PF_AEQ(&binat.src.addr.v.a.mask,
42633b3a8eb9SGleb Smirnoff 				    &$13->host->addr.v.a.mask, binat.af)) {
42643b3a8eb9SGleb Smirnoff 					yyerror("'binat' source mask and "
42653b3a8eb9SGleb Smirnoff 					    "redirect mask must be the same");
42663b3a8eb9SGleb Smirnoff 					YYERROR;
42673b3a8eb9SGleb Smirnoff 				}
42683b3a8eb9SGleb Smirnoff 
42693b3a8eb9SGleb Smirnoff 				TAILQ_INIT(&binat.rpool.list);
42703b3a8eb9SGleb Smirnoff 				pa = calloc(1, sizeof(struct pf_pooladdr));
42713b3a8eb9SGleb Smirnoff 				if (pa == NULL)
42723b3a8eb9SGleb Smirnoff 					err(1, "binat: calloc");
42733b3a8eb9SGleb Smirnoff 				pa->addr = $13->host->addr;
42743b3a8eb9SGleb Smirnoff 				pa->ifname[0] = 0;
42753b3a8eb9SGleb Smirnoff 				TAILQ_INSERT_TAIL(&binat.rpool.list,
42763b3a8eb9SGleb Smirnoff 				    pa, entries);
42773b3a8eb9SGleb Smirnoff 
42783b3a8eb9SGleb Smirnoff 				free($13);
42793b3a8eb9SGleb Smirnoff 			}
42803b3a8eb9SGleb Smirnoff 
42813b3a8eb9SGleb Smirnoff 			pfctl_add_rule(pf, &binat, "");
42823b3a8eb9SGleb Smirnoff 		}
42833b3a8eb9SGleb Smirnoff 		;
42843b3a8eb9SGleb Smirnoff 
42853b3a8eb9SGleb Smirnoff tag		: /* empty */		{ $$ = NULL; }
42863b3a8eb9SGleb Smirnoff 		| TAG STRING		{ $$ = $2; }
42873b3a8eb9SGleb Smirnoff 		;
42883b3a8eb9SGleb Smirnoff 
42893b3a8eb9SGleb Smirnoff tagged		: /* empty */		{ $$.neg = 0; $$.name = NULL; }
42903b3a8eb9SGleb Smirnoff 		| not TAGGED string	{ $$.neg = $1; $$.name = $3; }
42913b3a8eb9SGleb Smirnoff 		;
42923b3a8eb9SGleb Smirnoff 
42933b3a8eb9SGleb Smirnoff rtable		: /* empty */		{ $$ = -1; }
42943b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER		{
42953b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
42963b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
42973b3a8eb9SGleb Smirnoff 				YYERROR;
42983b3a8eb9SGleb Smirnoff 			}
42993b3a8eb9SGleb Smirnoff 			$$ = $2;
43003b3a8eb9SGleb Smirnoff 		}
43013b3a8eb9SGleb Smirnoff 		;
43023b3a8eb9SGleb Smirnoff 
43033b3a8eb9SGleb Smirnoff route_host	: STRING			{
43043b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
43053b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
43063b3a8eb9SGleb Smirnoff 				err(1, "route_host: calloc");
43073b3a8eb9SGleb Smirnoff 			$$->ifname = $1;
43083b3a8eb9SGleb Smirnoff 			set_ipmask($$, 128);
43093b3a8eb9SGleb Smirnoff 			$$->next = NULL;
43103b3a8eb9SGleb Smirnoff 			$$->tail = $$;
43113b3a8eb9SGleb Smirnoff 		}
43123b3a8eb9SGleb Smirnoff 		| '(' STRING host ')'		{
43133b3a8eb9SGleb Smirnoff 			$$ = $3;
43143b3a8eb9SGleb Smirnoff 			$$->ifname = $2;
43153b3a8eb9SGleb Smirnoff 		}
43163b3a8eb9SGleb Smirnoff 		;
43173b3a8eb9SGleb Smirnoff 
43183b3a8eb9SGleb Smirnoff route_host_list	: route_host optnl			{ $$ = $1; }
43193b3a8eb9SGleb Smirnoff 		| route_host_list comma route_host optnl {
43203b3a8eb9SGleb Smirnoff 			if ($1->af == 0)
43213b3a8eb9SGleb Smirnoff 				$1->af = $3->af;
43223b3a8eb9SGleb Smirnoff 			if ($1->af != $3->af) {
43233b3a8eb9SGleb Smirnoff 				yyerror("all pool addresses must be in the "
43243b3a8eb9SGleb Smirnoff 				    "same address family");
43253b3a8eb9SGleb Smirnoff 				YYERROR;
43263b3a8eb9SGleb Smirnoff 			}
43273b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
43283b3a8eb9SGleb Smirnoff 			$1->tail = $3->tail;
43293b3a8eb9SGleb Smirnoff 			$$ = $1;
43303b3a8eb9SGleb Smirnoff 		}
43313b3a8eb9SGleb Smirnoff 		;
43323b3a8eb9SGleb Smirnoff 
43333b3a8eb9SGleb Smirnoff routespec	: route_host			{ $$ = $1; }
43343b3a8eb9SGleb Smirnoff 		| '{' optnl route_host_list '}'	{ $$ = $3; }
43353b3a8eb9SGleb Smirnoff 		;
43363b3a8eb9SGleb Smirnoff 
43373b3a8eb9SGleb Smirnoff route		: /* empty */			{
43383b3a8eb9SGleb Smirnoff 			$$.host = NULL;
43393b3a8eb9SGleb Smirnoff 			$$.rt = 0;
43403b3a8eb9SGleb Smirnoff 			$$.pool_opts = 0;
43413b3a8eb9SGleb Smirnoff 		}
43423b3a8eb9SGleb Smirnoff 		| FASTROUTE {
43433b3a8eb9SGleb Smirnoff 			$$.host = NULL;
43443b3a8eb9SGleb Smirnoff 			$$.rt = PF_FASTROUTE;
43453b3a8eb9SGleb Smirnoff 			$$.pool_opts = 0;
43463b3a8eb9SGleb Smirnoff 		}
43473b3a8eb9SGleb Smirnoff 		| ROUTETO routespec pool_opts {
43483b3a8eb9SGleb Smirnoff 			$$.host = $2;
43493b3a8eb9SGleb Smirnoff 			$$.rt = PF_ROUTETO;
43503b3a8eb9SGleb Smirnoff 			$$.pool_opts = $3.type | $3.opts;
43513b3a8eb9SGleb Smirnoff 			if ($3.key != NULL)
43523b3a8eb9SGleb Smirnoff 				$$.key = $3.key;
43533b3a8eb9SGleb Smirnoff 		}
43543b3a8eb9SGleb Smirnoff 		| REPLYTO routespec pool_opts {
43553b3a8eb9SGleb Smirnoff 			$$.host = $2;
43563b3a8eb9SGleb Smirnoff 			$$.rt = PF_REPLYTO;
43573b3a8eb9SGleb Smirnoff 			$$.pool_opts = $3.type | $3.opts;
43583b3a8eb9SGleb Smirnoff 			if ($3.key != NULL)
43593b3a8eb9SGleb Smirnoff 				$$.key = $3.key;
43603b3a8eb9SGleb Smirnoff 		}
43613b3a8eb9SGleb Smirnoff 		| DUPTO routespec pool_opts {
43623b3a8eb9SGleb Smirnoff 			$$.host = $2;
43633b3a8eb9SGleb Smirnoff 			$$.rt = PF_DUPTO;
43643b3a8eb9SGleb Smirnoff 			$$.pool_opts = $3.type | $3.opts;
43653b3a8eb9SGleb Smirnoff 			if ($3.key != NULL)
43663b3a8eb9SGleb Smirnoff 				$$.key = $3.key;
43673b3a8eb9SGleb Smirnoff 		}
43683b3a8eb9SGleb Smirnoff 		;
43693b3a8eb9SGleb Smirnoff 
43703b3a8eb9SGleb Smirnoff timeout_spec	: STRING NUMBER
43713b3a8eb9SGleb Smirnoff 		{
43723b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
43733b3a8eb9SGleb Smirnoff 				free($1);
43743b3a8eb9SGleb Smirnoff 				YYERROR;
43753b3a8eb9SGleb Smirnoff 			}
43763b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
43773b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
43783b3a8eb9SGleb Smirnoff 				YYERROR;
43793b3a8eb9SGleb Smirnoff 			}
43803b3a8eb9SGleb Smirnoff 			if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
43813b3a8eb9SGleb Smirnoff 				yyerror("unknown timeout %s", $1);
43823b3a8eb9SGleb Smirnoff 				free($1);
43833b3a8eb9SGleb Smirnoff 				YYERROR;
43843b3a8eb9SGleb Smirnoff 			}
43853b3a8eb9SGleb Smirnoff 			free($1);
43863b3a8eb9SGleb Smirnoff 		}
43873b3a8eb9SGleb Smirnoff 		;
43883b3a8eb9SGleb Smirnoff 
43893b3a8eb9SGleb Smirnoff timeout_list	: timeout_list comma timeout_spec optnl
43903b3a8eb9SGleb Smirnoff 		| timeout_spec optnl
43913b3a8eb9SGleb Smirnoff 		;
43923b3a8eb9SGleb Smirnoff 
43933b3a8eb9SGleb Smirnoff limit_spec	: STRING NUMBER
43943b3a8eb9SGleb Smirnoff 		{
43953b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
43963b3a8eb9SGleb Smirnoff 				free($1);
43973b3a8eb9SGleb Smirnoff 				YYERROR;
43983b3a8eb9SGleb Smirnoff 			}
43993b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
44003b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
44013b3a8eb9SGleb Smirnoff 				YYERROR;
44023b3a8eb9SGleb Smirnoff 			}
44033b3a8eb9SGleb Smirnoff 			if (pfctl_set_limit(pf, $1, $2) != 0) {
44043b3a8eb9SGleb Smirnoff 				yyerror("unable to set limit %s %u", $1, $2);
44053b3a8eb9SGleb Smirnoff 				free($1);
44063b3a8eb9SGleb Smirnoff 				YYERROR;
44073b3a8eb9SGleb Smirnoff 			}
44083b3a8eb9SGleb Smirnoff 			free($1);
44093b3a8eb9SGleb Smirnoff 		}
44103b3a8eb9SGleb Smirnoff 		;
44113b3a8eb9SGleb Smirnoff 
44123b3a8eb9SGleb Smirnoff limit_list	: limit_list comma limit_spec optnl
44133b3a8eb9SGleb Smirnoff 		| limit_spec optnl
44143b3a8eb9SGleb Smirnoff 		;
44153b3a8eb9SGleb Smirnoff 
44163b3a8eb9SGleb Smirnoff comma		: ','
44173b3a8eb9SGleb Smirnoff 		| /* empty */
44183b3a8eb9SGleb Smirnoff 		;
44193b3a8eb9SGleb Smirnoff 
44203b3a8eb9SGleb Smirnoff yesno		: NO			{ $$ = 0; }
44213b3a8eb9SGleb Smirnoff 		| STRING		{
44223b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "yes"))
44233b3a8eb9SGleb Smirnoff 				$$ = 1;
44243b3a8eb9SGleb Smirnoff 			else {
44253b3a8eb9SGleb Smirnoff 				yyerror("invalid value '%s', expected 'yes' "
44263b3a8eb9SGleb Smirnoff 				    "or 'no'", $1);
44273b3a8eb9SGleb Smirnoff 				free($1);
44283b3a8eb9SGleb Smirnoff 				YYERROR;
44293b3a8eb9SGleb Smirnoff 			}
44303b3a8eb9SGleb Smirnoff 			free($1);
44313b3a8eb9SGleb Smirnoff 		}
44323b3a8eb9SGleb Smirnoff 		;
44333b3a8eb9SGleb Smirnoff 
44343b3a8eb9SGleb Smirnoff unaryop		: '='		{ $$ = PF_OP_EQ; }
44353b3a8eb9SGleb Smirnoff 		| '!' '='	{ $$ = PF_OP_NE; }
44363b3a8eb9SGleb Smirnoff 		| '<' '='	{ $$ = PF_OP_LE; }
44373b3a8eb9SGleb Smirnoff 		| '<'		{ $$ = PF_OP_LT; }
44383b3a8eb9SGleb Smirnoff 		| '>' '='	{ $$ = PF_OP_GE; }
44393b3a8eb9SGleb Smirnoff 		| '>'		{ $$ = PF_OP_GT; }
44403b3a8eb9SGleb Smirnoff 		;
44413b3a8eb9SGleb Smirnoff 
44423b3a8eb9SGleb Smirnoff %%
44433b3a8eb9SGleb Smirnoff 
44443b3a8eb9SGleb Smirnoff int
44453b3a8eb9SGleb Smirnoff yyerror(const char *fmt, ...)
44463b3a8eb9SGleb Smirnoff {
44473b3a8eb9SGleb Smirnoff 	va_list		 ap;
44483b3a8eb9SGleb Smirnoff 
44493b3a8eb9SGleb Smirnoff 	file->errors++;
44503b3a8eb9SGleb Smirnoff 	va_start(ap, fmt);
44513b3a8eb9SGleb Smirnoff 	fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
44523b3a8eb9SGleb Smirnoff 	vfprintf(stderr, fmt, ap);
44533b3a8eb9SGleb Smirnoff 	fprintf(stderr, "\n");
44543b3a8eb9SGleb Smirnoff 	va_end(ap);
44553b3a8eb9SGleb Smirnoff 	return (0);
44563b3a8eb9SGleb Smirnoff }
44573b3a8eb9SGleb Smirnoff 
44583b3a8eb9SGleb Smirnoff int
44593b3a8eb9SGleb Smirnoff disallow_table(struct node_host *h, const char *fmt)
44603b3a8eb9SGleb Smirnoff {
44613b3a8eb9SGleb Smirnoff 	for (; h != NULL; h = h->next)
44623b3a8eb9SGleb Smirnoff 		if (h->addr.type == PF_ADDR_TABLE) {
44633b3a8eb9SGleb Smirnoff 			yyerror(fmt, h->addr.v.tblname);
44643b3a8eb9SGleb Smirnoff 			return (1);
44653b3a8eb9SGleb Smirnoff 		}
44663b3a8eb9SGleb Smirnoff 	return (0);
44673b3a8eb9SGleb Smirnoff }
44683b3a8eb9SGleb Smirnoff 
44693b3a8eb9SGleb Smirnoff int
44703b3a8eb9SGleb Smirnoff disallow_urpf_failed(struct node_host *h, const char *fmt)
44713b3a8eb9SGleb Smirnoff {
44723b3a8eb9SGleb Smirnoff 	for (; h != NULL; h = h->next)
44733b3a8eb9SGleb Smirnoff 		if (h->addr.type == PF_ADDR_URPFFAILED) {
44743b3a8eb9SGleb Smirnoff 			yyerror(fmt);
44753b3a8eb9SGleb Smirnoff 			return (1);
44763b3a8eb9SGleb Smirnoff 		}
44773b3a8eb9SGleb Smirnoff 	return (0);
44783b3a8eb9SGleb Smirnoff }
44793b3a8eb9SGleb Smirnoff 
44803b3a8eb9SGleb Smirnoff int
44813b3a8eb9SGleb Smirnoff disallow_alias(struct node_host *h, const char *fmt)
44823b3a8eb9SGleb Smirnoff {
44833b3a8eb9SGleb Smirnoff 	for (; h != NULL; h = h->next)
44843b3a8eb9SGleb Smirnoff 		if (DYNIF_MULTIADDR(h->addr)) {
44853b3a8eb9SGleb Smirnoff 			yyerror(fmt, h->addr.v.tblname);
44863b3a8eb9SGleb Smirnoff 			return (1);
44873b3a8eb9SGleb Smirnoff 		}
44883b3a8eb9SGleb Smirnoff 	return (0);
44893b3a8eb9SGleb Smirnoff }
44903b3a8eb9SGleb Smirnoff 
44913b3a8eb9SGleb Smirnoff int
44923b3a8eb9SGleb Smirnoff rule_consistent(struct pf_rule *r, int anchor_call)
44933b3a8eb9SGleb Smirnoff {
44943b3a8eb9SGleb Smirnoff 	int	problems = 0;
44953b3a8eb9SGleb Smirnoff 
44963b3a8eb9SGleb Smirnoff 	switch (r->action) {
44973b3a8eb9SGleb Smirnoff 	case PF_PASS:
44983b3a8eb9SGleb Smirnoff 	case PF_DROP:
44993b3a8eb9SGleb Smirnoff 	case PF_SCRUB:
45003b3a8eb9SGleb Smirnoff 	case PF_NOSCRUB:
45013b3a8eb9SGleb Smirnoff 		problems = filter_consistent(r, anchor_call);
45023b3a8eb9SGleb Smirnoff 		break;
45033b3a8eb9SGleb Smirnoff 	case PF_NAT:
45043b3a8eb9SGleb Smirnoff 	case PF_NONAT:
45053b3a8eb9SGleb Smirnoff 		problems = nat_consistent(r);
45063b3a8eb9SGleb Smirnoff 		break;
45073b3a8eb9SGleb Smirnoff 	case PF_RDR:
45083b3a8eb9SGleb Smirnoff 	case PF_NORDR:
45093b3a8eb9SGleb Smirnoff 		problems = rdr_consistent(r);
45103b3a8eb9SGleb Smirnoff 		break;
45113b3a8eb9SGleb Smirnoff 	case PF_BINAT:
45123b3a8eb9SGleb Smirnoff 	case PF_NOBINAT:
45133b3a8eb9SGleb Smirnoff 	default:
45143b3a8eb9SGleb Smirnoff 		break;
45153b3a8eb9SGleb Smirnoff 	}
45163b3a8eb9SGleb Smirnoff 	return (problems);
45173b3a8eb9SGleb Smirnoff }
45183b3a8eb9SGleb Smirnoff 
45193b3a8eb9SGleb Smirnoff int
45203b3a8eb9SGleb Smirnoff filter_consistent(struct pf_rule *r, int anchor_call)
45213b3a8eb9SGleb Smirnoff {
45223b3a8eb9SGleb Smirnoff 	int	problems = 0;
45233b3a8eb9SGleb Smirnoff 
45243b3a8eb9SGleb Smirnoff 	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
45253b3a8eb9SGleb Smirnoff 	    (r->src.port_op || r->dst.port_op)) {
45263b3a8eb9SGleb Smirnoff 		yyerror("port only applies to tcp/udp");
45273b3a8eb9SGleb Smirnoff 		problems++;
45283b3a8eb9SGleb Smirnoff 	}
45293b3a8eb9SGleb Smirnoff 	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
45303b3a8eb9SGleb Smirnoff 	    (r->type || r->code)) {
45313b3a8eb9SGleb Smirnoff 		yyerror("icmp-type/code only applies to icmp");
45323b3a8eb9SGleb Smirnoff 		problems++;
45333b3a8eb9SGleb Smirnoff 	}
45343b3a8eb9SGleb Smirnoff 	if (!r->af && (r->type || r->code)) {
45353b3a8eb9SGleb Smirnoff 		yyerror("must indicate address family with icmp-type/code");
45363b3a8eb9SGleb Smirnoff 		problems++;
45373b3a8eb9SGleb Smirnoff 	}
45383b3a8eb9SGleb Smirnoff 	if (r->overload_tblname[0] &&
45393b3a8eb9SGleb Smirnoff 	    r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
45403b3a8eb9SGleb Smirnoff 		yyerror("'overload' requires 'max-src-conn' "
45413b3a8eb9SGleb Smirnoff 		    "or 'max-src-conn-rate'");
45423b3a8eb9SGleb Smirnoff 		problems++;
45433b3a8eb9SGleb Smirnoff 	}
45443b3a8eb9SGleb Smirnoff 	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
45453b3a8eb9SGleb Smirnoff 	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
45463b3a8eb9SGleb Smirnoff 		yyerror("proto %s doesn't match address family %s",
45473b3a8eb9SGleb Smirnoff 		    r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
45483b3a8eb9SGleb Smirnoff 		    r->af == AF_INET ? "inet" : "inet6");
45493b3a8eb9SGleb Smirnoff 		problems++;
45503b3a8eb9SGleb Smirnoff 	}
45513b3a8eb9SGleb Smirnoff 	if (r->allow_opts && r->action != PF_PASS) {
45523b3a8eb9SGleb Smirnoff 		yyerror("allow-opts can only be specified for pass rules");
45533b3a8eb9SGleb Smirnoff 		problems++;
45543b3a8eb9SGleb Smirnoff 	}
45553b3a8eb9SGleb Smirnoff 	if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
45563b3a8eb9SGleb Smirnoff 	    r->dst.port_op || r->flagset || r->type || r->code)) {
45573b3a8eb9SGleb Smirnoff 		yyerror("fragments can be filtered only on IP header fields");
45583b3a8eb9SGleb Smirnoff 		problems++;
45593b3a8eb9SGleb Smirnoff 	}
45603b3a8eb9SGleb Smirnoff 	if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
45613b3a8eb9SGleb Smirnoff 		yyerror("return-rst can only be applied to TCP rules");
45623b3a8eb9SGleb Smirnoff 		problems++;
45633b3a8eb9SGleb Smirnoff 	}
45643b3a8eb9SGleb Smirnoff 	if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
45653b3a8eb9SGleb Smirnoff 		yyerror("max-src-nodes requires 'source-track rule'");
45663b3a8eb9SGleb Smirnoff 		problems++;
45673b3a8eb9SGleb Smirnoff 	}
45683b3a8eb9SGleb Smirnoff 	if (r->action == PF_DROP && r->keep_state) {
45693b3a8eb9SGleb Smirnoff 		yyerror("keep state on block rules doesn't make sense");
45703b3a8eb9SGleb Smirnoff 		problems++;
45713b3a8eb9SGleb Smirnoff 	}
45723b3a8eb9SGleb Smirnoff 	if (r->rule_flag & PFRULE_STATESLOPPY &&
45733b3a8eb9SGleb Smirnoff 	    (r->keep_state == PF_STATE_MODULATE ||
45743b3a8eb9SGleb Smirnoff 	    r->keep_state == PF_STATE_SYNPROXY)) {
45753b3a8eb9SGleb Smirnoff 		yyerror("sloppy state matching cannot be used with "
45763b3a8eb9SGleb Smirnoff 		    "synproxy state or modulate state");
45773b3a8eb9SGleb Smirnoff 		problems++;
45783b3a8eb9SGleb Smirnoff 	}
45793b3a8eb9SGleb Smirnoff 	return (-problems);
45803b3a8eb9SGleb Smirnoff }
45813b3a8eb9SGleb Smirnoff 
45823b3a8eb9SGleb Smirnoff int
45833b3a8eb9SGleb Smirnoff nat_consistent(struct pf_rule *r)
45843b3a8eb9SGleb Smirnoff {
45853b3a8eb9SGleb Smirnoff 	return (0);	/* yeah! */
45863b3a8eb9SGleb Smirnoff }
45873b3a8eb9SGleb Smirnoff 
45883b3a8eb9SGleb Smirnoff int
45893b3a8eb9SGleb Smirnoff rdr_consistent(struct pf_rule *r)
45903b3a8eb9SGleb Smirnoff {
45913b3a8eb9SGleb Smirnoff 	int			 problems = 0;
45923b3a8eb9SGleb Smirnoff 
45933b3a8eb9SGleb Smirnoff 	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
45943b3a8eb9SGleb Smirnoff 		if (r->src.port_op) {
45953b3a8eb9SGleb Smirnoff 			yyerror("src port only applies to tcp/udp");
45963b3a8eb9SGleb Smirnoff 			problems++;
45973b3a8eb9SGleb Smirnoff 		}
45983b3a8eb9SGleb Smirnoff 		if (r->dst.port_op) {
45993b3a8eb9SGleb Smirnoff 			yyerror("dst port only applies to tcp/udp");
46003b3a8eb9SGleb Smirnoff 			problems++;
46013b3a8eb9SGleb Smirnoff 		}
46023b3a8eb9SGleb Smirnoff 		if (r->rpool.proxy_port[0]) {
46033b3a8eb9SGleb Smirnoff 			yyerror("rpool port only applies to tcp/udp");
46043b3a8eb9SGleb Smirnoff 			problems++;
46053b3a8eb9SGleb Smirnoff 		}
46063b3a8eb9SGleb Smirnoff 	}
46073b3a8eb9SGleb Smirnoff 	if (r->dst.port_op &&
46083b3a8eb9SGleb Smirnoff 	    r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
46093b3a8eb9SGleb Smirnoff 		yyerror("invalid port operator for rdr destination port");
46103b3a8eb9SGleb Smirnoff 		problems++;
46113b3a8eb9SGleb Smirnoff 	}
46123b3a8eb9SGleb Smirnoff 	return (-problems);
46133b3a8eb9SGleb Smirnoff }
46143b3a8eb9SGleb Smirnoff 
46153b3a8eb9SGleb Smirnoff int
46163b3a8eb9SGleb Smirnoff process_tabledef(char *name, struct table_opts *opts)
46173b3a8eb9SGleb Smirnoff {
46183b3a8eb9SGleb Smirnoff 	struct pfr_buffer	 ab;
46193b3a8eb9SGleb Smirnoff 	struct node_tinit	*ti;
46203b3a8eb9SGleb Smirnoff 
46213b3a8eb9SGleb Smirnoff 	bzero(&ab, sizeof(ab));
46223b3a8eb9SGleb Smirnoff 	ab.pfrb_type = PFRB_ADDRS;
46233b3a8eb9SGleb Smirnoff 	SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
46243b3a8eb9SGleb Smirnoff 		if (ti->file)
46253b3a8eb9SGleb Smirnoff 			if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
46263b3a8eb9SGleb Smirnoff 				if (errno)
46273b3a8eb9SGleb Smirnoff 					yyerror("cannot load \"%s\": %s",
46283b3a8eb9SGleb Smirnoff 					    ti->file, strerror(errno));
46293b3a8eb9SGleb Smirnoff 				else
46303b3a8eb9SGleb Smirnoff 					yyerror("file \"%s\" contains bad data",
46313b3a8eb9SGleb Smirnoff 					    ti->file);
46323b3a8eb9SGleb Smirnoff 				goto _error;
46333b3a8eb9SGleb Smirnoff 			}
46343b3a8eb9SGleb Smirnoff 		if (ti->host)
46353b3a8eb9SGleb Smirnoff 			if (append_addr_host(&ab, ti->host, 0, 0)) {
46363b3a8eb9SGleb Smirnoff 				yyerror("cannot create address buffer: %s",
46373b3a8eb9SGleb Smirnoff 				    strerror(errno));
46383b3a8eb9SGleb Smirnoff 				goto _error;
46393b3a8eb9SGleb Smirnoff 			}
46403b3a8eb9SGleb Smirnoff 	}
46413b3a8eb9SGleb Smirnoff 	if (pf->opts & PF_OPT_VERBOSE)
46423b3a8eb9SGleb Smirnoff 		print_tabledef(name, opts->flags, opts->init_addr,
46433b3a8eb9SGleb Smirnoff 		    &opts->init_nodes);
46443b3a8eb9SGleb Smirnoff 	if (!(pf->opts & PF_OPT_NOACTION) &&
46453b3a8eb9SGleb Smirnoff 	    pfctl_define_table(name, opts->flags, opts->init_addr,
46463b3a8eb9SGleb Smirnoff 	    pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
46473b3a8eb9SGleb Smirnoff 		yyerror("cannot define table %s: %s", name,
46483b3a8eb9SGleb Smirnoff 		    pfr_strerror(errno));
46493b3a8eb9SGleb Smirnoff 		goto _error;
46503b3a8eb9SGleb Smirnoff 	}
46513b3a8eb9SGleb Smirnoff 	pf->tdirty = 1;
46523b3a8eb9SGleb Smirnoff 	pfr_buf_clear(&ab);
46533b3a8eb9SGleb Smirnoff 	return (0);
46543b3a8eb9SGleb Smirnoff _error:
46553b3a8eb9SGleb Smirnoff 	pfr_buf_clear(&ab);
46563b3a8eb9SGleb Smirnoff 	return (-1);
46573b3a8eb9SGleb Smirnoff }
46583b3a8eb9SGleb Smirnoff 
46593b3a8eb9SGleb Smirnoff struct keywords {
46603b3a8eb9SGleb Smirnoff 	const char	*k_name;
46613b3a8eb9SGleb Smirnoff 	int		 k_val;
46623b3a8eb9SGleb Smirnoff };
46633b3a8eb9SGleb Smirnoff 
46643b3a8eb9SGleb Smirnoff /* macro gore, but you should've seen the prior indentation nightmare... */
46653b3a8eb9SGleb Smirnoff 
46663b3a8eb9SGleb Smirnoff #define FREE_LIST(T,r) \
46673b3a8eb9SGleb Smirnoff 	do { \
46683b3a8eb9SGleb Smirnoff 		T *p, *node = r; \
46693b3a8eb9SGleb Smirnoff 		while (node != NULL) { \
46703b3a8eb9SGleb Smirnoff 			p = node; \
46713b3a8eb9SGleb Smirnoff 			node = node->next; \
46723b3a8eb9SGleb Smirnoff 			free(p); \
46733b3a8eb9SGleb Smirnoff 		} \
46743b3a8eb9SGleb Smirnoff 	} while (0)
46753b3a8eb9SGleb Smirnoff 
46763b3a8eb9SGleb Smirnoff #define LOOP_THROUGH(T,n,r,C) \
46773b3a8eb9SGleb Smirnoff 	do { \
46783b3a8eb9SGleb Smirnoff 		T *n; \
46793b3a8eb9SGleb Smirnoff 		if (r == NULL) { \
46803b3a8eb9SGleb Smirnoff 			r = calloc(1, sizeof(T)); \
46813b3a8eb9SGleb Smirnoff 			if (r == NULL) \
46823b3a8eb9SGleb Smirnoff 				err(1, "LOOP: calloc"); \
46833b3a8eb9SGleb Smirnoff 			r->next = NULL; \
46843b3a8eb9SGleb Smirnoff 		} \
46853b3a8eb9SGleb Smirnoff 		n = r; \
46863b3a8eb9SGleb Smirnoff 		while (n != NULL) { \
46873b3a8eb9SGleb Smirnoff 			do { \
46883b3a8eb9SGleb Smirnoff 				C; \
46893b3a8eb9SGleb Smirnoff 			} while (0); \
46903b3a8eb9SGleb Smirnoff 			n = n->next; \
46913b3a8eb9SGleb Smirnoff 		} \
46923b3a8eb9SGleb Smirnoff 	} while (0)
46933b3a8eb9SGleb Smirnoff 
46943b3a8eb9SGleb Smirnoff void
46953b3a8eb9SGleb Smirnoff expand_label_str(char *label, size_t len, const char *srch, const char *repl)
46963b3a8eb9SGleb Smirnoff {
46973b3a8eb9SGleb Smirnoff 	char *tmp;
46983b3a8eb9SGleb Smirnoff 	char *p, *q;
46993b3a8eb9SGleb Smirnoff 
47003b3a8eb9SGleb Smirnoff 	if ((tmp = calloc(1, len)) == NULL)
47013b3a8eb9SGleb Smirnoff 		err(1, "expand_label_str: calloc");
47023b3a8eb9SGleb Smirnoff 	p = q = label;
47033b3a8eb9SGleb Smirnoff 	while ((q = strstr(p, srch)) != NULL) {
47043b3a8eb9SGleb Smirnoff 		*q = '\0';
47053b3a8eb9SGleb Smirnoff 		if ((strlcat(tmp, p, len) >= len) ||
47063b3a8eb9SGleb Smirnoff 		    (strlcat(tmp, repl, len) >= len))
47073b3a8eb9SGleb Smirnoff 			errx(1, "expand_label: label too long");
47083b3a8eb9SGleb Smirnoff 		q += strlen(srch);
47093b3a8eb9SGleb Smirnoff 		p = q;
47103b3a8eb9SGleb Smirnoff 	}
47113b3a8eb9SGleb Smirnoff 	if (strlcat(tmp, p, len) >= len)
47123b3a8eb9SGleb Smirnoff 		errx(1, "expand_label: label too long");
47133b3a8eb9SGleb Smirnoff 	strlcpy(label, tmp, len);	/* always fits */
47143b3a8eb9SGleb Smirnoff 	free(tmp);
47153b3a8eb9SGleb Smirnoff }
47163b3a8eb9SGleb Smirnoff 
47173b3a8eb9SGleb Smirnoff void
47183b3a8eb9SGleb Smirnoff expand_label_if(const char *name, char *label, size_t len, const char *ifname)
47193b3a8eb9SGleb Smirnoff {
47203b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
47213b3a8eb9SGleb Smirnoff 		if (!*ifname)
47223b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, "any");
47233b3a8eb9SGleb Smirnoff 		else
47243b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, ifname);
47253b3a8eb9SGleb Smirnoff 	}
47263b3a8eb9SGleb Smirnoff }
47273b3a8eb9SGleb Smirnoff 
47283b3a8eb9SGleb Smirnoff void
47293b3a8eb9SGleb Smirnoff expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
47303b3a8eb9SGleb Smirnoff     struct node_host *h)
47313b3a8eb9SGleb Smirnoff {
47323b3a8eb9SGleb Smirnoff 	char tmp[64], tmp_not[66];
47333b3a8eb9SGleb Smirnoff 
47343b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
47353b3a8eb9SGleb Smirnoff 		switch (h->addr.type) {
47363b3a8eb9SGleb Smirnoff 		case PF_ADDR_DYNIFTL:
47373b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
47383b3a8eb9SGleb Smirnoff 			break;
47393b3a8eb9SGleb Smirnoff 		case PF_ADDR_TABLE:
47403b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
47413b3a8eb9SGleb Smirnoff 			break;
47423b3a8eb9SGleb Smirnoff 		case PF_ADDR_NOROUTE:
47433b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "no-route");
47443b3a8eb9SGleb Smirnoff 			break;
47453b3a8eb9SGleb Smirnoff 		case PF_ADDR_URPFFAILED:
47463b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "urpf-failed");
47473b3a8eb9SGleb Smirnoff 			break;
47483b3a8eb9SGleb Smirnoff 		case PF_ADDR_ADDRMASK:
47493b3a8eb9SGleb Smirnoff 			if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
47503b3a8eb9SGleb Smirnoff 			    PF_AZERO(&h->addr.v.a.mask, af)))
47513b3a8eb9SGleb Smirnoff 				snprintf(tmp, sizeof(tmp), "any");
47523b3a8eb9SGleb Smirnoff 			else {
47533b3a8eb9SGleb Smirnoff 				char	a[48];
47543b3a8eb9SGleb Smirnoff 				int	bits;
47553b3a8eb9SGleb Smirnoff 
47563b3a8eb9SGleb Smirnoff 				if (inet_ntop(af, &h->addr.v.a.addr, a,
47573b3a8eb9SGleb Smirnoff 				    sizeof(a)) == NULL)
47583b3a8eb9SGleb Smirnoff 					snprintf(tmp, sizeof(tmp), "?");
47593b3a8eb9SGleb Smirnoff 				else {
47603b3a8eb9SGleb Smirnoff 					bits = unmask(&h->addr.v.a.mask, af);
47613b3a8eb9SGleb Smirnoff 					if ((af == AF_INET && bits < 32) ||
47623b3a8eb9SGleb Smirnoff 					    (af == AF_INET6 && bits < 128))
47633b3a8eb9SGleb Smirnoff 						snprintf(tmp, sizeof(tmp),
47643b3a8eb9SGleb Smirnoff 						    "%s/%d", a, bits);
47653b3a8eb9SGleb Smirnoff 					else
47663b3a8eb9SGleb Smirnoff 						snprintf(tmp, sizeof(tmp),
47673b3a8eb9SGleb Smirnoff 						    "%s", a);
47683b3a8eb9SGleb Smirnoff 				}
47693b3a8eb9SGleb Smirnoff 			}
47703b3a8eb9SGleb Smirnoff 			break;
47713b3a8eb9SGleb Smirnoff 		default:
47723b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "?");
47733b3a8eb9SGleb Smirnoff 			break;
47743b3a8eb9SGleb Smirnoff 		}
47753b3a8eb9SGleb Smirnoff 
47763b3a8eb9SGleb Smirnoff 		if (h->not) {
47773b3a8eb9SGleb Smirnoff 			snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
47783b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, tmp_not);
47793b3a8eb9SGleb Smirnoff 		} else
47803b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, tmp);
47813b3a8eb9SGleb Smirnoff 	}
47823b3a8eb9SGleb Smirnoff }
47833b3a8eb9SGleb Smirnoff 
47843b3a8eb9SGleb Smirnoff void
47853b3a8eb9SGleb Smirnoff expand_label_port(const char *name, char *label, size_t len,
47863b3a8eb9SGleb Smirnoff     struct node_port *port)
47873b3a8eb9SGleb Smirnoff {
47883b3a8eb9SGleb Smirnoff 	char	 a1[6], a2[6], op[13] = "";
47893b3a8eb9SGleb Smirnoff 
47903b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
47913b3a8eb9SGleb Smirnoff 		snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
47923b3a8eb9SGleb Smirnoff 		snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
47933b3a8eb9SGleb Smirnoff 		if (!port->op)
47943b3a8eb9SGleb Smirnoff 			;
47953b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_IRG)
47963b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "%s><%s", a1, a2);
47973b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_XRG)
47983b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "%s<>%s", a1, a2);
47993b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_EQ)
48003b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "%s", a1);
48013b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_NE)
48023b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "!=%s", a1);
48033b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_LT)
48043b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "<%s", a1);
48053b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_LE)
48063b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "<=%s", a1);
48073b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_GT)
48083b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), ">%s", a1);
48093b3a8eb9SGleb Smirnoff 		else if (port->op == PF_OP_GE)
48103b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), ">=%s", a1);
48113b3a8eb9SGleb Smirnoff 		expand_label_str(label, len, name, op);
48123b3a8eb9SGleb Smirnoff 	}
48133b3a8eb9SGleb Smirnoff }
48143b3a8eb9SGleb Smirnoff 
48153b3a8eb9SGleb Smirnoff void
48163b3a8eb9SGleb Smirnoff expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
48173b3a8eb9SGleb Smirnoff {
48183b3a8eb9SGleb Smirnoff 	struct protoent *pe;
48193b3a8eb9SGleb Smirnoff 	char n[4];
48203b3a8eb9SGleb Smirnoff 
48213b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
48223b3a8eb9SGleb Smirnoff 		pe = getprotobynumber(proto);
48233b3a8eb9SGleb Smirnoff 		if (pe != NULL)
48243b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, pe->p_name);
48253b3a8eb9SGleb Smirnoff 		else {
48263b3a8eb9SGleb Smirnoff 			snprintf(n, sizeof(n), "%u", proto);
48273b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, n);
48283b3a8eb9SGleb Smirnoff 		}
48293b3a8eb9SGleb Smirnoff 	}
48303b3a8eb9SGleb Smirnoff }
48313b3a8eb9SGleb Smirnoff 
48323b3a8eb9SGleb Smirnoff void
48333b3a8eb9SGleb Smirnoff expand_label_nr(const char *name, char *label, size_t len)
48343b3a8eb9SGleb Smirnoff {
48353b3a8eb9SGleb Smirnoff 	char n[11];
48363b3a8eb9SGleb Smirnoff 
48373b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
48383b3a8eb9SGleb Smirnoff 		snprintf(n, sizeof(n), "%u", pf->anchor->match);
48393b3a8eb9SGleb Smirnoff 		expand_label_str(label, len, name, n);
48403b3a8eb9SGleb Smirnoff 	}
48413b3a8eb9SGleb Smirnoff }
48423b3a8eb9SGleb Smirnoff 
48433b3a8eb9SGleb Smirnoff void
48443b3a8eb9SGleb Smirnoff expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
48453b3a8eb9SGleb Smirnoff     struct node_host *src_host, struct node_port *src_port,
48463b3a8eb9SGleb Smirnoff     struct node_host *dst_host, struct node_port *dst_port,
48473b3a8eb9SGleb Smirnoff     u_int8_t proto)
48483b3a8eb9SGleb Smirnoff {
48493b3a8eb9SGleb Smirnoff 	expand_label_if("$if", label, len, ifname);
48503b3a8eb9SGleb Smirnoff 	expand_label_addr("$srcaddr", label, len, af, src_host);
48513b3a8eb9SGleb Smirnoff 	expand_label_addr("$dstaddr", label, len, af, dst_host);
48523b3a8eb9SGleb Smirnoff 	expand_label_port("$srcport", label, len, src_port);
48533b3a8eb9SGleb Smirnoff 	expand_label_port("$dstport", label, len, dst_port);
48543b3a8eb9SGleb Smirnoff 	expand_label_proto("$proto", label, len, proto);
48553b3a8eb9SGleb Smirnoff 	expand_label_nr("$nr", label, len);
48563b3a8eb9SGleb Smirnoff }
48573b3a8eb9SGleb Smirnoff 
48583b3a8eb9SGleb Smirnoff int
48593b3a8eb9SGleb Smirnoff expand_altq(struct pf_altq *a, struct node_if *interfaces,
48603b3a8eb9SGleb Smirnoff     struct node_queue *nqueues, struct node_queue_bw bwspec,
48613b3a8eb9SGleb Smirnoff     struct node_queue_opt *opts)
48623b3a8eb9SGleb Smirnoff {
48633b3a8eb9SGleb Smirnoff 	struct pf_altq		 pa, pb;
48643b3a8eb9SGleb Smirnoff 	char			 qname[PF_QNAME_SIZE];
48653b3a8eb9SGleb Smirnoff 	struct node_queue	*n;
48663b3a8eb9SGleb Smirnoff 	struct node_queue_bw	 bw;
48673b3a8eb9SGleb Smirnoff 	int			 errs = 0;
48683b3a8eb9SGleb Smirnoff 
48693b3a8eb9SGleb Smirnoff 	if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
48703b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_if, interfaces);
48710a70aaf8SLuiz Otavio O Souza 		if (nqueues)
48723b3a8eb9SGleb Smirnoff 			FREE_LIST(struct node_queue, nqueues);
48733b3a8eb9SGleb Smirnoff 		return (0);
48743b3a8eb9SGleb Smirnoff 	}
48753b3a8eb9SGleb Smirnoff 
48763b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
48773b3a8eb9SGleb Smirnoff 		memcpy(&pa, a, sizeof(struct pf_altq));
48783b3a8eb9SGleb Smirnoff 		if (strlcpy(pa.ifname, interface->ifname,
48793b3a8eb9SGleb Smirnoff 		    sizeof(pa.ifname)) >= sizeof(pa.ifname))
48803b3a8eb9SGleb Smirnoff 			errx(1, "expand_altq: strlcpy");
48813b3a8eb9SGleb Smirnoff 
48823b3a8eb9SGleb Smirnoff 		if (interface->not) {
48833b3a8eb9SGleb Smirnoff 			yyerror("altq on ! <interface> is not supported");
48843b3a8eb9SGleb Smirnoff 			errs++;
48853b3a8eb9SGleb Smirnoff 		} else {
48863b3a8eb9SGleb Smirnoff 			if (eval_pfaltq(pf, &pa, &bwspec, opts))
48873b3a8eb9SGleb Smirnoff 				errs++;
48883b3a8eb9SGleb Smirnoff 			else
48893b3a8eb9SGleb Smirnoff 				if (pfctl_add_altq(pf, &pa))
48903b3a8eb9SGleb Smirnoff 					errs++;
48913b3a8eb9SGleb Smirnoff 
48923b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE) {
48933b3a8eb9SGleb Smirnoff 				print_altq(&pf->paltq->altq, 0,
48943b3a8eb9SGleb Smirnoff 				    &bwspec, opts);
48953b3a8eb9SGleb Smirnoff 				if (nqueues && nqueues->tail) {
48963b3a8eb9SGleb Smirnoff 					printf("queue { ");
48973b3a8eb9SGleb Smirnoff 					LOOP_THROUGH(struct node_queue, queue,
48983b3a8eb9SGleb Smirnoff 					    nqueues,
48993b3a8eb9SGleb Smirnoff 						printf("%s ",
49003b3a8eb9SGleb Smirnoff 						    queue->queue);
49013b3a8eb9SGleb Smirnoff 					);
49023b3a8eb9SGleb Smirnoff 					printf("}");
49033b3a8eb9SGleb Smirnoff 				}
49043b3a8eb9SGleb Smirnoff 				printf("\n");
49053b3a8eb9SGleb Smirnoff 			}
49063b3a8eb9SGleb Smirnoff 
49073b3a8eb9SGleb Smirnoff 			if (pa.scheduler == ALTQT_CBQ ||
49083b3a8eb9SGleb Smirnoff 			    pa.scheduler == ALTQT_HFSC) {
49093b3a8eb9SGleb Smirnoff 				/* now create a root queue */
49103b3a8eb9SGleb Smirnoff 				memset(&pb, 0, sizeof(struct pf_altq));
49113b3a8eb9SGleb Smirnoff 				if (strlcpy(qname, "root_", sizeof(qname)) >=
49123b3a8eb9SGleb Smirnoff 				    sizeof(qname))
49133b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
49143b3a8eb9SGleb Smirnoff 				if (strlcat(qname, interface->ifname,
49153b3a8eb9SGleb Smirnoff 				    sizeof(qname)) >= sizeof(qname))
49163b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcat");
49173b3a8eb9SGleb Smirnoff 				if (strlcpy(pb.qname, qname,
49183b3a8eb9SGleb Smirnoff 				    sizeof(pb.qname)) >= sizeof(pb.qname))
49193b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
49203b3a8eb9SGleb Smirnoff 				if (strlcpy(pb.ifname, interface->ifname,
49213b3a8eb9SGleb Smirnoff 				    sizeof(pb.ifname)) >= sizeof(pb.ifname))
49223b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
49233b3a8eb9SGleb Smirnoff 				pb.qlimit = pa.qlimit;
49243b3a8eb9SGleb Smirnoff 				pb.scheduler = pa.scheduler;
49253b3a8eb9SGleb Smirnoff 				bw.bw_absolute = pa.ifbandwidth;
49263b3a8eb9SGleb Smirnoff 				bw.bw_percent = 0;
49273b3a8eb9SGleb Smirnoff 				if (eval_pfqueue(pf, &pb, &bw, opts))
49283b3a8eb9SGleb Smirnoff 					errs++;
49293b3a8eb9SGleb Smirnoff 				else
49303b3a8eb9SGleb Smirnoff 					if (pfctl_add_altq(pf, &pb))
49313b3a8eb9SGleb Smirnoff 						errs++;
49323b3a8eb9SGleb Smirnoff 			}
49333b3a8eb9SGleb Smirnoff 
49343b3a8eb9SGleb Smirnoff 			LOOP_THROUGH(struct node_queue, queue, nqueues,
49353b3a8eb9SGleb Smirnoff 				n = calloc(1, sizeof(struct node_queue));
49363b3a8eb9SGleb Smirnoff 				if (n == NULL)
49373b3a8eb9SGleb Smirnoff 					err(1, "expand_altq: calloc");
49383b3a8eb9SGleb Smirnoff 				if (pa.scheduler == ALTQT_CBQ ||
49393b3a8eb9SGleb Smirnoff 				    pa.scheduler == ALTQT_HFSC)
49403b3a8eb9SGleb Smirnoff 					if (strlcpy(n->parent, qname,
49413b3a8eb9SGleb Smirnoff 					    sizeof(n->parent)) >=
49423b3a8eb9SGleb Smirnoff 					    sizeof(n->parent))
49433b3a8eb9SGleb Smirnoff 						errx(1, "expand_altq: strlcpy");
49443b3a8eb9SGleb Smirnoff 				if (strlcpy(n->queue, queue->queue,
49453b3a8eb9SGleb Smirnoff 				    sizeof(n->queue)) >= sizeof(n->queue))
49463b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
49473b3a8eb9SGleb Smirnoff 				if (strlcpy(n->ifname, interface->ifname,
49483b3a8eb9SGleb Smirnoff 				    sizeof(n->ifname)) >= sizeof(n->ifname))
49493b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
49503b3a8eb9SGleb Smirnoff 				n->scheduler = pa.scheduler;
49513b3a8eb9SGleb Smirnoff 				n->next = NULL;
49523b3a8eb9SGleb Smirnoff 				n->tail = n;
49533b3a8eb9SGleb Smirnoff 				if (queues == NULL)
49543b3a8eb9SGleb Smirnoff 					queues = n;
49553b3a8eb9SGleb Smirnoff 				else {
49563b3a8eb9SGleb Smirnoff 					queues->tail->next = n;
49573b3a8eb9SGleb Smirnoff 					queues->tail = n;
49583b3a8eb9SGleb Smirnoff 				}
49593b3a8eb9SGleb Smirnoff 			);
49603b3a8eb9SGleb Smirnoff 		}
49613b3a8eb9SGleb Smirnoff 	);
49623b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
49630a70aaf8SLuiz Otavio O Souza 	if (nqueues)
49643b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_queue, nqueues);
49653b3a8eb9SGleb Smirnoff 
49663b3a8eb9SGleb Smirnoff 	return (errs);
49673b3a8eb9SGleb Smirnoff }
49683b3a8eb9SGleb Smirnoff 
49693b3a8eb9SGleb Smirnoff int
49703b3a8eb9SGleb Smirnoff expand_queue(struct pf_altq *a, struct node_if *interfaces,
49713b3a8eb9SGleb Smirnoff     struct node_queue *nqueues, struct node_queue_bw bwspec,
49723b3a8eb9SGleb Smirnoff     struct node_queue_opt *opts)
49733b3a8eb9SGleb Smirnoff {
49743b3a8eb9SGleb Smirnoff 	struct node_queue	*n, *nq;
49753b3a8eb9SGleb Smirnoff 	struct pf_altq		 pa;
49763b3a8eb9SGleb Smirnoff 	u_int8_t		 found = 0;
49773b3a8eb9SGleb Smirnoff 	u_int8_t		 errs = 0;
49783b3a8eb9SGleb Smirnoff 
49793b3a8eb9SGleb Smirnoff 	if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
49803b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_queue, nqueues);
49813b3a8eb9SGleb Smirnoff 		return (0);
49823b3a8eb9SGleb Smirnoff 	}
49833b3a8eb9SGleb Smirnoff 
49843b3a8eb9SGleb Smirnoff 	if (queues == NULL) {
49853b3a8eb9SGleb Smirnoff 		yyerror("queue %s has no parent", a->qname);
49863b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_queue, nqueues);
49873b3a8eb9SGleb Smirnoff 		return (1);
49883b3a8eb9SGleb Smirnoff 	}
49893b3a8eb9SGleb Smirnoff 
49903b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
49913b3a8eb9SGleb Smirnoff 		LOOP_THROUGH(struct node_queue, tqueue, queues,
49923b3a8eb9SGleb Smirnoff 			if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
49933b3a8eb9SGleb Smirnoff 			    (interface->ifname[0] == 0 ||
49943b3a8eb9SGleb Smirnoff 			    (!interface->not && !strncmp(interface->ifname,
49953b3a8eb9SGleb Smirnoff 			    tqueue->ifname, IFNAMSIZ)) ||
49963b3a8eb9SGleb Smirnoff 			    (interface->not && strncmp(interface->ifname,
49973b3a8eb9SGleb Smirnoff 			    tqueue->ifname, IFNAMSIZ)))) {
49983b3a8eb9SGleb Smirnoff 				/* found ourself in queues */
49993b3a8eb9SGleb Smirnoff 				found++;
50003b3a8eb9SGleb Smirnoff 
50013b3a8eb9SGleb Smirnoff 				memcpy(&pa, a, sizeof(struct pf_altq));
50023b3a8eb9SGleb Smirnoff 
50033b3a8eb9SGleb Smirnoff 				if (pa.scheduler != ALTQT_NONE &&
50043b3a8eb9SGleb Smirnoff 				    pa.scheduler != tqueue->scheduler) {
50053b3a8eb9SGleb Smirnoff 					yyerror("exactly one scheduler type "
50063b3a8eb9SGleb Smirnoff 					    "per interface allowed");
50073b3a8eb9SGleb Smirnoff 					return (1);
50083b3a8eb9SGleb Smirnoff 				}
50093b3a8eb9SGleb Smirnoff 				pa.scheduler = tqueue->scheduler;
50103b3a8eb9SGleb Smirnoff 
50113b3a8eb9SGleb Smirnoff 				/* scheduler dependent error checking */
50123b3a8eb9SGleb Smirnoff 				switch (pa.scheduler) {
50133b3a8eb9SGleb Smirnoff 				case ALTQT_PRIQ:
50143b3a8eb9SGleb Smirnoff 					if (nqueues != NULL) {
50153b3a8eb9SGleb Smirnoff 						yyerror("priq queues cannot "
50163b3a8eb9SGleb Smirnoff 						    "have child queues");
50173b3a8eb9SGleb Smirnoff 						return (1);
50183b3a8eb9SGleb Smirnoff 					}
50193b3a8eb9SGleb Smirnoff 					if (bwspec.bw_absolute > 0 ||
50203b3a8eb9SGleb Smirnoff 					    bwspec.bw_percent < 100) {
50213b3a8eb9SGleb Smirnoff 						yyerror("priq doesn't take "
50223b3a8eb9SGleb Smirnoff 						    "bandwidth");
50233b3a8eb9SGleb Smirnoff 						return (1);
50243b3a8eb9SGleb Smirnoff 					}
50253b3a8eb9SGleb Smirnoff 					break;
50263b3a8eb9SGleb Smirnoff 				default:
50273b3a8eb9SGleb Smirnoff 					break;
50283b3a8eb9SGleb Smirnoff 				}
50293b3a8eb9SGleb Smirnoff 
50303b3a8eb9SGleb Smirnoff 				if (strlcpy(pa.ifname, tqueue->ifname,
50313b3a8eb9SGleb Smirnoff 				    sizeof(pa.ifname)) >= sizeof(pa.ifname))
50323b3a8eb9SGleb Smirnoff 					errx(1, "expand_queue: strlcpy");
50333b3a8eb9SGleb Smirnoff 				if (strlcpy(pa.parent, tqueue->parent,
50343b3a8eb9SGleb Smirnoff 				    sizeof(pa.parent)) >= sizeof(pa.parent))
50353b3a8eb9SGleb Smirnoff 					errx(1, "expand_queue: strlcpy");
50363b3a8eb9SGleb Smirnoff 
50373b3a8eb9SGleb Smirnoff 				if (eval_pfqueue(pf, &pa, &bwspec, opts))
50383b3a8eb9SGleb Smirnoff 					errs++;
50393b3a8eb9SGleb Smirnoff 				else
50403b3a8eb9SGleb Smirnoff 					if (pfctl_add_altq(pf, &pa))
50413b3a8eb9SGleb Smirnoff 						errs++;
50423b3a8eb9SGleb Smirnoff 
50433b3a8eb9SGleb Smirnoff 				for (nq = nqueues; nq != NULL; nq = nq->next) {
50443b3a8eb9SGleb Smirnoff 					if (!strcmp(a->qname, nq->queue)) {
50453b3a8eb9SGleb Smirnoff 						yyerror("queue cannot have "
50463b3a8eb9SGleb Smirnoff 						    "itself as child");
50473b3a8eb9SGleb Smirnoff 						errs++;
50483b3a8eb9SGleb Smirnoff 						continue;
50493b3a8eb9SGleb Smirnoff 					}
50503b3a8eb9SGleb Smirnoff 					n = calloc(1,
50513b3a8eb9SGleb Smirnoff 					    sizeof(struct node_queue));
50523b3a8eb9SGleb Smirnoff 					if (n == NULL)
50533b3a8eb9SGleb Smirnoff 						err(1, "expand_queue: calloc");
50543b3a8eb9SGleb Smirnoff 					if (strlcpy(n->parent, a->qname,
50553b3a8eb9SGleb Smirnoff 					    sizeof(n->parent)) >=
50563b3a8eb9SGleb Smirnoff 					    sizeof(n->parent))
50573b3a8eb9SGleb Smirnoff 						errx(1, "expand_queue strlcpy");
50583b3a8eb9SGleb Smirnoff 					if (strlcpy(n->queue, nq->queue,
50593b3a8eb9SGleb Smirnoff 					    sizeof(n->queue)) >=
50603b3a8eb9SGleb Smirnoff 					    sizeof(n->queue))
50613b3a8eb9SGleb Smirnoff 						errx(1, "expand_queue strlcpy");
50623b3a8eb9SGleb Smirnoff 					if (strlcpy(n->ifname, tqueue->ifname,
50633b3a8eb9SGleb Smirnoff 					    sizeof(n->ifname)) >=
50643b3a8eb9SGleb Smirnoff 					    sizeof(n->ifname))
50653b3a8eb9SGleb Smirnoff 						errx(1, "expand_queue strlcpy");
50663b3a8eb9SGleb Smirnoff 					n->scheduler = tqueue->scheduler;
50673b3a8eb9SGleb Smirnoff 					n->next = NULL;
50683b3a8eb9SGleb Smirnoff 					n->tail = n;
50693b3a8eb9SGleb Smirnoff 					if (queues == NULL)
50703b3a8eb9SGleb Smirnoff 						queues = n;
50713b3a8eb9SGleb Smirnoff 					else {
50723b3a8eb9SGleb Smirnoff 						queues->tail->next = n;
50733b3a8eb9SGleb Smirnoff 						queues->tail = n;
50743b3a8eb9SGleb Smirnoff 					}
50753b3a8eb9SGleb Smirnoff 				}
50763b3a8eb9SGleb Smirnoff 				if ((pf->opts & PF_OPT_VERBOSE) && (
50773b3a8eb9SGleb Smirnoff 				    (found == 1 && interface->ifname[0] == 0) ||
50783b3a8eb9SGleb Smirnoff 				    (found > 0 && interface->ifname[0] != 0))) {
50793b3a8eb9SGleb Smirnoff 					print_queue(&pf->paltq->altq, 0,
50803b3a8eb9SGleb Smirnoff 					    &bwspec, interface->ifname[0] != 0,
50813b3a8eb9SGleb Smirnoff 					    opts);
50823b3a8eb9SGleb Smirnoff 					if (nqueues && nqueues->tail) {
50833b3a8eb9SGleb Smirnoff 						printf("{ ");
50843b3a8eb9SGleb Smirnoff 						LOOP_THROUGH(struct node_queue,
50853b3a8eb9SGleb Smirnoff 						    queue, nqueues,
50863b3a8eb9SGleb Smirnoff 							printf("%s ",
50873b3a8eb9SGleb Smirnoff 							    queue->queue);
50883b3a8eb9SGleb Smirnoff 						);
50893b3a8eb9SGleb Smirnoff 						printf("}");
50903b3a8eb9SGleb Smirnoff 					}
50913b3a8eb9SGleb Smirnoff 					printf("\n");
50923b3a8eb9SGleb Smirnoff 				}
50933b3a8eb9SGleb Smirnoff 			}
50943b3a8eb9SGleb Smirnoff 		);
50953b3a8eb9SGleb Smirnoff 	);
50963b3a8eb9SGleb Smirnoff 
50973b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_queue, nqueues);
50983b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
50993b3a8eb9SGleb Smirnoff 
51003b3a8eb9SGleb Smirnoff 	if (!found) {
51013b3a8eb9SGleb Smirnoff 		yyerror("queue %s has no parent", a->qname);
51023b3a8eb9SGleb Smirnoff 		errs++;
51033b3a8eb9SGleb Smirnoff 	}
51043b3a8eb9SGleb Smirnoff 
51053b3a8eb9SGleb Smirnoff 	if (errs)
51063b3a8eb9SGleb Smirnoff 		return (1);
51073b3a8eb9SGleb Smirnoff 	else
51083b3a8eb9SGleb Smirnoff 		return (0);
51093b3a8eb9SGleb Smirnoff }
51103b3a8eb9SGleb Smirnoff 
51113b3a8eb9SGleb Smirnoff void
51123b3a8eb9SGleb Smirnoff expand_rule(struct pf_rule *r,
51133b3a8eb9SGleb Smirnoff     struct node_if *interfaces, struct node_host *rpool_hosts,
51143b3a8eb9SGleb Smirnoff     struct node_proto *protos, struct node_os *src_oses,
51153b3a8eb9SGleb Smirnoff     struct node_host *src_hosts, struct node_port *src_ports,
51163b3a8eb9SGleb Smirnoff     struct node_host *dst_hosts, struct node_port *dst_ports,
51173b3a8eb9SGleb Smirnoff     struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
51183b3a8eb9SGleb Smirnoff     const char *anchor_call)
51193b3a8eb9SGleb Smirnoff {
51203b3a8eb9SGleb Smirnoff 	sa_family_t		 af = r->af;
51213b3a8eb9SGleb Smirnoff 	int			 added = 0, error = 0;
51223b3a8eb9SGleb Smirnoff 	char			 ifname[IF_NAMESIZE];
51233b3a8eb9SGleb Smirnoff 	char			 label[PF_RULE_LABEL_SIZE];
51243b3a8eb9SGleb Smirnoff 	char			 tagname[PF_TAG_NAME_SIZE];
51253b3a8eb9SGleb Smirnoff 	char			 match_tagname[PF_TAG_NAME_SIZE];
51263b3a8eb9SGleb Smirnoff 	struct pf_pooladdr	*pa;
51273b3a8eb9SGleb Smirnoff 	struct node_host	*h;
51283b3a8eb9SGleb Smirnoff 	u_int8_t		 flags, flagset, keep_state;
51293b3a8eb9SGleb Smirnoff 
51303b3a8eb9SGleb Smirnoff 	if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
51313b3a8eb9SGleb Smirnoff 		errx(1, "expand_rule: strlcpy");
51323b3a8eb9SGleb Smirnoff 	if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
51333b3a8eb9SGleb Smirnoff 		errx(1, "expand_rule: strlcpy");
51343b3a8eb9SGleb Smirnoff 	if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
51353b3a8eb9SGleb Smirnoff 	    sizeof(match_tagname))
51363b3a8eb9SGleb Smirnoff 		errx(1, "expand_rule: strlcpy");
51373b3a8eb9SGleb Smirnoff 	flags = r->flags;
51383b3a8eb9SGleb Smirnoff 	flagset = r->flagset;
51393b3a8eb9SGleb Smirnoff 	keep_state = r->keep_state;
51403b3a8eb9SGleb Smirnoff 
51413b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
51423b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_proto, proto, protos,
51433b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
51443b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_host, src_host, src_hosts,
51453b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_port, src_port, src_ports,
51463b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_os, src_os, src_oses,
51473b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
51483b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
51493b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_uid, uid, uids,
51503b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_gid, gid, gids,
51513b3a8eb9SGleb Smirnoff 
51523b3a8eb9SGleb Smirnoff 		r->af = af;
51533b3a8eb9SGleb Smirnoff 		/* for link-local IPv6 address, interface must match up */
51543b3a8eb9SGleb Smirnoff 		if ((r->af && src_host->af && r->af != src_host->af) ||
51553b3a8eb9SGleb Smirnoff 		    (r->af && dst_host->af && r->af != dst_host->af) ||
51563b3a8eb9SGleb Smirnoff 		    (src_host->af && dst_host->af &&
51573b3a8eb9SGleb Smirnoff 		    src_host->af != dst_host->af) ||
51583b3a8eb9SGleb Smirnoff 		    (src_host->ifindex && dst_host->ifindex &&
51593b3a8eb9SGleb Smirnoff 		    src_host->ifindex != dst_host->ifindex) ||
51603b3a8eb9SGleb Smirnoff 		    (src_host->ifindex && *interface->ifname &&
51613b3a8eb9SGleb Smirnoff 		    src_host->ifindex != if_nametoindex(interface->ifname)) ||
51623b3a8eb9SGleb Smirnoff 		    (dst_host->ifindex && *interface->ifname &&
51633b3a8eb9SGleb Smirnoff 		    dst_host->ifindex != if_nametoindex(interface->ifname)))
51643b3a8eb9SGleb Smirnoff 			continue;
51653b3a8eb9SGleb Smirnoff 		if (!r->af && src_host->af)
51663b3a8eb9SGleb Smirnoff 			r->af = src_host->af;
51673b3a8eb9SGleb Smirnoff 		else if (!r->af && dst_host->af)
51683b3a8eb9SGleb Smirnoff 			r->af = dst_host->af;
51693b3a8eb9SGleb Smirnoff 
51703b3a8eb9SGleb Smirnoff 		if (*interface->ifname)
51713b3a8eb9SGleb Smirnoff 			strlcpy(r->ifname, interface->ifname,
51723b3a8eb9SGleb Smirnoff 			    sizeof(r->ifname));
51733b3a8eb9SGleb Smirnoff 		else if (if_indextoname(src_host->ifindex, ifname))
51743b3a8eb9SGleb Smirnoff 			strlcpy(r->ifname, ifname, sizeof(r->ifname));
51753b3a8eb9SGleb Smirnoff 		else if (if_indextoname(dst_host->ifindex, ifname))
51763b3a8eb9SGleb Smirnoff 			strlcpy(r->ifname, ifname, sizeof(r->ifname));
51773b3a8eb9SGleb Smirnoff 		else
51783b3a8eb9SGleb Smirnoff 			memset(r->ifname, '\0', sizeof(r->ifname));
51793b3a8eb9SGleb Smirnoff 
51803b3a8eb9SGleb Smirnoff 		if (strlcpy(r->label, label, sizeof(r->label)) >=
51813b3a8eb9SGleb Smirnoff 		    sizeof(r->label))
51823b3a8eb9SGleb Smirnoff 			errx(1, "expand_rule: strlcpy");
51833b3a8eb9SGleb Smirnoff 		if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
51843b3a8eb9SGleb Smirnoff 		    sizeof(r->tagname))
51853b3a8eb9SGleb Smirnoff 			errx(1, "expand_rule: strlcpy");
51863b3a8eb9SGleb Smirnoff 		if (strlcpy(r->match_tagname, match_tagname,
51873b3a8eb9SGleb Smirnoff 		    sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
51883b3a8eb9SGleb Smirnoff 			errx(1, "expand_rule: strlcpy");
51893b3a8eb9SGleb Smirnoff 		expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
51903b3a8eb9SGleb Smirnoff 		    src_host, src_port, dst_host, dst_port, proto->proto);
51913b3a8eb9SGleb Smirnoff 		expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
51923b3a8eb9SGleb Smirnoff 		    src_host, src_port, dst_host, dst_port, proto->proto);
51933b3a8eb9SGleb Smirnoff 		expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
51943b3a8eb9SGleb Smirnoff 		    r->af, src_host, src_port, dst_host, dst_port,
51953b3a8eb9SGleb Smirnoff 		    proto->proto);
51963b3a8eb9SGleb Smirnoff 
51973b3a8eb9SGleb Smirnoff 		error += check_netmask(src_host, r->af);
51983b3a8eb9SGleb Smirnoff 		error += check_netmask(dst_host, r->af);
51993b3a8eb9SGleb Smirnoff 
52003b3a8eb9SGleb Smirnoff 		r->ifnot = interface->not;
52013b3a8eb9SGleb Smirnoff 		r->proto = proto->proto;
52023b3a8eb9SGleb Smirnoff 		r->src.addr = src_host->addr;
52033b3a8eb9SGleb Smirnoff 		r->src.neg = src_host->not;
52043b3a8eb9SGleb Smirnoff 		r->src.port[0] = src_port->port[0];
52053b3a8eb9SGleb Smirnoff 		r->src.port[1] = src_port->port[1];
52063b3a8eb9SGleb Smirnoff 		r->src.port_op = src_port->op;
52073b3a8eb9SGleb Smirnoff 		r->dst.addr = dst_host->addr;
52083b3a8eb9SGleb Smirnoff 		r->dst.neg = dst_host->not;
52093b3a8eb9SGleb Smirnoff 		r->dst.port[0] = dst_port->port[0];
52103b3a8eb9SGleb Smirnoff 		r->dst.port[1] = dst_port->port[1];
52113b3a8eb9SGleb Smirnoff 		r->dst.port_op = dst_port->op;
52123b3a8eb9SGleb Smirnoff 		r->uid.op = uid->op;
52133b3a8eb9SGleb Smirnoff 		r->uid.uid[0] = uid->uid[0];
52143b3a8eb9SGleb Smirnoff 		r->uid.uid[1] = uid->uid[1];
52153b3a8eb9SGleb Smirnoff 		r->gid.op = gid->op;
52163b3a8eb9SGleb Smirnoff 		r->gid.gid[0] = gid->gid[0];
52173b3a8eb9SGleb Smirnoff 		r->gid.gid[1] = gid->gid[1];
52183b3a8eb9SGleb Smirnoff 		r->type = icmp_type->type;
52193b3a8eb9SGleb Smirnoff 		r->code = icmp_type->code;
52203b3a8eb9SGleb Smirnoff 
52213b3a8eb9SGleb Smirnoff 		if ((keep_state == PF_STATE_MODULATE ||
52223b3a8eb9SGleb Smirnoff 		    keep_state == PF_STATE_SYNPROXY) &&
52233b3a8eb9SGleb Smirnoff 		    r->proto && r->proto != IPPROTO_TCP)
52243b3a8eb9SGleb Smirnoff 			r->keep_state = PF_STATE_NORMAL;
52253b3a8eb9SGleb Smirnoff 		else
52263b3a8eb9SGleb Smirnoff 			r->keep_state = keep_state;
52273b3a8eb9SGleb Smirnoff 
52283b3a8eb9SGleb Smirnoff 		if (r->proto && r->proto != IPPROTO_TCP) {
52293b3a8eb9SGleb Smirnoff 			r->flags = 0;
52303b3a8eb9SGleb Smirnoff 			r->flagset = 0;
52313b3a8eb9SGleb Smirnoff 		} else {
52323b3a8eb9SGleb Smirnoff 			r->flags = flags;
52333b3a8eb9SGleb Smirnoff 			r->flagset = flagset;
52343b3a8eb9SGleb Smirnoff 		}
52353b3a8eb9SGleb Smirnoff 		if (icmp_type->proto && r->proto != icmp_type->proto) {
52363b3a8eb9SGleb Smirnoff 			yyerror("icmp-type mismatch");
52373b3a8eb9SGleb Smirnoff 			error++;
52383b3a8eb9SGleb Smirnoff 		}
52393b3a8eb9SGleb Smirnoff 
52403b3a8eb9SGleb Smirnoff 		if (src_os && src_os->os) {
52413b3a8eb9SGleb Smirnoff 			r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
52423b3a8eb9SGleb Smirnoff 			if ((pf->opts & PF_OPT_VERBOSE2) &&
52433b3a8eb9SGleb Smirnoff 			    r->os_fingerprint == PF_OSFP_NOMATCH)
52443b3a8eb9SGleb Smirnoff 				fprintf(stderr,
52453b3a8eb9SGleb Smirnoff 				    "warning: unknown '%s' OS fingerprint\n",
52463b3a8eb9SGleb Smirnoff 				    src_os->os);
52473b3a8eb9SGleb Smirnoff 		} else {
52483b3a8eb9SGleb Smirnoff 			r->os_fingerprint = PF_OSFP_ANY;
52493b3a8eb9SGleb Smirnoff 		}
52503b3a8eb9SGleb Smirnoff 
52513b3a8eb9SGleb Smirnoff 		TAILQ_INIT(&r->rpool.list);
52523b3a8eb9SGleb Smirnoff 		for (h = rpool_hosts; h != NULL; h = h->next) {
52533b3a8eb9SGleb Smirnoff 			pa = calloc(1, sizeof(struct pf_pooladdr));
52543b3a8eb9SGleb Smirnoff 			if (pa == NULL)
52553b3a8eb9SGleb Smirnoff 				err(1, "expand_rule: calloc");
52563b3a8eb9SGleb Smirnoff 			pa->addr = h->addr;
52573b3a8eb9SGleb Smirnoff 			if (h->ifname != NULL) {
52583b3a8eb9SGleb Smirnoff 				if (strlcpy(pa->ifname, h->ifname,
52593b3a8eb9SGleb Smirnoff 				    sizeof(pa->ifname)) >=
52603b3a8eb9SGleb Smirnoff 				    sizeof(pa->ifname))
52613b3a8eb9SGleb Smirnoff 					errx(1, "expand_rule: strlcpy");
52623b3a8eb9SGleb Smirnoff 			} else
52633b3a8eb9SGleb Smirnoff 				pa->ifname[0] = 0;
52643b3a8eb9SGleb Smirnoff 			TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
52653b3a8eb9SGleb Smirnoff 		}
52663b3a8eb9SGleb Smirnoff 
52673b3a8eb9SGleb Smirnoff 		if (rule_consistent(r, anchor_call[0]) < 0 || error)
52683b3a8eb9SGleb Smirnoff 			yyerror("skipping rule due to errors");
52693b3a8eb9SGleb Smirnoff 		else {
52703b3a8eb9SGleb Smirnoff 			r->nr = pf->astack[pf->asd]->match++;
52713b3a8eb9SGleb Smirnoff 			pfctl_add_rule(pf, r, anchor_call);
52723b3a8eb9SGleb Smirnoff 			added++;
52733b3a8eb9SGleb Smirnoff 		}
52743b3a8eb9SGleb Smirnoff 
52753b3a8eb9SGleb Smirnoff 	))))))))));
52763b3a8eb9SGleb Smirnoff 
52773b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
52783b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_proto, protos);
52793b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_host, src_hosts);
52803b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_port, src_ports);
52813b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_os, src_oses);
52823b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_host, dst_hosts);
52833b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_port, dst_ports);
52843b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_uid, uids);
52853b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_gid, gids);
52863b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_icmp, icmp_types);
52873b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_host, rpool_hosts);
52883b3a8eb9SGleb Smirnoff 
52893b3a8eb9SGleb Smirnoff 	if (!added)
52903b3a8eb9SGleb Smirnoff 		yyerror("rule expands to no valid combination");
52913b3a8eb9SGleb Smirnoff }
52923b3a8eb9SGleb Smirnoff 
52933b3a8eb9SGleb Smirnoff int
52943b3a8eb9SGleb Smirnoff expand_skip_interface(struct node_if *interfaces)
52953b3a8eb9SGleb Smirnoff {
52963b3a8eb9SGleb Smirnoff 	int	errs = 0;
52973b3a8eb9SGleb Smirnoff 
52983b3a8eb9SGleb Smirnoff 	if (!interfaces || (!interfaces->next && !interfaces->not &&
52993b3a8eb9SGleb Smirnoff 	    !strcmp(interfaces->ifname, "none"))) {
53003b3a8eb9SGleb Smirnoff 		if (pf->opts & PF_OPT_VERBOSE)
53013b3a8eb9SGleb Smirnoff 			printf("set skip on none\n");
53023b3a8eb9SGleb Smirnoff 		errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
53033b3a8eb9SGleb Smirnoff 		return (errs);
53043b3a8eb9SGleb Smirnoff 	}
53053b3a8eb9SGleb Smirnoff 
53063b3a8eb9SGleb Smirnoff 	if (pf->opts & PF_OPT_VERBOSE)
53073b3a8eb9SGleb Smirnoff 		printf("set skip on {");
53083b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
53093b3a8eb9SGleb Smirnoff 		if (pf->opts & PF_OPT_VERBOSE)
53103b3a8eb9SGleb Smirnoff 			printf(" %s", interface->ifname);
53113b3a8eb9SGleb Smirnoff 		if (interface->not) {
53123b3a8eb9SGleb Smirnoff 			yyerror("skip on ! <interface> is not supported");
53133b3a8eb9SGleb Smirnoff 			errs++;
53143b3a8eb9SGleb Smirnoff 		} else
53153b3a8eb9SGleb Smirnoff 			errs += pfctl_set_interface_flags(pf,
53163b3a8eb9SGleb Smirnoff 			    interface->ifname, PFI_IFLAG_SKIP, 1);
53173b3a8eb9SGleb Smirnoff 	);
53183b3a8eb9SGleb Smirnoff 	if (pf->opts & PF_OPT_VERBOSE)
53193b3a8eb9SGleb Smirnoff 		printf(" }\n");
53203b3a8eb9SGleb Smirnoff 
53213b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
53223b3a8eb9SGleb Smirnoff 
53233b3a8eb9SGleb Smirnoff 	if (errs)
53243b3a8eb9SGleb Smirnoff 		return (1);
53253b3a8eb9SGleb Smirnoff 	else
53263b3a8eb9SGleb Smirnoff 		return (0);
53273b3a8eb9SGleb Smirnoff }
53283b3a8eb9SGleb Smirnoff 
53293b3a8eb9SGleb Smirnoff #undef FREE_LIST
53303b3a8eb9SGleb Smirnoff #undef LOOP_THROUGH
53313b3a8eb9SGleb Smirnoff 
53323b3a8eb9SGleb Smirnoff int
53333b3a8eb9SGleb Smirnoff check_rulestate(int desired_state)
53343b3a8eb9SGleb Smirnoff {
53353b3a8eb9SGleb Smirnoff 	if (require_order && (rulestate > desired_state)) {
53363b3a8eb9SGleb Smirnoff 		yyerror("Rules must be in order: options, normalization, "
53373b3a8eb9SGleb Smirnoff 		    "queueing, translation, filtering");
53383b3a8eb9SGleb Smirnoff 		return (1);
53393b3a8eb9SGleb Smirnoff 	}
53403b3a8eb9SGleb Smirnoff 	rulestate = desired_state;
53413b3a8eb9SGleb Smirnoff 	return (0);
53423b3a8eb9SGleb Smirnoff }
53433b3a8eb9SGleb Smirnoff 
53443b3a8eb9SGleb Smirnoff int
53453b3a8eb9SGleb Smirnoff kw_cmp(const void *k, const void *e)
53463b3a8eb9SGleb Smirnoff {
53473b3a8eb9SGleb Smirnoff 	return (strcmp(k, ((const struct keywords *)e)->k_name));
53483b3a8eb9SGleb Smirnoff }
53493b3a8eb9SGleb Smirnoff 
53503b3a8eb9SGleb Smirnoff int
53513b3a8eb9SGleb Smirnoff lookup(char *s)
53523b3a8eb9SGleb Smirnoff {
53533b3a8eb9SGleb Smirnoff 	/* this has to be sorted always */
53543b3a8eb9SGleb Smirnoff 	static const struct keywords keywords[] = {
53553b3a8eb9SGleb Smirnoff 		{ "all",		ALL},
53563b3a8eb9SGleb Smirnoff 		{ "allow-opts",		ALLOWOPTS},
53573b3a8eb9SGleb Smirnoff 		{ "altq",		ALTQ},
53583b3a8eb9SGleb Smirnoff 		{ "anchor",		ANCHOR},
53593b3a8eb9SGleb Smirnoff 		{ "antispoof",		ANTISPOOF},
53603b3a8eb9SGleb Smirnoff 		{ "any",		ANY},
53613b3a8eb9SGleb Smirnoff 		{ "bandwidth",		BANDWIDTH},
53623b3a8eb9SGleb Smirnoff 		{ "binat",		BINAT},
53633b3a8eb9SGleb Smirnoff 		{ "binat-anchor",	BINATANCHOR},
53643b3a8eb9SGleb Smirnoff 		{ "bitmask",		BITMASK},
53653b3a8eb9SGleb Smirnoff 		{ "block",		BLOCK},
53663b3a8eb9SGleb Smirnoff 		{ "block-policy",	BLOCKPOLICY},
5367a5b789f6SErmal Luçi 		{ "buckets",		BUCKETS},
53683b3a8eb9SGleb Smirnoff 		{ "cbq",		CBQ},
53693b3a8eb9SGleb Smirnoff 		{ "code",		CODE},
53700a70aaf8SLuiz Otavio O Souza 		{ "codelq",		CODEL},
53713b3a8eb9SGleb Smirnoff 		{ "crop",		FRAGCROP},
53723b3a8eb9SGleb Smirnoff 		{ "debug",		DEBUG},
53733b3a8eb9SGleb Smirnoff 		{ "divert-reply",	DIVERTREPLY},
53743b3a8eb9SGleb Smirnoff 		{ "divert-to",		DIVERTTO},
53753b3a8eb9SGleb Smirnoff 		{ "drop",		DROP},
53763b3a8eb9SGleb Smirnoff 		{ "drop-ovl",		FRAGDROP},
53773b3a8eb9SGleb Smirnoff 		{ "dup-to",		DUPTO},
5378a5b789f6SErmal Luçi 		{ "fairq",		FAIRQ},
53793b3a8eb9SGleb Smirnoff 		{ "fastroute",		FASTROUTE},
53803b3a8eb9SGleb Smirnoff 		{ "file",		FILENAME},
53813b3a8eb9SGleb Smirnoff 		{ "fingerprints",	FINGERPRINTS},
53823b3a8eb9SGleb Smirnoff 		{ "flags",		FLAGS},
53833b3a8eb9SGleb Smirnoff 		{ "floating",		FLOATING},
53843b3a8eb9SGleb Smirnoff 		{ "flush",		FLUSH},
53853b3a8eb9SGleb Smirnoff 		{ "for",		FOR},
53863b3a8eb9SGleb Smirnoff 		{ "fragment",		FRAGMENT},
53873b3a8eb9SGleb Smirnoff 		{ "from",		FROM},
53883b3a8eb9SGleb Smirnoff 		{ "global",		GLOBAL},
53893b3a8eb9SGleb Smirnoff 		{ "group",		GROUP},
53903b3a8eb9SGleb Smirnoff 		{ "hfsc",		HFSC},
5391a5b789f6SErmal Luçi 		{ "hogs",		HOGS},
53923b3a8eb9SGleb Smirnoff 		{ "hostid",		HOSTID},
53933b3a8eb9SGleb Smirnoff 		{ "icmp-type",		ICMPTYPE},
53943b3a8eb9SGleb Smirnoff 		{ "icmp6-type",		ICMP6TYPE},
53953b3a8eb9SGleb Smirnoff 		{ "if-bound",		IFBOUND},
53963b3a8eb9SGleb Smirnoff 		{ "in",			IN},
53973b3a8eb9SGleb Smirnoff 		{ "include",		INCLUDE},
53983b3a8eb9SGleb Smirnoff 		{ "inet",		INET},
53993b3a8eb9SGleb Smirnoff 		{ "inet6",		INET6},
54000a70aaf8SLuiz Otavio O Souza 		{ "interval",		INTERVAL},
54013b3a8eb9SGleb Smirnoff 		{ "keep",		KEEP},
54023b3a8eb9SGleb Smirnoff 		{ "label",		LABEL},
54033b3a8eb9SGleb Smirnoff 		{ "limit",		LIMIT},
54043b3a8eb9SGleb Smirnoff 		{ "linkshare",		LINKSHARE},
54053b3a8eb9SGleb Smirnoff 		{ "load",		LOAD},
54063b3a8eb9SGleb Smirnoff 		{ "log",		LOG},
54073b3a8eb9SGleb Smirnoff 		{ "loginterface",	LOGINTERFACE},
54083b3a8eb9SGleb Smirnoff 		{ "max",		MAXIMUM},
54093b3a8eb9SGleb Smirnoff 		{ "max-mss",		MAXMSS},
54103b3a8eb9SGleb Smirnoff 		{ "max-src-conn",	MAXSRCCONN},
54113b3a8eb9SGleb Smirnoff 		{ "max-src-conn-rate",	MAXSRCCONNRATE},
54123b3a8eb9SGleb Smirnoff 		{ "max-src-nodes",	MAXSRCNODES},
54133b3a8eb9SGleb Smirnoff 		{ "max-src-states",	MAXSRCSTATES},
54143b3a8eb9SGleb Smirnoff 		{ "min-ttl",		MINTTL},
54153b3a8eb9SGleb Smirnoff 		{ "modulate",		MODULATE},
54163b3a8eb9SGleb Smirnoff 		{ "nat",		NAT},
54173b3a8eb9SGleb Smirnoff 		{ "nat-anchor",		NATANCHOR},
54183b3a8eb9SGleb Smirnoff 		{ "no",			NO},
54193b3a8eb9SGleb Smirnoff 		{ "no-df",		NODF},
54203b3a8eb9SGleb Smirnoff 		{ "no-route",		NOROUTE},
54213b3a8eb9SGleb Smirnoff 		{ "no-sync",		NOSYNC},
54223b3a8eb9SGleb Smirnoff 		{ "on",			ON},
54233b3a8eb9SGleb Smirnoff 		{ "optimization",	OPTIMIZATION},
54243b3a8eb9SGleb Smirnoff 		{ "os",			OS},
54253b3a8eb9SGleb Smirnoff 		{ "out",		OUT},
54263b3a8eb9SGleb Smirnoff 		{ "overload",		OVERLOAD},
54273b3a8eb9SGleb Smirnoff 		{ "pass",		PASS},
54283b3a8eb9SGleb Smirnoff 		{ "port",		PORT},
54293b3a8eb9SGleb Smirnoff 		{ "priority",		PRIORITY},
54303b3a8eb9SGleb Smirnoff 		{ "priq",		PRIQ},
54313b3a8eb9SGleb Smirnoff 		{ "probability",	PROBABILITY},
54323b3a8eb9SGleb Smirnoff 		{ "proto",		PROTO},
54333b3a8eb9SGleb Smirnoff 		{ "qlimit",		QLIMIT},
54343b3a8eb9SGleb Smirnoff 		{ "queue",		QUEUE},
54353b3a8eb9SGleb Smirnoff 		{ "quick",		QUICK},
54363b3a8eb9SGleb Smirnoff 		{ "random",		RANDOM},
54373b3a8eb9SGleb Smirnoff 		{ "random-id",		RANDOMID},
54383b3a8eb9SGleb Smirnoff 		{ "rdr",		RDR},
54393b3a8eb9SGleb Smirnoff 		{ "rdr-anchor",		RDRANCHOR},
54403b3a8eb9SGleb Smirnoff 		{ "realtime",		REALTIME},
54413b3a8eb9SGleb Smirnoff 		{ "reassemble",		REASSEMBLE},
54423b3a8eb9SGleb Smirnoff 		{ "reply-to",		REPLYTO},
54433b3a8eb9SGleb Smirnoff 		{ "require-order",	REQUIREORDER},
54443b3a8eb9SGleb Smirnoff 		{ "return",		RETURN},
54453b3a8eb9SGleb Smirnoff 		{ "return-icmp",	RETURNICMP},
54463b3a8eb9SGleb Smirnoff 		{ "return-icmp6",	RETURNICMP6},
54473b3a8eb9SGleb Smirnoff 		{ "return-rst",		RETURNRST},
54483b3a8eb9SGleb Smirnoff 		{ "round-robin",	ROUNDROBIN},
54493b3a8eb9SGleb Smirnoff 		{ "route",		ROUTE},
54503b3a8eb9SGleb Smirnoff 		{ "route-to",		ROUTETO},
54513b3a8eb9SGleb Smirnoff 		{ "rtable",		RTABLE},
54523b3a8eb9SGleb Smirnoff 		{ "rule",		RULE},
54533b3a8eb9SGleb Smirnoff 		{ "ruleset-optimization",	RULESET_OPTIMIZATION},
54543b3a8eb9SGleb Smirnoff 		{ "scrub",		SCRUB},
54553b3a8eb9SGleb Smirnoff 		{ "set",		SET},
54563b3a8eb9SGleb Smirnoff 		{ "set-tos",		SETTOS},
54573b3a8eb9SGleb Smirnoff 		{ "skip",		SKIP},
54583b3a8eb9SGleb Smirnoff 		{ "sloppy",		SLOPPY},
54593b3a8eb9SGleb Smirnoff 		{ "source-hash",	SOURCEHASH},
54603b3a8eb9SGleb Smirnoff 		{ "source-track",	SOURCETRACK},
54613b3a8eb9SGleb Smirnoff 		{ "state",		STATE},
54623b3a8eb9SGleb Smirnoff 		{ "state-defaults",	STATEDEFAULTS},
54633b3a8eb9SGleb Smirnoff 		{ "state-policy",	STATEPOLICY},
54643b3a8eb9SGleb Smirnoff 		{ "static-port",	STATICPORT},
54653b3a8eb9SGleb Smirnoff 		{ "sticky-address",	STICKYADDRESS},
54663b3a8eb9SGleb Smirnoff 		{ "synproxy",		SYNPROXY},
54673b3a8eb9SGleb Smirnoff 		{ "table",		TABLE},
54683b3a8eb9SGleb Smirnoff 		{ "tag",		TAG},
54693b3a8eb9SGleb Smirnoff 		{ "tagged",		TAGGED},
54700a70aaf8SLuiz Otavio O Souza 		{ "target",		TARGET},
54713b3a8eb9SGleb Smirnoff 		{ "tbrsize",		TBRSIZE},
54723b3a8eb9SGleb Smirnoff 		{ "timeout",		TIMEOUT},
54733b3a8eb9SGleb Smirnoff 		{ "to",			TO},
54743b3a8eb9SGleb Smirnoff 		{ "tos",		TOS},
54753b3a8eb9SGleb Smirnoff 		{ "ttl",		TTL},
54763b3a8eb9SGleb Smirnoff 		{ "upperlimit",		UPPERLIMIT},
54773b3a8eb9SGleb Smirnoff 		{ "urpf-failed",	URPFFAILED},
54783b3a8eb9SGleb Smirnoff 		{ "user",		USER},
54793b3a8eb9SGleb Smirnoff 	};
54803b3a8eb9SGleb Smirnoff 	const struct keywords	*p;
54813b3a8eb9SGleb Smirnoff 
54823b3a8eb9SGleb Smirnoff 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
54833b3a8eb9SGleb Smirnoff 	    sizeof(keywords[0]), kw_cmp);
54843b3a8eb9SGleb Smirnoff 
54853b3a8eb9SGleb Smirnoff 	if (p) {
54863b3a8eb9SGleb Smirnoff 		if (debug > 1)
54873b3a8eb9SGleb Smirnoff 			fprintf(stderr, "%s: %d\n", s, p->k_val);
54883b3a8eb9SGleb Smirnoff 		return (p->k_val);
54893b3a8eb9SGleb Smirnoff 	} else {
54903b3a8eb9SGleb Smirnoff 		if (debug > 1)
54913b3a8eb9SGleb Smirnoff 			fprintf(stderr, "string: %s\n", s);
54923b3a8eb9SGleb Smirnoff 		return (STRING);
54933b3a8eb9SGleb Smirnoff 	}
54943b3a8eb9SGleb Smirnoff }
54953b3a8eb9SGleb Smirnoff 
54963b3a8eb9SGleb Smirnoff #define MAXPUSHBACK	128
54973b3a8eb9SGleb Smirnoff 
54983b3a8eb9SGleb Smirnoff char	*parsebuf;
54993b3a8eb9SGleb Smirnoff int	 parseindex;
55003b3a8eb9SGleb Smirnoff char	 pushback_buffer[MAXPUSHBACK];
55013b3a8eb9SGleb Smirnoff int	 pushback_index = 0;
55023b3a8eb9SGleb Smirnoff 
55033b3a8eb9SGleb Smirnoff int
55043b3a8eb9SGleb Smirnoff lgetc(int quotec)
55053b3a8eb9SGleb Smirnoff {
55063b3a8eb9SGleb Smirnoff 	int		c, next;
55073b3a8eb9SGleb Smirnoff 
55083b3a8eb9SGleb Smirnoff 	if (parsebuf) {
55093b3a8eb9SGleb Smirnoff 		/* Read character from the parsebuffer instead of input. */
55103b3a8eb9SGleb Smirnoff 		if (parseindex >= 0) {
55113b3a8eb9SGleb Smirnoff 			c = parsebuf[parseindex++];
55123b3a8eb9SGleb Smirnoff 			if (c != '\0')
55133b3a8eb9SGleb Smirnoff 				return (c);
55143b3a8eb9SGleb Smirnoff 			parsebuf = NULL;
55153b3a8eb9SGleb Smirnoff 		} else
55163b3a8eb9SGleb Smirnoff 			parseindex++;
55173b3a8eb9SGleb Smirnoff 	}
55183b3a8eb9SGleb Smirnoff 
55193b3a8eb9SGleb Smirnoff 	if (pushback_index)
55203b3a8eb9SGleb Smirnoff 		return (pushback_buffer[--pushback_index]);
55213b3a8eb9SGleb Smirnoff 
55223b3a8eb9SGleb Smirnoff 	if (quotec) {
55233b3a8eb9SGleb Smirnoff 		if ((c = getc(file->stream)) == EOF) {
55243b3a8eb9SGleb Smirnoff 			yyerror("reached end of file while parsing quoted string");
55253b3a8eb9SGleb Smirnoff 			if (popfile() == EOF)
55263b3a8eb9SGleb Smirnoff 				return (EOF);
55273b3a8eb9SGleb Smirnoff 			return (quotec);
55283b3a8eb9SGleb Smirnoff 		}
55293b3a8eb9SGleb Smirnoff 		return (c);
55303b3a8eb9SGleb Smirnoff 	}
55313b3a8eb9SGleb Smirnoff 
55323b3a8eb9SGleb Smirnoff 	while ((c = getc(file->stream)) == '\\') {
55333b3a8eb9SGleb Smirnoff 		next = getc(file->stream);
55343b3a8eb9SGleb Smirnoff 		if (next != '\n') {
55353b3a8eb9SGleb Smirnoff 			c = next;
55363b3a8eb9SGleb Smirnoff 			break;
55373b3a8eb9SGleb Smirnoff 		}
55383b3a8eb9SGleb Smirnoff 		yylval.lineno = file->lineno;
55393b3a8eb9SGleb Smirnoff 		file->lineno++;
55403b3a8eb9SGleb Smirnoff 	}
55413b3a8eb9SGleb Smirnoff 
55423b3a8eb9SGleb Smirnoff 	while (c == EOF) {
55433b3a8eb9SGleb Smirnoff 		if (popfile() == EOF)
55443b3a8eb9SGleb Smirnoff 			return (EOF);
55453b3a8eb9SGleb Smirnoff 		c = getc(file->stream);
55463b3a8eb9SGleb Smirnoff 	}
55473b3a8eb9SGleb Smirnoff 	return (c);
55483b3a8eb9SGleb Smirnoff }
55493b3a8eb9SGleb Smirnoff 
55503b3a8eb9SGleb Smirnoff int
55513b3a8eb9SGleb Smirnoff lungetc(int c)
55523b3a8eb9SGleb Smirnoff {
55533b3a8eb9SGleb Smirnoff 	if (c == EOF)
55543b3a8eb9SGleb Smirnoff 		return (EOF);
55553b3a8eb9SGleb Smirnoff 	if (parsebuf) {
55563b3a8eb9SGleb Smirnoff 		parseindex--;
55573b3a8eb9SGleb Smirnoff 		if (parseindex >= 0)
55583b3a8eb9SGleb Smirnoff 			return (c);
55593b3a8eb9SGleb Smirnoff 	}
55603b3a8eb9SGleb Smirnoff 	if (pushback_index < MAXPUSHBACK-1)
55613b3a8eb9SGleb Smirnoff 		return (pushback_buffer[pushback_index++] = c);
55623b3a8eb9SGleb Smirnoff 	else
55633b3a8eb9SGleb Smirnoff 		return (EOF);
55643b3a8eb9SGleb Smirnoff }
55653b3a8eb9SGleb Smirnoff 
55663b3a8eb9SGleb Smirnoff int
55673b3a8eb9SGleb Smirnoff findeol(void)
55683b3a8eb9SGleb Smirnoff {
55693b3a8eb9SGleb Smirnoff 	int	c;
55703b3a8eb9SGleb Smirnoff 
55713b3a8eb9SGleb Smirnoff 	parsebuf = NULL;
55723b3a8eb9SGleb Smirnoff 
55733b3a8eb9SGleb Smirnoff 	/* skip to either EOF or the first real EOL */
55743b3a8eb9SGleb Smirnoff 	while (1) {
55753b3a8eb9SGleb Smirnoff 		if (pushback_index)
55763b3a8eb9SGleb Smirnoff 			c = pushback_buffer[--pushback_index];
55773b3a8eb9SGleb Smirnoff 		else
55783b3a8eb9SGleb Smirnoff 			c = lgetc(0);
55793b3a8eb9SGleb Smirnoff 		if (c == '\n') {
55803b3a8eb9SGleb Smirnoff 			file->lineno++;
55813b3a8eb9SGleb Smirnoff 			break;
55823b3a8eb9SGleb Smirnoff 		}
55833b3a8eb9SGleb Smirnoff 		if (c == EOF)
55843b3a8eb9SGleb Smirnoff 			break;
55853b3a8eb9SGleb Smirnoff 	}
55863b3a8eb9SGleb Smirnoff 	return (ERROR);
55873b3a8eb9SGleb Smirnoff }
55883b3a8eb9SGleb Smirnoff 
55893b3a8eb9SGleb Smirnoff int
55903b3a8eb9SGleb Smirnoff yylex(void)
55913b3a8eb9SGleb Smirnoff {
55923b3a8eb9SGleb Smirnoff 	char	 buf[8096];
55933b3a8eb9SGleb Smirnoff 	char	*p, *val;
55943b3a8eb9SGleb Smirnoff 	int	 quotec, next, c;
55953b3a8eb9SGleb Smirnoff 	int	 token;
55963b3a8eb9SGleb Smirnoff 
55973b3a8eb9SGleb Smirnoff top:
55983b3a8eb9SGleb Smirnoff 	p = buf;
55993b3a8eb9SGleb Smirnoff 	while ((c = lgetc(0)) == ' ' || c == '\t')
56003b3a8eb9SGleb Smirnoff 		; /* nothing */
56013b3a8eb9SGleb Smirnoff 
56023b3a8eb9SGleb Smirnoff 	yylval.lineno = file->lineno;
56033b3a8eb9SGleb Smirnoff 	if (c == '#')
56043b3a8eb9SGleb Smirnoff 		while ((c = lgetc(0)) != '\n' && c != EOF)
56053b3a8eb9SGleb Smirnoff 			; /* nothing */
56063b3a8eb9SGleb Smirnoff 	if (c == '$' && parsebuf == NULL) {
56073b3a8eb9SGleb Smirnoff 		while (1) {
56083b3a8eb9SGleb Smirnoff 			if ((c = lgetc(0)) == EOF)
56093b3a8eb9SGleb Smirnoff 				return (0);
56103b3a8eb9SGleb Smirnoff 
56113b3a8eb9SGleb Smirnoff 			if (p + 1 >= buf + sizeof(buf) - 1) {
56123b3a8eb9SGleb Smirnoff 				yyerror("string too long");
56133b3a8eb9SGleb Smirnoff 				return (findeol());
56143b3a8eb9SGleb Smirnoff 			}
56153b3a8eb9SGleb Smirnoff 			if (isalnum(c) || c == '_') {
56163b3a8eb9SGleb Smirnoff 				*p++ = (char)c;
56173b3a8eb9SGleb Smirnoff 				continue;
56183b3a8eb9SGleb Smirnoff 			}
56193b3a8eb9SGleb Smirnoff 			*p = '\0';
56203b3a8eb9SGleb Smirnoff 			lungetc(c);
56213b3a8eb9SGleb Smirnoff 			break;
56223b3a8eb9SGleb Smirnoff 		}
56233b3a8eb9SGleb Smirnoff 		val = symget(buf);
56243b3a8eb9SGleb Smirnoff 		if (val == NULL) {
56253b3a8eb9SGleb Smirnoff 			yyerror("macro '%s' not defined", buf);
56263b3a8eb9SGleb Smirnoff 			return (findeol());
56273b3a8eb9SGleb Smirnoff 		}
56283b3a8eb9SGleb Smirnoff 		parsebuf = val;
56293b3a8eb9SGleb Smirnoff 		parseindex = 0;
56303b3a8eb9SGleb Smirnoff 		goto top;
56313b3a8eb9SGleb Smirnoff 	}
56323b3a8eb9SGleb Smirnoff 
56333b3a8eb9SGleb Smirnoff 	switch (c) {
56343b3a8eb9SGleb Smirnoff 	case '\'':
56353b3a8eb9SGleb Smirnoff 	case '"':
56363b3a8eb9SGleb Smirnoff 		quotec = c;
56373b3a8eb9SGleb Smirnoff 		while (1) {
56383b3a8eb9SGleb Smirnoff 			if ((c = lgetc(quotec)) == EOF)
56393b3a8eb9SGleb Smirnoff 				return (0);
56403b3a8eb9SGleb Smirnoff 			if (c == '\n') {
56413b3a8eb9SGleb Smirnoff 				file->lineno++;
56423b3a8eb9SGleb Smirnoff 				continue;
56433b3a8eb9SGleb Smirnoff 			} else if (c == '\\') {
56443b3a8eb9SGleb Smirnoff 				if ((next = lgetc(quotec)) == EOF)
56453b3a8eb9SGleb Smirnoff 					return (0);
56463b3a8eb9SGleb Smirnoff 				if (next == quotec || c == ' ' || c == '\t')
56473b3a8eb9SGleb Smirnoff 					c = next;
56483b3a8eb9SGleb Smirnoff 				else if (next == '\n')
56493b3a8eb9SGleb Smirnoff 					continue;
56503b3a8eb9SGleb Smirnoff 				else
56513b3a8eb9SGleb Smirnoff 					lungetc(next);
56523b3a8eb9SGleb Smirnoff 			} else if (c == quotec) {
56533b3a8eb9SGleb Smirnoff 				*p = '\0';
56543b3a8eb9SGleb Smirnoff 				break;
56553b3a8eb9SGleb Smirnoff 			}
56563b3a8eb9SGleb Smirnoff 			if (p + 1 >= buf + sizeof(buf) - 1) {
56573b3a8eb9SGleb Smirnoff 				yyerror("string too long");
56583b3a8eb9SGleb Smirnoff 				return (findeol());
56593b3a8eb9SGleb Smirnoff 			}
56603b3a8eb9SGleb Smirnoff 			*p++ = (char)c;
56613b3a8eb9SGleb Smirnoff 		}
56623b3a8eb9SGleb Smirnoff 		yylval.v.string = strdup(buf);
56633b3a8eb9SGleb Smirnoff 		if (yylval.v.string == NULL)
56643b3a8eb9SGleb Smirnoff 			err(1, "yylex: strdup");
56653b3a8eb9SGleb Smirnoff 		return (STRING);
56663b3a8eb9SGleb Smirnoff 	case '<':
56673b3a8eb9SGleb Smirnoff 		next = lgetc(0);
56683b3a8eb9SGleb Smirnoff 		if (next == '>') {
56693b3a8eb9SGleb Smirnoff 			yylval.v.i = PF_OP_XRG;
56703b3a8eb9SGleb Smirnoff 			return (PORTBINARY);
56713b3a8eb9SGleb Smirnoff 		}
56723b3a8eb9SGleb Smirnoff 		lungetc(next);
56733b3a8eb9SGleb Smirnoff 		break;
56743b3a8eb9SGleb Smirnoff 	case '>':
56753b3a8eb9SGleb Smirnoff 		next = lgetc(0);
56763b3a8eb9SGleb Smirnoff 		if (next == '<') {
56773b3a8eb9SGleb Smirnoff 			yylval.v.i = PF_OP_IRG;
56783b3a8eb9SGleb Smirnoff 			return (PORTBINARY);
56793b3a8eb9SGleb Smirnoff 		}
56803b3a8eb9SGleb Smirnoff 		lungetc(next);
56813b3a8eb9SGleb Smirnoff 		break;
56823b3a8eb9SGleb Smirnoff 	case '-':
56833b3a8eb9SGleb Smirnoff 		next = lgetc(0);
56843b3a8eb9SGleb Smirnoff 		if (next == '>')
56853b3a8eb9SGleb Smirnoff 			return (ARROW);
56863b3a8eb9SGleb Smirnoff 		lungetc(next);
56873b3a8eb9SGleb Smirnoff 		break;
56883b3a8eb9SGleb Smirnoff 	}
56893b3a8eb9SGleb Smirnoff 
56903b3a8eb9SGleb Smirnoff #define allowed_to_end_number(x) \
56913b3a8eb9SGleb Smirnoff 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
56923b3a8eb9SGleb Smirnoff 
56933b3a8eb9SGleb Smirnoff 	if (c == '-' || isdigit(c)) {
56943b3a8eb9SGleb Smirnoff 		do {
56953b3a8eb9SGleb Smirnoff 			*p++ = c;
56963b3a8eb9SGleb Smirnoff 			if ((unsigned)(p-buf) >= sizeof(buf)) {
56973b3a8eb9SGleb Smirnoff 				yyerror("string too long");
56983b3a8eb9SGleb Smirnoff 				return (findeol());
56993b3a8eb9SGleb Smirnoff 			}
57003b3a8eb9SGleb Smirnoff 		} while ((c = lgetc(0)) != EOF && isdigit(c));
57013b3a8eb9SGleb Smirnoff 		lungetc(c);
57023b3a8eb9SGleb Smirnoff 		if (p == buf + 1 && buf[0] == '-')
57033b3a8eb9SGleb Smirnoff 			goto nodigits;
57043b3a8eb9SGleb Smirnoff 		if (c == EOF || allowed_to_end_number(c)) {
57053b3a8eb9SGleb Smirnoff 			const char *errstr = NULL;
57063b3a8eb9SGleb Smirnoff 
57073b3a8eb9SGleb Smirnoff 			*p = '\0';
57083b3a8eb9SGleb Smirnoff 			yylval.v.number = strtonum(buf, LLONG_MIN,
57093b3a8eb9SGleb Smirnoff 			    LLONG_MAX, &errstr);
57103b3a8eb9SGleb Smirnoff 			if (errstr) {
57113b3a8eb9SGleb Smirnoff 				yyerror("\"%s\" invalid number: %s",
57123b3a8eb9SGleb Smirnoff 				    buf, errstr);
57133b3a8eb9SGleb Smirnoff 				return (findeol());
57143b3a8eb9SGleb Smirnoff 			}
57153b3a8eb9SGleb Smirnoff 			return (NUMBER);
57163b3a8eb9SGleb Smirnoff 		} else {
57173b3a8eb9SGleb Smirnoff nodigits:
57183b3a8eb9SGleb Smirnoff 			while (p > buf + 1)
57193b3a8eb9SGleb Smirnoff 				lungetc(*--p);
57203b3a8eb9SGleb Smirnoff 			c = *--p;
57213b3a8eb9SGleb Smirnoff 			if (c == '-')
57223b3a8eb9SGleb Smirnoff 				return (c);
57233b3a8eb9SGleb Smirnoff 		}
57243b3a8eb9SGleb Smirnoff 	}
57253b3a8eb9SGleb Smirnoff 
57263b3a8eb9SGleb Smirnoff #define allowed_in_string(x) \
57273b3a8eb9SGleb Smirnoff 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
57283b3a8eb9SGleb Smirnoff 	x != '{' && x != '}' && x != '<' && x != '>' && \
57293b3a8eb9SGleb Smirnoff 	x != '!' && x != '=' && x != '/' && x != '#' && \
57303b3a8eb9SGleb Smirnoff 	x != ','))
57313b3a8eb9SGleb Smirnoff 
57323b3a8eb9SGleb Smirnoff 	if (isalnum(c) || c == ':' || c == '_') {
57333b3a8eb9SGleb Smirnoff 		do {
57343b3a8eb9SGleb Smirnoff 			*p++ = c;
57353b3a8eb9SGleb Smirnoff 			if ((unsigned)(p-buf) >= sizeof(buf)) {
57363b3a8eb9SGleb Smirnoff 				yyerror("string too long");
57373b3a8eb9SGleb Smirnoff 				return (findeol());
57383b3a8eb9SGleb Smirnoff 			}
57393b3a8eb9SGleb Smirnoff 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
57403b3a8eb9SGleb Smirnoff 		lungetc(c);
57413b3a8eb9SGleb Smirnoff 		*p = '\0';
57423b3a8eb9SGleb Smirnoff 		if ((token = lookup(buf)) == STRING)
57433b3a8eb9SGleb Smirnoff 			if ((yylval.v.string = strdup(buf)) == NULL)
57443b3a8eb9SGleb Smirnoff 				err(1, "yylex: strdup");
57453b3a8eb9SGleb Smirnoff 		return (token);
57463b3a8eb9SGleb Smirnoff 	}
57473b3a8eb9SGleb Smirnoff 	if (c == '\n') {
57483b3a8eb9SGleb Smirnoff 		yylval.lineno = file->lineno;
57493b3a8eb9SGleb Smirnoff 		file->lineno++;
57503b3a8eb9SGleb Smirnoff 	}
57513b3a8eb9SGleb Smirnoff 	if (c == EOF)
57523b3a8eb9SGleb Smirnoff 		return (0);
57533b3a8eb9SGleb Smirnoff 	return (c);
57543b3a8eb9SGleb Smirnoff }
57553b3a8eb9SGleb Smirnoff 
57563b3a8eb9SGleb Smirnoff int
57573b3a8eb9SGleb Smirnoff check_file_secrecy(int fd, const char *fname)
57583b3a8eb9SGleb Smirnoff {
57593b3a8eb9SGleb Smirnoff 	struct stat	st;
57603b3a8eb9SGleb Smirnoff 
57613b3a8eb9SGleb Smirnoff 	if (fstat(fd, &st)) {
57623b3a8eb9SGleb Smirnoff 		warn("cannot stat %s", fname);
57633b3a8eb9SGleb Smirnoff 		return (-1);
57643b3a8eb9SGleb Smirnoff 	}
57653b3a8eb9SGleb Smirnoff 	if (st.st_uid != 0 && st.st_uid != getuid()) {
57663b3a8eb9SGleb Smirnoff 		warnx("%s: owner not root or current user", fname);
57673b3a8eb9SGleb Smirnoff 		return (-1);
57683b3a8eb9SGleb Smirnoff 	}
57693b3a8eb9SGleb Smirnoff 	if (st.st_mode & (S_IRWXG | S_IRWXO)) {
57703b3a8eb9SGleb Smirnoff 		warnx("%s: group/world readable/writeable", fname);
57713b3a8eb9SGleb Smirnoff 		return (-1);
57723b3a8eb9SGleb Smirnoff 	}
57733b3a8eb9SGleb Smirnoff 	return (0);
57743b3a8eb9SGleb Smirnoff }
57753b3a8eb9SGleb Smirnoff 
57763b3a8eb9SGleb Smirnoff struct file *
57773b3a8eb9SGleb Smirnoff pushfile(const char *name, int secret)
57783b3a8eb9SGleb Smirnoff {
57793b3a8eb9SGleb Smirnoff 	struct file	*nfile;
57803b3a8eb9SGleb Smirnoff 
57813b3a8eb9SGleb Smirnoff 	if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
57823b3a8eb9SGleb Smirnoff 	    (nfile->name = strdup(name)) == NULL) {
57833b3a8eb9SGleb Smirnoff 		warn("malloc");
57843b3a8eb9SGleb Smirnoff 		return (NULL);
57853b3a8eb9SGleb Smirnoff 	}
57863b3a8eb9SGleb Smirnoff 	if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
57873b3a8eb9SGleb Smirnoff 		nfile->stream = stdin;
57883b3a8eb9SGleb Smirnoff 		free(nfile->name);
57893b3a8eb9SGleb Smirnoff 		if ((nfile->name = strdup("stdin")) == NULL) {
57903b3a8eb9SGleb Smirnoff 			warn("strdup");
57913b3a8eb9SGleb Smirnoff 			free(nfile);
57923b3a8eb9SGleb Smirnoff 			return (NULL);
57933b3a8eb9SGleb Smirnoff 		}
57943b3a8eb9SGleb Smirnoff 	} else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
57953b3a8eb9SGleb Smirnoff 		warn("%s", nfile->name);
57963b3a8eb9SGleb Smirnoff 		free(nfile->name);
57973b3a8eb9SGleb Smirnoff 		free(nfile);
57983b3a8eb9SGleb Smirnoff 		return (NULL);
57993b3a8eb9SGleb Smirnoff 	} else if (secret &&
58003b3a8eb9SGleb Smirnoff 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
58013b3a8eb9SGleb Smirnoff 		fclose(nfile->stream);
58023b3a8eb9SGleb Smirnoff 		free(nfile->name);
58033b3a8eb9SGleb Smirnoff 		free(nfile);
58043b3a8eb9SGleb Smirnoff 		return (NULL);
58053b3a8eb9SGleb Smirnoff 	}
58063b3a8eb9SGleb Smirnoff 	nfile->lineno = 1;
58073b3a8eb9SGleb Smirnoff 	TAILQ_INSERT_TAIL(&files, nfile, entry);
58083b3a8eb9SGleb Smirnoff 	return (nfile);
58093b3a8eb9SGleb Smirnoff }
58103b3a8eb9SGleb Smirnoff 
58113b3a8eb9SGleb Smirnoff int
58123b3a8eb9SGleb Smirnoff popfile(void)
58133b3a8eb9SGleb Smirnoff {
58143b3a8eb9SGleb Smirnoff 	struct file	*prev;
58153b3a8eb9SGleb Smirnoff 
58163b3a8eb9SGleb Smirnoff 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
58173b3a8eb9SGleb Smirnoff 		prev->errors += file->errors;
58183b3a8eb9SGleb Smirnoff 		TAILQ_REMOVE(&files, file, entry);
58193b3a8eb9SGleb Smirnoff 		fclose(file->stream);
58203b3a8eb9SGleb Smirnoff 		free(file->name);
58213b3a8eb9SGleb Smirnoff 		free(file);
58223b3a8eb9SGleb Smirnoff 		file = prev;
58233b3a8eb9SGleb Smirnoff 		return (0);
58243b3a8eb9SGleb Smirnoff 	}
58253b3a8eb9SGleb Smirnoff 	return (EOF);
58263b3a8eb9SGleb Smirnoff }
58273b3a8eb9SGleb Smirnoff 
58283b3a8eb9SGleb Smirnoff int
58293b3a8eb9SGleb Smirnoff parse_config(char *filename, struct pfctl *xpf)
58303b3a8eb9SGleb Smirnoff {
58313b3a8eb9SGleb Smirnoff 	int		 errors = 0;
58323b3a8eb9SGleb Smirnoff 	struct sym	*sym;
58333b3a8eb9SGleb Smirnoff 
58343b3a8eb9SGleb Smirnoff 	pf = xpf;
58353b3a8eb9SGleb Smirnoff 	errors = 0;
58363b3a8eb9SGleb Smirnoff 	rulestate = PFCTL_STATE_NONE;
58373b3a8eb9SGleb Smirnoff 	returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
58383b3a8eb9SGleb Smirnoff 	returnicmp6default =
58393b3a8eb9SGleb Smirnoff 	    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
58403b3a8eb9SGleb Smirnoff 	blockpolicy = PFRULE_DROP;
58413b3a8eb9SGleb Smirnoff 	require_order = 1;
58423b3a8eb9SGleb Smirnoff 
58433b3a8eb9SGleb Smirnoff 	if ((file = pushfile(filename, 0)) == NULL) {
58443b3a8eb9SGleb Smirnoff 		warn("cannot open the main config file!");
58453b3a8eb9SGleb Smirnoff 		return (-1);
58463b3a8eb9SGleb Smirnoff 	}
58473b3a8eb9SGleb Smirnoff 
58483b3a8eb9SGleb Smirnoff 	yyparse();
58493b3a8eb9SGleb Smirnoff 	errors = file->errors;
58503b3a8eb9SGleb Smirnoff 	popfile();
58513b3a8eb9SGleb Smirnoff 
58523b3a8eb9SGleb Smirnoff 	/* Free macros and check which have not been used. */
58533b3a8eb9SGleb Smirnoff 	while ((sym = TAILQ_FIRST(&symhead))) {
58543b3a8eb9SGleb Smirnoff 		if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
58553b3a8eb9SGleb Smirnoff 			fprintf(stderr, "warning: macro '%s' not "
58563b3a8eb9SGleb Smirnoff 			    "used\n", sym->nam);
58573b3a8eb9SGleb Smirnoff 		free(sym->nam);
58583b3a8eb9SGleb Smirnoff 		free(sym->val);
58593b3a8eb9SGleb Smirnoff 		TAILQ_REMOVE(&symhead, sym, entry);
58603b3a8eb9SGleb Smirnoff 		free(sym);
58613b3a8eb9SGleb Smirnoff 	}
58623b3a8eb9SGleb Smirnoff 
58633b3a8eb9SGleb Smirnoff 	return (errors ? -1 : 0);
58643b3a8eb9SGleb Smirnoff }
58653b3a8eb9SGleb Smirnoff 
58663b3a8eb9SGleb Smirnoff int
58673b3a8eb9SGleb Smirnoff symset(const char *nam, const char *val, int persist)
58683b3a8eb9SGleb Smirnoff {
58693b3a8eb9SGleb Smirnoff 	struct sym	*sym;
58703b3a8eb9SGleb Smirnoff 
58713b3a8eb9SGleb Smirnoff 	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
58723b3a8eb9SGleb Smirnoff 	    sym = TAILQ_NEXT(sym, entry))
58733b3a8eb9SGleb Smirnoff 		;	/* nothing */
58743b3a8eb9SGleb Smirnoff 
58753b3a8eb9SGleb Smirnoff 	if (sym != NULL) {
58763b3a8eb9SGleb Smirnoff 		if (sym->persist == 1)
58773b3a8eb9SGleb Smirnoff 			return (0);
58783b3a8eb9SGleb Smirnoff 		else {
58793b3a8eb9SGleb Smirnoff 			free(sym->nam);
58803b3a8eb9SGleb Smirnoff 			free(sym->val);
58813b3a8eb9SGleb Smirnoff 			TAILQ_REMOVE(&symhead, sym, entry);
58823b3a8eb9SGleb Smirnoff 			free(sym);
58833b3a8eb9SGleb Smirnoff 		}
58843b3a8eb9SGleb Smirnoff 	}
58853b3a8eb9SGleb Smirnoff 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
58863b3a8eb9SGleb Smirnoff 		return (-1);
58873b3a8eb9SGleb Smirnoff 
58883b3a8eb9SGleb Smirnoff 	sym->nam = strdup(nam);
58893b3a8eb9SGleb Smirnoff 	if (sym->nam == NULL) {
58903b3a8eb9SGleb Smirnoff 		free(sym);
58913b3a8eb9SGleb Smirnoff 		return (-1);
58923b3a8eb9SGleb Smirnoff 	}
58933b3a8eb9SGleb Smirnoff 	sym->val = strdup(val);
58943b3a8eb9SGleb Smirnoff 	if (sym->val == NULL) {
58953b3a8eb9SGleb Smirnoff 		free(sym->nam);
58963b3a8eb9SGleb Smirnoff 		free(sym);
58973b3a8eb9SGleb Smirnoff 		return (-1);
58983b3a8eb9SGleb Smirnoff 	}
58993b3a8eb9SGleb Smirnoff 	sym->used = 0;
59003b3a8eb9SGleb Smirnoff 	sym->persist = persist;
59013b3a8eb9SGleb Smirnoff 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
59023b3a8eb9SGleb Smirnoff 	return (0);
59033b3a8eb9SGleb Smirnoff }
59043b3a8eb9SGleb Smirnoff 
59053b3a8eb9SGleb Smirnoff int
59063b3a8eb9SGleb Smirnoff pfctl_cmdline_symset(char *s)
59073b3a8eb9SGleb Smirnoff {
59083b3a8eb9SGleb Smirnoff 	char	*sym, *val;
59093b3a8eb9SGleb Smirnoff 	int	 ret;
59103b3a8eb9SGleb Smirnoff 
59113b3a8eb9SGleb Smirnoff 	if ((val = strrchr(s, '=')) == NULL)
59123b3a8eb9SGleb Smirnoff 		return (-1);
59133b3a8eb9SGleb Smirnoff 
59143b3a8eb9SGleb Smirnoff 	if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
59153b3a8eb9SGleb Smirnoff 		err(1, "pfctl_cmdline_symset: malloc");
59163b3a8eb9SGleb Smirnoff 
59173b3a8eb9SGleb Smirnoff 	strlcpy(sym, s, strlen(s) - strlen(val) + 1);
59183b3a8eb9SGleb Smirnoff 
59193b3a8eb9SGleb Smirnoff 	ret = symset(sym, val + 1, 1);
59203b3a8eb9SGleb Smirnoff 	free(sym);
59213b3a8eb9SGleb Smirnoff 
59223b3a8eb9SGleb Smirnoff 	return (ret);
59233b3a8eb9SGleb Smirnoff }
59243b3a8eb9SGleb Smirnoff 
59253b3a8eb9SGleb Smirnoff char *
59263b3a8eb9SGleb Smirnoff symget(const char *nam)
59273b3a8eb9SGleb Smirnoff {
59283b3a8eb9SGleb Smirnoff 	struct sym	*sym;
59293b3a8eb9SGleb Smirnoff 
59303b3a8eb9SGleb Smirnoff 	TAILQ_FOREACH(sym, &symhead, entry)
59313b3a8eb9SGleb Smirnoff 		if (strcmp(nam, sym->nam) == 0) {
59323b3a8eb9SGleb Smirnoff 			sym->used = 1;
59333b3a8eb9SGleb Smirnoff 			return (sym->val);
59343b3a8eb9SGleb Smirnoff 		}
59353b3a8eb9SGleb Smirnoff 	return (NULL);
59363b3a8eb9SGleb Smirnoff }
59373b3a8eb9SGleb Smirnoff 
59383b3a8eb9SGleb Smirnoff void
59393b3a8eb9SGleb Smirnoff mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
59403b3a8eb9SGleb Smirnoff {
59413b3a8eb9SGleb Smirnoff 	int i;
59423b3a8eb9SGleb Smirnoff 	struct pf_rule *r;
59433b3a8eb9SGleb Smirnoff 
59443b3a8eb9SGleb Smirnoff 	for (i = 0; i < PF_RULESET_MAX; ++i) {
59453b3a8eb9SGleb Smirnoff 		while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
59463b3a8eb9SGleb Smirnoff 		    != NULL) {
59473b3a8eb9SGleb Smirnoff 			TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
59483b3a8eb9SGleb Smirnoff 			TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
59493b3a8eb9SGleb Smirnoff 			dst->anchor->match++;
59503b3a8eb9SGleb Smirnoff 		}
59513b3a8eb9SGleb Smirnoff 		src->anchor->match = 0;
59523b3a8eb9SGleb Smirnoff 		while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
59533b3a8eb9SGleb Smirnoff 		    != NULL) {
59543b3a8eb9SGleb Smirnoff 			TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
59553b3a8eb9SGleb Smirnoff 			TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
59563b3a8eb9SGleb Smirnoff 				r, entries);
59573b3a8eb9SGleb Smirnoff 		}
59583b3a8eb9SGleb Smirnoff 	}
59593b3a8eb9SGleb Smirnoff }
59603b3a8eb9SGleb Smirnoff 
59613b3a8eb9SGleb Smirnoff void
59623b3a8eb9SGleb Smirnoff decide_address_family(struct node_host *n, sa_family_t *af)
59633b3a8eb9SGleb Smirnoff {
59643b3a8eb9SGleb Smirnoff 	if (*af != 0 || n == NULL)
59653b3a8eb9SGleb Smirnoff 		return;
59663b3a8eb9SGleb Smirnoff 	*af = n->af;
59673b3a8eb9SGleb Smirnoff 	while ((n = n->next) != NULL) {
59683b3a8eb9SGleb Smirnoff 		if (n->af != *af) {
59693b3a8eb9SGleb Smirnoff 			*af = 0;
59703b3a8eb9SGleb Smirnoff 			return;
59713b3a8eb9SGleb Smirnoff 		}
59723b3a8eb9SGleb Smirnoff 	}
59733b3a8eb9SGleb Smirnoff }
59743b3a8eb9SGleb Smirnoff 
59753b3a8eb9SGleb Smirnoff void
59763b3a8eb9SGleb Smirnoff remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
59773b3a8eb9SGleb Smirnoff {
59783b3a8eb9SGleb Smirnoff 	struct node_host	*n = *nh, *prev = NULL;
59793b3a8eb9SGleb Smirnoff 
59803b3a8eb9SGleb Smirnoff 	while (n != NULL) {
59813b3a8eb9SGleb Smirnoff 		if (*af && n->af && n->af != *af) {
59823b3a8eb9SGleb Smirnoff 			/* unlink and free n */
59833b3a8eb9SGleb Smirnoff 			struct node_host *next = n->next;
59843b3a8eb9SGleb Smirnoff 
59853b3a8eb9SGleb Smirnoff 			/* adjust tail pointer */
59863b3a8eb9SGleb Smirnoff 			if (n == (*nh)->tail)
59873b3a8eb9SGleb Smirnoff 				(*nh)->tail = prev;
59883b3a8eb9SGleb Smirnoff 			/* adjust previous node's next pointer */
59893b3a8eb9SGleb Smirnoff 			if (prev == NULL)
59903b3a8eb9SGleb Smirnoff 				*nh = next;
59913b3a8eb9SGleb Smirnoff 			else
59923b3a8eb9SGleb Smirnoff 				prev->next = next;
59933b3a8eb9SGleb Smirnoff 			/* free node */
59943b3a8eb9SGleb Smirnoff 			if (n->ifname != NULL)
59953b3a8eb9SGleb Smirnoff 				free(n->ifname);
59963b3a8eb9SGleb Smirnoff 			free(n);
59973b3a8eb9SGleb Smirnoff 			n = next;
59983b3a8eb9SGleb Smirnoff 		} else {
59993b3a8eb9SGleb Smirnoff 			if (n->af && !*af)
60003b3a8eb9SGleb Smirnoff 				*af = n->af;
60013b3a8eb9SGleb Smirnoff 			prev = n;
60023b3a8eb9SGleb Smirnoff 			n = n->next;
60033b3a8eb9SGleb Smirnoff 		}
60043b3a8eb9SGleb Smirnoff 	}
60053b3a8eb9SGleb Smirnoff }
60063b3a8eb9SGleb Smirnoff 
60073b3a8eb9SGleb Smirnoff int
60083b3a8eb9SGleb Smirnoff invalid_redirect(struct node_host *nh, sa_family_t af)
60093b3a8eb9SGleb Smirnoff {
60103b3a8eb9SGleb Smirnoff 	if (!af) {
60113b3a8eb9SGleb Smirnoff 		struct node_host *n;
60123b3a8eb9SGleb Smirnoff 
60133b3a8eb9SGleb Smirnoff 		/* tables and dyniftl are ok without an address family */
60143b3a8eb9SGleb Smirnoff 		for (n = nh; n != NULL; n = n->next) {
60153b3a8eb9SGleb Smirnoff 			if (n->addr.type != PF_ADDR_TABLE &&
60163b3a8eb9SGleb Smirnoff 			    n->addr.type != PF_ADDR_DYNIFTL) {
60173b3a8eb9SGleb Smirnoff 				yyerror("address family not given and "
60183b3a8eb9SGleb Smirnoff 				    "translation address expands to multiple "
60193b3a8eb9SGleb Smirnoff 				    "address families");
60203b3a8eb9SGleb Smirnoff 				return (1);
60213b3a8eb9SGleb Smirnoff 			}
60223b3a8eb9SGleb Smirnoff 		}
60233b3a8eb9SGleb Smirnoff 	}
60243b3a8eb9SGleb Smirnoff 	if (nh == NULL) {
60253b3a8eb9SGleb Smirnoff 		yyerror("no translation address with matching address family "
60263b3a8eb9SGleb Smirnoff 		    "found.");
60273b3a8eb9SGleb Smirnoff 		return (1);
60283b3a8eb9SGleb Smirnoff 	}
60293b3a8eb9SGleb Smirnoff 	return (0);
60303b3a8eb9SGleb Smirnoff }
60313b3a8eb9SGleb Smirnoff 
60323b3a8eb9SGleb Smirnoff int
60333b3a8eb9SGleb Smirnoff atoul(char *s, u_long *ulvalp)
60343b3a8eb9SGleb Smirnoff {
60353b3a8eb9SGleb Smirnoff 	u_long	 ulval;
60363b3a8eb9SGleb Smirnoff 	char	*ep;
60373b3a8eb9SGleb Smirnoff 
60383b3a8eb9SGleb Smirnoff 	errno = 0;
60393b3a8eb9SGleb Smirnoff 	ulval = strtoul(s, &ep, 0);
60403b3a8eb9SGleb Smirnoff 	if (s[0] == '\0' || *ep != '\0')
60413b3a8eb9SGleb Smirnoff 		return (-1);
60423b3a8eb9SGleb Smirnoff 	if (errno == ERANGE && ulval == ULONG_MAX)
60433b3a8eb9SGleb Smirnoff 		return (-1);
60443b3a8eb9SGleb Smirnoff 	*ulvalp = ulval;
60453b3a8eb9SGleb Smirnoff 	return (0);
60463b3a8eb9SGleb Smirnoff }
60473b3a8eb9SGleb Smirnoff 
60483b3a8eb9SGleb Smirnoff int
60493b3a8eb9SGleb Smirnoff getservice(char *n)
60503b3a8eb9SGleb Smirnoff {
60513b3a8eb9SGleb Smirnoff 	struct servent	*s;
60523b3a8eb9SGleb Smirnoff 	u_long		 ulval;
60533b3a8eb9SGleb Smirnoff 
60543b3a8eb9SGleb Smirnoff 	if (atoul(n, &ulval) == 0) {
60553b3a8eb9SGleb Smirnoff 		if (ulval > 65535) {
60563b3a8eb9SGleb Smirnoff 			yyerror("illegal port value %lu", ulval);
60573b3a8eb9SGleb Smirnoff 			return (-1);
60583b3a8eb9SGleb Smirnoff 		}
60593b3a8eb9SGleb Smirnoff 		return (htons(ulval));
60603b3a8eb9SGleb Smirnoff 	} else {
60613b3a8eb9SGleb Smirnoff 		s = getservbyname(n, "tcp");
60623b3a8eb9SGleb Smirnoff 		if (s == NULL)
60633b3a8eb9SGleb Smirnoff 			s = getservbyname(n, "udp");
60643b3a8eb9SGleb Smirnoff 		if (s == NULL) {
60653b3a8eb9SGleb Smirnoff 			yyerror("unknown port %s", n);
60663b3a8eb9SGleb Smirnoff 			return (-1);
60673b3a8eb9SGleb Smirnoff 		}
60683b3a8eb9SGleb Smirnoff 		return (s->s_port);
60693b3a8eb9SGleb Smirnoff 	}
60703b3a8eb9SGleb Smirnoff }
60713b3a8eb9SGleb Smirnoff 
60723b3a8eb9SGleb Smirnoff int
60733b3a8eb9SGleb Smirnoff rule_label(struct pf_rule *r, char *s)
60743b3a8eb9SGleb Smirnoff {
60753b3a8eb9SGleb Smirnoff 	if (s) {
60763b3a8eb9SGleb Smirnoff 		if (strlcpy(r->label, s, sizeof(r->label)) >=
60773b3a8eb9SGleb Smirnoff 		    sizeof(r->label)) {
60783b3a8eb9SGleb Smirnoff 			yyerror("rule label too long (max %d chars)",
60793b3a8eb9SGleb Smirnoff 			    sizeof(r->label)-1);
60803b3a8eb9SGleb Smirnoff 			return (-1);
60813b3a8eb9SGleb Smirnoff 		}
60823b3a8eb9SGleb Smirnoff 	}
60833b3a8eb9SGleb Smirnoff 	return (0);
60843b3a8eb9SGleb Smirnoff }
60853b3a8eb9SGleb Smirnoff 
60863b3a8eb9SGleb Smirnoff u_int16_t
60873b3a8eb9SGleb Smirnoff parseicmpspec(char *w, sa_family_t af)
60883b3a8eb9SGleb Smirnoff {
60893b3a8eb9SGleb Smirnoff 	const struct icmpcodeent	*p;
60903b3a8eb9SGleb Smirnoff 	u_long				 ulval;
60913b3a8eb9SGleb Smirnoff 	u_int8_t			 icmptype;
60923b3a8eb9SGleb Smirnoff 
60933b3a8eb9SGleb Smirnoff 	if (af == AF_INET)
60943b3a8eb9SGleb Smirnoff 		icmptype = returnicmpdefault >> 8;
60953b3a8eb9SGleb Smirnoff 	else
60963b3a8eb9SGleb Smirnoff 		icmptype = returnicmp6default >> 8;
60973b3a8eb9SGleb Smirnoff 
60983b3a8eb9SGleb Smirnoff 	if (atoul(w, &ulval) == -1) {
60993b3a8eb9SGleb Smirnoff 		if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
61003b3a8eb9SGleb Smirnoff 			yyerror("unknown icmp code %s", w);
61013b3a8eb9SGleb Smirnoff 			return (0);
61023b3a8eb9SGleb Smirnoff 		}
61033b3a8eb9SGleb Smirnoff 		ulval = p->code;
61043b3a8eb9SGleb Smirnoff 	}
61053b3a8eb9SGleb Smirnoff 	if (ulval > 255) {
61063b3a8eb9SGleb Smirnoff 		yyerror("invalid icmp code %lu", ulval);
61073b3a8eb9SGleb Smirnoff 		return (0);
61083b3a8eb9SGleb Smirnoff 	}
61093b3a8eb9SGleb Smirnoff 	return (icmptype << 8 | ulval);
61103b3a8eb9SGleb Smirnoff }
61113b3a8eb9SGleb Smirnoff 
61123b3a8eb9SGleb Smirnoff int
61133b3a8eb9SGleb Smirnoff parseport(char *port, struct range *r, int extensions)
61143b3a8eb9SGleb Smirnoff {
61153b3a8eb9SGleb Smirnoff 	char	*p = strchr(port, ':');
61163b3a8eb9SGleb Smirnoff 
61173b3a8eb9SGleb Smirnoff 	if (p == NULL) {
61183b3a8eb9SGleb Smirnoff 		if ((r->a = getservice(port)) == -1)
61193b3a8eb9SGleb Smirnoff 			return (-1);
61203b3a8eb9SGleb Smirnoff 		r->b = 0;
61213b3a8eb9SGleb Smirnoff 		r->t = PF_OP_NONE;
61223b3a8eb9SGleb Smirnoff 		return (0);
61233b3a8eb9SGleb Smirnoff 	}
61243b3a8eb9SGleb Smirnoff 	if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
61253b3a8eb9SGleb Smirnoff 		*p = 0;
61263b3a8eb9SGleb Smirnoff 		if ((r->a = getservice(port)) == -1)
61273b3a8eb9SGleb Smirnoff 			return (-1);
61283b3a8eb9SGleb Smirnoff 		r->b = 0;
61293b3a8eb9SGleb Smirnoff 		r->t = PF_OP_IRG;
61303b3a8eb9SGleb Smirnoff 		return (0);
61313b3a8eb9SGleb Smirnoff 	}
61323b3a8eb9SGleb Smirnoff 	if ((extensions & PPORT_RANGE)) {
61333b3a8eb9SGleb Smirnoff 		*p++ = 0;
61343b3a8eb9SGleb Smirnoff 		if ((r->a = getservice(port)) == -1 ||
61353b3a8eb9SGleb Smirnoff 		    (r->b = getservice(p)) == -1)
61363b3a8eb9SGleb Smirnoff 			return (-1);
61373b3a8eb9SGleb Smirnoff 		if (r->a == r->b) {
61383b3a8eb9SGleb Smirnoff 			r->b = 0;
61393b3a8eb9SGleb Smirnoff 			r->t = PF_OP_NONE;
61403b3a8eb9SGleb Smirnoff 		} else
61413b3a8eb9SGleb Smirnoff 			r->t = PF_OP_RRG;
61423b3a8eb9SGleb Smirnoff 		return (0);
61433b3a8eb9SGleb Smirnoff 	}
61443b3a8eb9SGleb Smirnoff 	return (-1);
61453b3a8eb9SGleb Smirnoff }
61463b3a8eb9SGleb Smirnoff 
61473b3a8eb9SGleb Smirnoff int
61483b3a8eb9SGleb Smirnoff pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
61493b3a8eb9SGleb Smirnoff {
61503b3a8eb9SGleb Smirnoff 	struct loadanchors	*la;
61513b3a8eb9SGleb Smirnoff 
61523b3a8eb9SGleb Smirnoff 	TAILQ_FOREACH(la, &loadanchorshead, entries) {
61533b3a8eb9SGleb Smirnoff 		if (pf->opts & PF_OPT_VERBOSE)
61543b3a8eb9SGleb Smirnoff 			fprintf(stderr, "\nLoading anchor %s from %s\n",
61553b3a8eb9SGleb Smirnoff 			    la->anchorname, la->filename);
61563b3a8eb9SGleb Smirnoff 		if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
61573b3a8eb9SGleb Smirnoff 		    la->anchorname, trans) == -1)
61583b3a8eb9SGleb Smirnoff 			return (-1);
61593b3a8eb9SGleb Smirnoff 	}
61603b3a8eb9SGleb Smirnoff 
61613b3a8eb9SGleb Smirnoff 	return (0);
61623b3a8eb9SGleb Smirnoff }
61633b3a8eb9SGleb Smirnoff 
61643b3a8eb9SGleb Smirnoff int
61653b3a8eb9SGleb Smirnoff rt_tableid_max(void)
61663b3a8eb9SGleb Smirnoff {
61673b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
61683b3a8eb9SGleb Smirnoff 	int fibs;
61693b3a8eb9SGleb Smirnoff 	size_t l = sizeof(fibs);
61703b3a8eb9SGleb Smirnoff 
61713b3a8eb9SGleb Smirnoff         if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
61723b3a8eb9SGleb Smirnoff 		fibs = 16;	/* XXX RT_MAXFIBS, at least limit it some. */
61733b3a8eb9SGleb Smirnoff 	/*
61743b3a8eb9SGleb Smirnoff 	 * As the OpenBSD code only compares > and not >= we need to adjust
61753b3a8eb9SGleb Smirnoff 	 * here given we only accept values of 0..n and want to avoid #ifdefs
61763b3a8eb9SGleb Smirnoff 	 * in the grammer.
61773b3a8eb9SGleb Smirnoff 	 */
61783b3a8eb9SGleb Smirnoff 	return (fibs - 1);
61793b3a8eb9SGleb Smirnoff #else
61803b3a8eb9SGleb Smirnoff 	return (RT_TABLEID_MAX);
61813b3a8eb9SGleb Smirnoff #endif
61823b3a8eb9SGleb Smirnoff }
6183