xref: /freebsd/sbin/pfctl/parse.y (revision 71594e3235f21746fbc6c0b12ad70409db18a46b)
13b3a8eb9SGleb Smirnoff /*	$OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $	*/
23b3a8eb9SGleb Smirnoff 
31de7b4b8SPedro F. Giffuni /*-
41de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni  *
63b3a8eb9SGleb Smirnoff  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
73b3a8eb9SGleb Smirnoff  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
83b3a8eb9SGleb Smirnoff  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
93b3a8eb9SGleb Smirnoff  * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
103b3a8eb9SGleb Smirnoff  *
113b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
123b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
133b3a8eb9SGleb Smirnoff  * are met:
143b3a8eb9SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
153b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
163b3a8eb9SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
173b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
183b3a8eb9SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
193b3a8eb9SGleb Smirnoff  *
203b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
213b3a8eb9SGleb Smirnoff  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
223b3a8eb9SGleb Smirnoff  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
233b3a8eb9SGleb Smirnoff  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
243b3a8eb9SGleb Smirnoff  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
253b3a8eb9SGleb Smirnoff  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
263b3a8eb9SGleb Smirnoff  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
273b3a8eb9SGleb Smirnoff  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
283b3a8eb9SGleb Smirnoff  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
293b3a8eb9SGleb Smirnoff  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
303b3a8eb9SGleb Smirnoff  */
313b3a8eb9SGleb Smirnoff %{
323b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
33249cc75fSPatrick Kelsey #define PFIOC_USE_LATEST
34249cc75fSPatrick Kelsey 
353b3a8eb9SGleb Smirnoff #include <sys/types.h>
363b3a8eb9SGleb Smirnoff #include <sys/socket.h>
373b3a8eb9SGleb Smirnoff #include <sys/stat.h>
383b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
393b3a8eb9SGleb Smirnoff #include <sys/sysctl.h>
403b3a8eb9SGleb Smirnoff #endif
413b3a8eb9SGleb Smirnoff #include <net/if.h>
423b3a8eb9SGleb Smirnoff #include <netinet/in.h>
433b3a8eb9SGleb Smirnoff #include <netinet/in_systm.h>
443b3a8eb9SGleb Smirnoff #include <netinet/ip.h>
453b3a8eb9SGleb Smirnoff #include <netinet/ip_icmp.h>
463b3a8eb9SGleb Smirnoff #include <netinet/icmp6.h>
473b3a8eb9SGleb Smirnoff #include <net/pfvar.h>
483b3a8eb9SGleb Smirnoff #include <arpa/inet.h>
49772e66a6SGleb Smirnoff #include <net/altq/altq.h>
50772e66a6SGleb Smirnoff #include <net/altq/altq_cbq.h>
510a70aaf8SLuiz Otavio O Souza #include <net/altq/altq_codel.h>
52772e66a6SGleb Smirnoff #include <net/altq/altq_priq.h>
53772e66a6SGleb Smirnoff #include <net/altq/altq_hfsc.h>
54a5b789f6SErmal Luçi #include <net/altq/altq_fairq.h>
553b3a8eb9SGleb Smirnoff 
566fcc8e04SKristof Provost #include <assert.h>
573b3a8eb9SGleb Smirnoff #include <stdio.h>
583b3a8eb9SGleb Smirnoff #include <unistd.h>
593b3a8eb9SGleb Smirnoff #include <stdlib.h>
603b3a8eb9SGleb Smirnoff #include <netdb.h>
613b3a8eb9SGleb Smirnoff #include <stdarg.h>
623b3a8eb9SGleb Smirnoff #include <errno.h>
633b3a8eb9SGleb Smirnoff #include <string.h>
643b3a8eb9SGleb Smirnoff #include <ctype.h>
653b3a8eb9SGleb Smirnoff #include <math.h>
663b3a8eb9SGleb Smirnoff #include <err.h>
673b3a8eb9SGleb Smirnoff #include <limits.h>
683b3a8eb9SGleb Smirnoff #include <pwd.h>
693b3a8eb9SGleb Smirnoff #include <grp.h>
703b3a8eb9SGleb Smirnoff #include <md5.h>
713b3a8eb9SGleb Smirnoff 
723b3a8eb9SGleb Smirnoff #include "pfctl_parser.h"
733b3a8eb9SGleb Smirnoff #include "pfctl.h"
743b3a8eb9SGleb Smirnoff 
753b3a8eb9SGleb Smirnoff static struct pfctl	*pf = NULL;
763b3a8eb9SGleb Smirnoff static int		 debug = 0;
773b3a8eb9SGleb Smirnoff static int		 rulestate = 0;
783b3a8eb9SGleb Smirnoff static u_int16_t	 returnicmpdefault =
793b3a8eb9SGleb Smirnoff 			    (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
803b3a8eb9SGleb Smirnoff static u_int16_t	 returnicmp6default =
813b3a8eb9SGleb Smirnoff 			    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
823b3a8eb9SGleb Smirnoff static int		 blockpolicy = PFRULE_DROP;
83150182e3SKristof Provost static int		 failpolicy = PFRULE_DROP;
843b3a8eb9SGleb Smirnoff static int		 require_order = 1;
853b3a8eb9SGleb Smirnoff static int		 default_statelock;
863b3a8eb9SGleb Smirnoff 
8713cfafabSKristof Provost static TAILQ_HEAD(files, file)	 files = TAILQ_HEAD_INITIALIZER(files);
883b3a8eb9SGleb Smirnoff static struct file {
893b3a8eb9SGleb Smirnoff 	TAILQ_ENTRY(file)	 entry;
903b3a8eb9SGleb Smirnoff 	FILE			*stream;
913b3a8eb9SGleb Smirnoff 	char			*name;
923b3a8eb9SGleb Smirnoff 	int			 lineno;
933b3a8eb9SGleb Smirnoff 	int			 errors;
943b3a8eb9SGleb Smirnoff } *file;
953b3a8eb9SGleb Smirnoff struct file	*pushfile(const char *, int);
963b3a8eb9SGleb Smirnoff int		 popfile(void);
973b3a8eb9SGleb Smirnoff int		 check_file_secrecy(int, const char *);
983b3a8eb9SGleb Smirnoff int		 yyparse(void);
993b3a8eb9SGleb Smirnoff int		 yylex(void);
1003b3a8eb9SGleb Smirnoff int		 yyerror(const char *, ...);
1013b3a8eb9SGleb Smirnoff int		 kw_cmp(const void *, const void *);
1023b3a8eb9SGleb Smirnoff int		 lookup(char *);
1033b3a8eb9SGleb Smirnoff int		 lgetc(int);
1043b3a8eb9SGleb Smirnoff int		 lungetc(int);
1053b3a8eb9SGleb Smirnoff int		 findeol(void);
1063b3a8eb9SGleb Smirnoff 
10713cfafabSKristof Provost static TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
1083b3a8eb9SGleb Smirnoff struct sym {
1093b3a8eb9SGleb Smirnoff 	TAILQ_ENTRY(sym)	 entry;
1103b3a8eb9SGleb Smirnoff 	int			 used;
1113b3a8eb9SGleb Smirnoff 	int			 persist;
1123b3a8eb9SGleb Smirnoff 	char			*nam;
1133b3a8eb9SGleb Smirnoff 	char			*val;
1143b3a8eb9SGleb Smirnoff };
1153b3a8eb9SGleb Smirnoff int		 symset(const char *, const char *, int);
1163b3a8eb9SGleb Smirnoff char		*symget(const char *);
1173b3a8eb9SGleb Smirnoff 
1183b3a8eb9SGleb Smirnoff int		 atoul(char *, u_long *);
1193b3a8eb9SGleb Smirnoff 
1203b3a8eb9SGleb Smirnoff enum {
1213b3a8eb9SGleb Smirnoff 	PFCTL_STATE_NONE,
1223b3a8eb9SGleb Smirnoff 	PFCTL_STATE_OPTION,
1232b29ceb8SKristof Provost 	PFCTL_STATE_ETHER,
1243b3a8eb9SGleb Smirnoff 	PFCTL_STATE_SCRUB,
1253b3a8eb9SGleb Smirnoff 	PFCTL_STATE_QUEUE,
1263b3a8eb9SGleb Smirnoff 	PFCTL_STATE_NAT,
1273b3a8eb9SGleb Smirnoff 	PFCTL_STATE_FILTER
1283b3a8eb9SGleb Smirnoff };
1293b3a8eb9SGleb Smirnoff 
1302b29ceb8SKristof Provost struct node_etherproto {
1312b29ceb8SKristof Provost 	u_int16_t		 proto;
1322b29ceb8SKristof Provost 	struct node_etherproto	*next;
1332b29ceb8SKristof Provost 	struct node_etherproto	*tail;
1342b29ceb8SKristof Provost };
1352b29ceb8SKristof Provost 
1363b3a8eb9SGleb Smirnoff struct node_proto {
1373b3a8eb9SGleb Smirnoff 	u_int8_t		 proto;
1383b3a8eb9SGleb Smirnoff 	struct node_proto	*next;
1393b3a8eb9SGleb Smirnoff 	struct node_proto	*tail;
1403b3a8eb9SGleb Smirnoff };
1413b3a8eb9SGleb Smirnoff 
1423b3a8eb9SGleb Smirnoff struct node_port {
1433b3a8eb9SGleb Smirnoff 	u_int16_t		 port[2];
1443b3a8eb9SGleb Smirnoff 	u_int8_t		 op;
1453b3a8eb9SGleb Smirnoff 	struct node_port	*next;
1463b3a8eb9SGleb Smirnoff 	struct node_port	*tail;
1473b3a8eb9SGleb Smirnoff };
1483b3a8eb9SGleb Smirnoff 
1493b3a8eb9SGleb Smirnoff struct node_uid {
1503b3a8eb9SGleb Smirnoff 	uid_t			 uid[2];
1513b3a8eb9SGleb Smirnoff 	u_int8_t		 op;
1523b3a8eb9SGleb Smirnoff 	struct node_uid		*next;
1533b3a8eb9SGleb Smirnoff 	struct node_uid		*tail;
1543b3a8eb9SGleb Smirnoff };
1553b3a8eb9SGleb Smirnoff 
1563b3a8eb9SGleb Smirnoff struct node_gid {
1573b3a8eb9SGleb Smirnoff 	gid_t			 gid[2];
1583b3a8eb9SGleb Smirnoff 	u_int8_t		 op;
1593b3a8eb9SGleb Smirnoff 	struct node_gid		*next;
1603b3a8eb9SGleb Smirnoff 	struct node_gid		*tail;
1613b3a8eb9SGleb Smirnoff };
1623b3a8eb9SGleb Smirnoff 
1633b3a8eb9SGleb Smirnoff struct node_icmp {
1643b3a8eb9SGleb Smirnoff 	u_int8_t		 code;
1653b3a8eb9SGleb Smirnoff 	u_int8_t		 type;
1663b3a8eb9SGleb Smirnoff 	u_int8_t		 proto;
1673b3a8eb9SGleb Smirnoff 	struct node_icmp	*next;
1683b3a8eb9SGleb Smirnoff 	struct node_icmp	*tail;
1693b3a8eb9SGleb Smirnoff };
1703b3a8eb9SGleb Smirnoff 
1713b3a8eb9SGleb Smirnoff enum	{ PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
1723b3a8eb9SGleb Smirnoff 	    PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
1733b3a8eb9SGleb Smirnoff 	    PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
1743b3a8eb9SGleb Smirnoff 	    PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
175baf9b6d0SKristof Provost 	    PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY,
176e4f2733dSKristof Provost 	    PF_STATE_OPT_PFLOW, PF_STATE_OPT_ALLOW_RELATED };
1773b3a8eb9SGleb Smirnoff 
1783b3a8eb9SGleb Smirnoff enum	{ PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
1793b3a8eb9SGleb Smirnoff 
1803b3a8eb9SGleb Smirnoff struct node_state_opt {
1813b3a8eb9SGleb Smirnoff 	int			 type;
1823b3a8eb9SGleb Smirnoff 	union {
1833b3a8eb9SGleb Smirnoff 		u_int32_t	 max_states;
1843b3a8eb9SGleb Smirnoff 		u_int32_t	 max_src_states;
1853b3a8eb9SGleb Smirnoff 		u_int32_t	 max_src_conn;
1863b3a8eb9SGleb Smirnoff 		struct {
1873b3a8eb9SGleb Smirnoff 			u_int32_t	limit;
1883b3a8eb9SGleb Smirnoff 			u_int32_t	seconds;
1893b3a8eb9SGleb Smirnoff 		}		 max_src_conn_rate;
1903b3a8eb9SGleb Smirnoff 		struct {
1913b3a8eb9SGleb Smirnoff 			u_int8_t	flush;
1923b3a8eb9SGleb Smirnoff 			char		tblname[PF_TABLE_NAME_SIZE];
1933b3a8eb9SGleb Smirnoff 		}		 overload;
1943b3a8eb9SGleb Smirnoff 		u_int32_t	 max_src_nodes;
1953b3a8eb9SGleb Smirnoff 		u_int8_t	 src_track;
1963b3a8eb9SGleb Smirnoff 		u_int32_t	 statelock;
1973b3a8eb9SGleb Smirnoff 		struct {
1983b3a8eb9SGleb Smirnoff 			int		number;
1993b3a8eb9SGleb Smirnoff 			u_int32_t	seconds;
2003b3a8eb9SGleb Smirnoff 		}		 timeout;
2013b3a8eb9SGleb Smirnoff 	}			 data;
2023b3a8eb9SGleb Smirnoff 	struct node_state_opt	*next;
2033b3a8eb9SGleb Smirnoff 	struct node_state_opt	*tail;
2043b3a8eb9SGleb Smirnoff };
2053b3a8eb9SGleb Smirnoff 
2063b3a8eb9SGleb Smirnoff struct peer {
2073b3a8eb9SGleb Smirnoff 	struct node_host	*host;
2083b3a8eb9SGleb Smirnoff 	struct node_port	*port;
2093b3a8eb9SGleb Smirnoff };
2103b3a8eb9SGleb Smirnoff 
21113cfafabSKristof Provost static struct node_queue {
2123b3a8eb9SGleb Smirnoff 	char			 queue[PF_QNAME_SIZE];
2133b3a8eb9SGleb Smirnoff 	char			 parent[PF_QNAME_SIZE];
2143b3a8eb9SGleb Smirnoff 	char			 ifname[IFNAMSIZ];
2153b3a8eb9SGleb Smirnoff 	int			 scheduler;
2163b3a8eb9SGleb Smirnoff 	struct node_queue	*next;
2173b3a8eb9SGleb Smirnoff 	struct node_queue	*tail;
2183b3a8eb9SGleb Smirnoff }	*queues = NULL;
2193b3a8eb9SGleb Smirnoff 
2203b3a8eb9SGleb Smirnoff struct node_qassign {
2213b3a8eb9SGleb Smirnoff 	char		*qname;
2223b3a8eb9SGleb Smirnoff 	char		*pqname;
2233b3a8eb9SGleb Smirnoff };
2243b3a8eb9SGleb Smirnoff 
225aa69fdf1SKristof Provost struct range {
226aa69fdf1SKristof Provost 	int		 a;
227aa69fdf1SKristof Provost 	int		 b;
228aa69fdf1SKristof Provost 	int		 t;
229aa69fdf1SKristof Provost };
230aa69fdf1SKristof Provost struct redirection {
231aa69fdf1SKristof Provost 	struct node_host	*host;
232aa69fdf1SKristof Provost 	struct range		 rport;
233aa69fdf1SKristof Provost };
234aa69fdf1SKristof Provost 
235aa69fdf1SKristof Provost static struct pool_opts {
236aa69fdf1SKristof Provost 	int			 marker;
237aa69fdf1SKristof Provost #define POM_TYPE		0x01
238aa69fdf1SKristof Provost #define POM_STICKYADDRESS	0x02
239aa69fdf1SKristof Provost #define POM_ENDPI		0x04
240aa69fdf1SKristof Provost 	u_int8_t		 opts;
241aa69fdf1SKristof Provost 	int			 type;
242aa69fdf1SKristof Provost 	int			 staticport;
243aa69fdf1SKristof Provost 	struct pf_poolhashkey	*key;
244aa69fdf1SKristof Provost 	struct pf_mape_portset	 mape;
245aa69fdf1SKristof Provost } pool_opts;
246aa69fdf1SKristof Provost 
247aa69fdf1SKristof Provost struct redirspec {
248aa69fdf1SKristof Provost 	struct redirection	 *rdr;
249aa69fdf1SKristof Provost 	struct pool_opts	 pool_opts;
250aa69fdf1SKristof Provost 	int		 af;
251aa69fdf1SKristof Provost };
252aa69fdf1SKristof Provost 
25313cfafabSKristof Provost static struct filter_opts {
2543b3a8eb9SGleb Smirnoff 	int			 marker;
25539282ef3SKajetan Staszkiewicz #define FOM_FLAGS	0x0001
25639282ef3SKajetan Staszkiewicz #define FOM_ICMP	0x0002
25739282ef3SKajetan Staszkiewicz #define FOM_TOS		0x0004
25839282ef3SKajetan Staszkiewicz #define FOM_KEEP	0x0008
25939282ef3SKajetan Staszkiewicz #define FOM_SRCTRACK	0x0010
26039282ef3SKajetan Staszkiewicz #define FOM_MINTTL	0x0020
26139282ef3SKajetan Staszkiewicz #define FOM_MAXMSS	0x0040
262aa69fdf1SKristof Provost #define FOM_AFTO	0x0080
26339282ef3SKajetan Staszkiewicz #define FOM_SETTOS	0x0100
26439282ef3SKajetan Staszkiewicz #define FOM_SCRUB_TCP	0x0200
2653e248e0fSKristof Provost #define FOM_SETPRIO	0x0400
26639282ef3SKajetan Staszkiewicz #define FOM_ONCE	0x1000 /* not yet implemmented */
2673e248e0fSKristof Provost #define FOM_PRIO	0x2000
26839282ef3SKajetan Staszkiewicz #define FOM_SETDELAY	0x4000
26939282ef3SKajetan Staszkiewicz #define FOM_FRAGCACHE	0x8000 /* does not exist in OpenBSD */
2703b3a8eb9SGleb Smirnoff 	struct node_uid		*uid;
2713b3a8eb9SGleb Smirnoff 	struct node_gid		*gid;
2722339ead6SKristof Provost 	struct node_if		*rcv;
2733b3a8eb9SGleb Smirnoff 	struct {
2743b3a8eb9SGleb Smirnoff 		u_int8_t	 b1;
2753b3a8eb9SGleb Smirnoff 		u_int8_t	 b2;
2763b3a8eb9SGleb Smirnoff 		u_int16_t	 w;
2773b3a8eb9SGleb Smirnoff 		u_int16_t	 w2;
2783b3a8eb9SGleb Smirnoff 	} flags;
2793b3a8eb9SGleb Smirnoff 	struct node_icmp	*icmpspec;
2803b3a8eb9SGleb Smirnoff 	u_int32_t		 tos;
2813b3a8eb9SGleb Smirnoff 	u_int32_t		 prob;
28276c5eeccSKristof Provost 	u_int32_t		 ridentifier;
2833b3a8eb9SGleb Smirnoff 	struct {
2843b3a8eb9SGleb Smirnoff 		int			 action;
2853b3a8eb9SGleb Smirnoff 		struct node_state_opt	*options;
2863b3a8eb9SGleb Smirnoff 	} keep;
2873b3a8eb9SGleb Smirnoff 	int			 fragment;
2883b3a8eb9SGleb Smirnoff 	int			 allowopts;
2896fcc8e04SKristof Provost 	char			*label[PF_RULE_MAX_LABEL_COUNT];
2906fcc8e04SKristof Provost 	int			 labelcount;
2913b3a8eb9SGleb Smirnoff 	struct node_qassign	 queues;
2923b3a8eb9SGleb Smirnoff 	char			*tag;
2933b3a8eb9SGleb Smirnoff 	char			*match_tag;
2943b3a8eb9SGleb Smirnoff 	u_int8_t		 match_tag_not;
29563b3c1c7SKristof Provost 	u_int16_t		 dnpipe;
29663b3c1c7SKristof Provost 	u_int16_t		 dnrpipe;
29763b3c1c7SKristof Provost 	u_int32_t		 free_flags;
2983b3a8eb9SGleb Smirnoff 	u_int			 rtableid;
2993e248e0fSKristof Provost 	u_int8_t		 prio;
3003e248e0fSKristof Provost 	u_int8_t		 set_prio[2];
3013b3a8eb9SGleb Smirnoff 	struct {
3023b3a8eb9SGleb Smirnoff 		struct node_host	*addr;
3033b3a8eb9SGleb Smirnoff 		u_int16_t		port;
3043b3a8eb9SGleb Smirnoff 	}			 divert;
305aa69fdf1SKristof Provost 	struct redirspec	 nat;
306aa69fdf1SKristof Provost 	struct redirspec	 rdr;
3070972294eSKristof Provost 	struct redirspec	 rroute;
30839282ef3SKajetan Staszkiewicz 	/* new-style scrub opts */
30939282ef3SKajetan Staszkiewicz 	int			 nodf;
31039282ef3SKajetan Staszkiewicz 	int			 minttl;
31139282ef3SKajetan Staszkiewicz 	int			 settos;
31239282ef3SKajetan Staszkiewicz 	int			 randomid;
31339282ef3SKajetan Staszkiewicz 	int			 max_mss;
3143b3a8eb9SGleb Smirnoff } filter_opts;
3153b3a8eb9SGleb Smirnoff 
31613cfafabSKristof Provost static struct antispoof_opts {
3176fcc8e04SKristof Provost 	char			*label[PF_RULE_MAX_LABEL_COUNT];
3186fcc8e04SKristof Provost 	int			 labelcount;
31976c5eeccSKristof Provost 	u_int32_t		 ridentifier;
3203b3a8eb9SGleb Smirnoff 	u_int			 rtableid;
3213b3a8eb9SGleb Smirnoff } antispoof_opts;
3223b3a8eb9SGleb Smirnoff 
32313cfafabSKristof Provost static struct scrub_opts {
3243b3a8eb9SGleb Smirnoff 	int			 marker;
3253b3a8eb9SGleb Smirnoff 	int			 nodf;
3263b3a8eb9SGleb Smirnoff 	int			 minttl;
3273b3a8eb9SGleb Smirnoff 	int			 maxmss;
3283b3a8eb9SGleb Smirnoff 	int			 settos;
3293b3a8eb9SGleb Smirnoff 	int			 fragcache;
3303b3a8eb9SGleb Smirnoff 	int			 randomid;
3313b3a8eb9SGleb Smirnoff 	int			 reassemble_tcp;
3323b3a8eb9SGleb Smirnoff 	char			*match_tag;
3333b3a8eb9SGleb Smirnoff 	u_int8_t		 match_tag_not;
3343b3a8eb9SGleb Smirnoff 	u_int			 rtableid;
3353b3a8eb9SGleb Smirnoff } scrub_opts;
3363b3a8eb9SGleb Smirnoff 
33713cfafabSKristof Provost static struct queue_opts {
3383b3a8eb9SGleb Smirnoff 	int			marker;
3393b3a8eb9SGleb Smirnoff #define QOM_BWSPEC	0x01
3403b3a8eb9SGleb Smirnoff #define QOM_SCHEDULER	0x02
3413b3a8eb9SGleb Smirnoff #define QOM_PRIORITY	0x04
3423b3a8eb9SGleb Smirnoff #define QOM_TBRSIZE	0x08
3433b3a8eb9SGleb Smirnoff #define QOM_QLIMIT	0x10
3443b3a8eb9SGleb Smirnoff 	struct node_queue_bw	queue_bwspec;
3453b3a8eb9SGleb Smirnoff 	struct node_queue_opt	scheduler;
3463b3a8eb9SGleb Smirnoff 	int			priority;
347249cc75fSPatrick Kelsey 	unsigned int		tbrsize;
3483b3a8eb9SGleb Smirnoff 	int			qlimit;
3493b3a8eb9SGleb Smirnoff } queue_opts;
3503b3a8eb9SGleb Smirnoff 
35113cfafabSKristof Provost static struct table_opts {
3523b3a8eb9SGleb Smirnoff 	int			flags;
3533b3a8eb9SGleb Smirnoff 	int			init_addr;
3543b3a8eb9SGleb Smirnoff 	struct node_tinithead	init_nodes;
3553b3a8eb9SGleb Smirnoff } table_opts;
3563b3a8eb9SGleb Smirnoff 
35713cfafabSKristof Provost static struct codel_opts	 codel_opts;
35813cfafabSKristof Provost static struct node_hfsc_opts	 hfsc_opts;
35913cfafabSKristof Provost static struct node_fairq_opts	 fairq_opts;
36013cfafabSKristof Provost static struct node_state_opt	*keep_state_defaults = NULL;
3615062afffSKristof Provost static struct pfctl_watermarks	 syncookie_opts;
3623b3a8eb9SGleb Smirnoff 
3633b3a8eb9SGleb Smirnoff int		 disallow_table(struct node_host *, const char *);
3643b3a8eb9SGleb Smirnoff int		 disallow_urpf_failed(struct node_host *, const char *);
3653b3a8eb9SGleb Smirnoff int		 disallow_alias(struct node_host *, const char *);
366e9eb0941SKristof Provost int		 rule_consistent(struct pfctl_rule *, int);
367e9eb0941SKristof Provost int		 filter_consistent(struct pfctl_rule *, int);
368e9eb0941SKristof Provost int		 nat_consistent(struct pfctl_rule *);
369e9eb0941SKristof Provost int		 rdr_consistent(struct pfctl_rule *);
3703b3a8eb9SGleb Smirnoff int		 process_tabledef(char *, struct table_opts *);
3713b3a8eb9SGleb Smirnoff void		 expand_label_str(char *, size_t, const char *, const char *);
3723b3a8eb9SGleb Smirnoff void		 expand_label_if(const char *, char *, size_t, const char *);
3739ec48bc3SKristof Provost void		 expand_label_addr(const char *, char *, size_t, sa_family_t,
37409c7f238SKristof Provost 		    struct pf_rule_addr *);
3753b3a8eb9SGleb Smirnoff void		 expand_label_port(const char *, char *, size_t,
37609c7f238SKristof Provost 		    struct pf_rule_addr *);
3773b3a8eb9SGleb Smirnoff void		 expand_label_proto(const char *, char *, size_t, u_int8_t);
37809c7f238SKristof Provost void		 expand_label_nr(const char *, char *, size_t,
37909c7f238SKristof Provost 		    struct pfctl_rule *);
3802b29ceb8SKristof Provost void		 expand_eth_rule(struct pfctl_eth_rule *,
38187a89d6eSKristof Provost 		    struct node_if *, struct node_etherproto *,
3828a42005dSKristof Provost 		    struct node_mac *, struct node_mac *,
3838a8af942SKristof Provost 		    struct node_host *, struct node_host *, const char *,
3848a8af942SKristof Provost 		    const char *);
385e9eb0941SKristof Provost void		 expand_rule(struct pfctl_rule *, struct node_if *,
3860972294eSKristof Provost 		    struct redirspec *, struct redirspec *, struct redirspec *,
3870972294eSKristof Provost 		    struct node_host *, struct node_host *, struct node_host *,
3880972294eSKristof Provost 		    struct node_proto *, struct node_os *, struct node_host *,
3890972294eSKristof Provost 		    struct node_port *, struct node_host *, struct node_port *,
3900972294eSKristof Provost 		    struct node_uid *, struct node_gid *, struct node_if *,
3910972294eSKristof Provost 		    struct node_icmp *, const char *);
3923b3a8eb9SGleb Smirnoff int		 expand_altq(struct pf_altq *, struct node_if *,
3933b3a8eb9SGleb Smirnoff 		    struct node_queue *, struct node_queue_bw bwspec,
3943b3a8eb9SGleb Smirnoff 		    struct node_queue_opt *);
3953b3a8eb9SGleb Smirnoff int		 expand_queue(struct pf_altq *, struct node_if *,
3963b3a8eb9SGleb Smirnoff 		    struct node_queue *, struct node_queue_bw,
3973b3a8eb9SGleb Smirnoff 		    struct node_queue_opt *);
3983b3a8eb9SGleb Smirnoff int		 expand_skip_interface(struct node_if *);
3993b3a8eb9SGleb Smirnoff 
4003b3a8eb9SGleb Smirnoff int	 check_rulestate(int);
4013b3a8eb9SGleb Smirnoff int	 getservice(char *);
4026fcc8e04SKristof Provost int	 rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
403ef661d4aSChristian McDonald int	 eth_rule_label(struct pfctl_eth_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
4043b3a8eb9SGleb Smirnoff int	 rt_tableid_max(void);
4053b3a8eb9SGleb Smirnoff 
406e9eb0941SKristof Provost void	 mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *);
407c5131afeSKristof Provost void	 mv_eth_rules(struct pfctl_eth_ruleset *, struct pfctl_eth_ruleset *);
4083b3a8eb9SGleb Smirnoff void	 decide_address_family(struct node_host *, sa_family_t *);
4093b3a8eb9SGleb Smirnoff void	 remove_invalid_hosts(struct node_host **, sa_family_t *);
4103b3a8eb9SGleb Smirnoff int	 invalid_redirect(struct node_host *, sa_family_t);
4113b3a8eb9SGleb Smirnoff u_int16_t parseicmpspec(char *, sa_family_t);
4121f495578SKristof Provost int	 kw_casecmp(const void *, const void *);
4131f495578SKristof Provost int	 map_tos(char *string, int *);
414b590f17aSKristof Provost struct node_mac* node_mac_from_string(const char *);
415b590f17aSKristof Provost struct node_mac* node_mac_from_string_masklen(const char *, int);
416b590f17aSKristof Provost struct node_mac* node_mac_from_string_mask(const char *, const char *);
4173b3a8eb9SGleb Smirnoff 
41813cfafabSKristof Provost static TAILQ_HEAD(loadanchorshead, loadanchors)
4193b3a8eb9SGleb Smirnoff     loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
4203b3a8eb9SGleb Smirnoff 
4213b3a8eb9SGleb Smirnoff struct loadanchors {
4223b3a8eb9SGleb Smirnoff 	TAILQ_ENTRY(loadanchors)	 entries;
4233b3a8eb9SGleb Smirnoff 	char				*anchorname;
4243b3a8eb9SGleb Smirnoff 	char				*filename;
4253b3a8eb9SGleb Smirnoff };
4263b3a8eb9SGleb Smirnoff 
4273b3a8eb9SGleb Smirnoff typedef struct {
4283b3a8eb9SGleb Smirnoff 	union {
4293b3a8eb9SGleb Smirnoff 		int64_t			 number;
4303b3a8eb9SGleb Smirnoff 		double			 probability;
4313b3a8eb9SGleb Smirnoff 		int			 i;
4323b3a8eb9SGleb Smirnoff 		char			*string;
4333b3a8eb9SGleb Smirnoff 		u_int			 rtableid;
4343b3a8eb9SGleb Smirnoff 		struct {
4353b3a8eb9SGleb Smirnoff 			u_int8_t	 b1;
4363b3a8eb9SGleb Smirnoff 			u_int8_t	 b2;
4373b3a8eb9SGleb Smirnoff 			u_int16_t	 w;
4383b3a8eb9SGleb Smirnoff 			u_int16_t	 w2;
4393b3a8eb9SGleb Smirnoff 		}			 b;
440aa69fdf1SKristof Provost 		struct range		 range;
4413b3a8eb9SGleb Smirnoff 		struct node_if		*interface;
4423b3a8eb9SGleb Smirnoff 		struct node_proto	*proto;
4432b29ceb8SKristof Provost 		struct node_etherproto	*etherproto;
4443b3a8eb9SGleb Smirnoff 		struct node_icmp	*icmp;
4453b3a8eb9SGleb Smirnoff 		struct node_host	*host;
4463b3a8eb9SGleb Smirnoff 		struct node_os		*os;
4473b3a8eb9SGleb Smirnoff 		struct node_port	*port;
4483b3a8eb9SGleb Smirnoff 		struct node_uid		*uid;
4493b3a8eb9SGleb Smirnoff 		struct node_gid		*gid;
4503b3a8eb9SGleb Smirnoff 		struct node_state_opt	*state_opt;
4513b3a8eb9SGleb Smirnoff 		struct peer		 peer;
4523b3a8eb9SGleb Smirnoff 		struct {
4533b3a8eb9SGleb Smirnoff 			struct peer	 src, dst;
4543b3a8eb9SGleb Smirnoff 			struct node_os	*src_os;
4553b3a8eb9SGleb Smirnoff 		}			 fromto;
4563b3a8eb9SGleb Smirnoff 		struct {
45787a89d6eSKristof Provost 			struct node_mac	*src;
45887a89d6eSKristof Provost 			struct node_mac	*dst;
4592b29ceb8SKristof Provost 		}			 etherfromto;
46087a89d6eSKristof Provost 		struct node_mac		*mac;
4612b29ceb8SKristof Provost 		struct {
46287a89d6eSKristof Provost 			struct node_mac	*mac;
4632b29ceb8SKristof Provost 		} etheraddr;
4648a8af942SKristof Provost 		char			*bridge_to;
4652b29ceb8SKristof Provost 		struct {
4663b3a8eb9SGleb Smirnoff 			struct node_host	*host;
4673b3a8eb9SGleb Smirnoff 			u_int8_t		 rt;
4683b3a8eb9SGleb Smirnoff 			u_int8_t		 pool_opts;
4693b3a8eb9SGleb Smirnoff 			sa_family_t		 af;
4703b3a8eb9SGleb Smirnoff 			struct pf_poolhashkey	*key;
4713b3a8eb9SGleb Smirnoff 		}			 route;
472aa69fdf1SKristof Provost 		struct redirection	*redirection;
4733b3a8eb9SGleb Smirnoff 		struct {
4743b3a8eb9SGleb Smirnoff 			int			 action;
4753b3a8eb9SGleb Smirnoff 			struct node_state_opt	*options;
4763b3a8eb9SGleb Smirnoff 		}			 keep_state;
4773b3a8eb9SGleb Smirnoff 		struct {
4783b3a8eb9SGleb Smirnoff 			u_int8_t	 log;
4793b3a8eb9SGleb Smirnoff 			u_int8_t	 logif;
4803b3a8eb9SGleb Smirnoff 			u_int8_t	 quick;
4813b3a8eb9SGleb Smirnoff 		}			 logquick;
4823b3a8eb9SGleb Smirnoff 		struct {
4833b3a8eb9SGleb Smirnoff 			int		 neg;
4843b3a8eb9SGleb Smirnoff 			char		*name;
4853b3a8eb9SGleb Smirnoff 		}			 tagged;
4863b3a8eb9SGleb Smirnoff 		struct pf_poolhashkey	*hashkey;
4873b3a8eb9SGleb Smirnoff 		struct node_queue	*queue;
4883b3a8eb9SGleb Smirnoff 		struct node_queue_opt	 queue_options;
4893b3a8eb9SGleb Smirnoff 		struct node_queue_bw	 queue_bwspec;
4903b3a8eb9SGleb Smirnoff 		struct node_qassign	 qassign;
4913b3a8eb9SGleb Smirnoff 		struct filter_opts	 filter_opts;
4923b3a8eb9SGleb Smirnoff 		struct antispoof_opts	 antispoof_opts;
4933b3a8eb9SGleb Smirnoff 		struct queue_opts	 queue_opts;
4943b3a8eb9SGleb Smirnoff 		struct scrub_opts	 scrub_opts;
4953b3a8eb9SGleb Smirnoff 		struct table_opts	 table_opts;
4963b3a8eb9SGleb Smirnoff 		struct pool_opts	 pool_opts;
4973b3a8eb9SGleb Smirnoff 		struct node_hfsc_opts	 hfsc_opts;
498a5b789f6SErmal Luçi 		struct node_fairq_opts	 fairq_opts;
4990a70aaf8SLuiz Otavio O Souza 		struct codel_opts	 codel_opts;
5005062afffSKristof Provost 		struct pfctl_watermarks	*watermarks;
5013b3a8eb9SGleb Smirnoff 	} v;
5023b3a8eb9SGleb Smirnoff 	int lineno;
5033b3a8eb9SGleb Smirnoff } YYSTYPE;
5043b3a8eb9SGleb Smirnoff 
5053b3a8eb9SGleb Smirnoff #define PPORT_RANGE	1
5063b3a8eb9SGleb Smirnoff #define PPORT_STAR	2
5073b3a8eb9SGleb Smirnoff int	parseport(char *, struct range *r, int);
5083b3a8eb9SGleb Smirnoff 
5093b3a8eb9SGleb Smirnoff #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
5103b3a8eb9SGleb Smirnoff 	(!((addr).iflags & PFI_AFLAG_NOALIAS) ||		 \
5113b3a8eb9SGleb Smirnoff 	!isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
5123b3a8eb9SGleb Smirnoff 
5133b3a8eb9SGleb Smirnoff %}
5143b3a8eb9SGleb Smirnoff 
515ef950daaSKristof Provost %token	PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
5163b3a8eb9SGleb Smirnoff %token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
5173b3a8eb9SGleb Smirnoff %token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
5183b3a8eb9SGleb Smirnoff %token	MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
5193b3a8eb9SGleb Smirnoff %token	NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
52088e858e5SKristof Provost %token	REASSEMBLE ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
521150182e3SKristof Provost %token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY
522150182e3SKristof Provost %token	RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
523f3ab00c2SKristof Provost %token	ANTISPOOF FOR INCLUDE KEEPCOUNTERS SYNCOOKIES L3 MATCHES
5242b29ceb8SKristof Provost %token	ETHER
5252aa21096SKurosawa Takahiro %token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
5260a70aaf8SLuiz Otavio O Souza %token	ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
5270a70aaf8SLuiz Otavio O Souza %token	UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
52876c5eeccSKristof Provost %token	DNPIPE DNQUEUE RIDENTIFIER
5293e248e0fSKristof Provost %token	LOAD RULESET_OPTIMIZATION PRIO
530390dc369STom Jones %token	STICKYADDRESS ENDPI MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
531e4f2733dSKristof Provost %token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW ALLOW_RELATED
5323b3a8eb9SGleb Smirnoff %token	TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
533aa69fdf1SKristof Provost %token	DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO
5343b3a8eb9SGleb Smirnoff %token	<v.string>		STRING
5353b3a8eb9SGleb Smirnoff %token	<v.number>		NUMBER
5363b3a8eb9SGleb Smirnoff %token	<v.i>			PORTBINARY
5373b3a8eb9SGleb Smirnoff %type	<v.interface>		interface if_list if_item_not if_item
5383b3a8eb9SGleb Smirnoff %type	<v.number>		number icmptype icmp6type uid gid
53939282ef3SKajetan Staszkiewicz %type	<v.number>		tos not yesno optnodf
5403b3a8eb9SGleb Smirnoff %type	<v.probability>		probability
541c69121c4SKristof Provost %type	<v.i>			no dir af fragcache optimizer syncookie_val
5423b3a8eb9SGleb Smirnoff %type	<v.i>			sourcetrack flush unaryop statelock
5432b29ceb8SKristof Provost %type	<v.i>			etherprotoval
5443b3a8eb9SGleb Smirnoff %type	<v.b>			action nataction natpasslog scrubaction
5453e248e0fSKristof Provost %type	<v.b>			flags flag blockspec prio
5463b3a8eb9SGleb Smirnoff %type	<v.range>		portplain portstar portrange
5473b3a8eb9SGleb Smirnoff %type	<v.hashkey>		hashkey
5483b3a8eb9SGleb Smirnoff %type	<v.proto>		proto proto_list proto_item
5493b3a8eb9SGleb Smirnoff %type	<v.number>		protoval
5503b3a8eb9SGleb Smirnoff %type	<v.icmp>		icmpspec
5513b3a8eb9SGleb Smirnoff %type	<v.icmp>		icmp_list icmp_item
5523b3a8eb9SGleb Smirnoff %type	<v.icmp>		icmp6_list icmp6_item
5533b3a8eb9SGleb Smirnoff %type	<v.number>		reticmpspec reticmp6spec
5548a42005dSKristof Provost %type	<v.fromto>		fromto l3fromto
5553b3a8eb9SGleb Smirnoff %type	<v.peer>		ipportspec from to
5563b3a8eb9SGleb Smirnoff %type	<v.host>		ipspec toipspec xhost host dynaddr host_list
5573b3a8eb9SGleb Smirnoff %type	<v.host>		redir_host_list redirspec
5583b3a8eb9SGleb Smirnoff %type	<v.host>		route_host route_host_list routespec
5593b3a8eb9SGleb Smirnoff %type	<v.os>			os xos os_list
5603b3a8eb9SGleb Smirnoff %type	<v.port>		portspec port_list port_item
5613b3a8eb9SGleb Smirnoff %type	<v.uid>			uids uid_list uid_item
5623b3a8eb9SGleb Smirnoff %type	<v.gid>			gids gid_list gid_item
5633b3a8eb9SGleb Smirnoff %type	<v.route>		route
5643b3a8eb9SGleb Smirnoff %type	<v.redirection>		redirection redirpool
5653b3a8eb9SGleb Smirnoff %type	<v.string>		label stringall tag anchorname
5663b3a8eb9SGleb Smirnoff %type	<v.string>		string varstring numberstring
5673b3a8eb9SGleb Smirnoff %type	<v.keep_state>		keep
5683b3a8eb9SGleb Smirnoff %type	<v.state_opt>		state_opt_spec state_opt_list state_opt_item
5693b3a8eb9SGleb Smirnoff %type	<v.logquick>		logquick quick log logopts logopt
5703b3a8eb9SGleb Smirnoff %type	<v.interface>		antispoof_ifspc antispoof_iflst antispoof_if
5712b29ceb8SKristof Provost %type	<v.qassign>		qname etherqname
5723b3a8eb9SGleb Smirnoff %type	<v.queue>		qassign qassign_list qassign_item
5733b3a8eb9SGleb Smirnoff %type	<v.queue_options>	scheduler
5743b3a8eb9SGleb Smirnoff %type	<v.number>		cbqflags_list cbqflags_item
5753b3a8eb9SGleb Smirnoff %type	<v.number>		priqflags_list priqflags_item
5763b3a8eb9SGleb Smirnoff %type	<v.hfsc_opts>		hfscopts_list hfscopts_item hfsc_opts
577a5b789f6SErmal Luçi %type	<v.fairq_opts>		fairqopts_list fairqopts_item fairq_opts
5780a70aaf8SLuiz Otavio O Souza %type	<v.codel_opts>		codelopts_list codelopts_item codel_opts
5793b3a8eb9SGleb Smirnoff %type	<v.queue_bwspec>	bandwidth
5802b29ceb8SKristof Provost %type	<v.filter_opts>		filter_opts filter_opt filter_opts_l etherfilter_opts etherfilter_opt etherfilter_opts_l
5813e248e0fSKristof Provost %type	<v.filter_opts>		filter_sets filter_set filter_sets_l
5823b3a8eb9SGleb Smirnoff %type	<v.antispoof_opts>	antispoof_opts antispoof_opt antispoof_opts_l
5833b3a8eb9SGleb Smirnoff %type	<v.queue_opts>		queue_opts queue_opt queue_opts_l
5843b3a8eb9SGleb Smirnoff %type	<v.scrub_opts>		scrub_opts scrub_opt scrub_opts_l
5853b3a8eb9SGleb Smirnoff %type	<v.table_opts>		table_opts table_opt table_opts_l
5863b3a8eb9SGleb Smirnoff %type	<v.pool_opts>		pool_opts pool_opt pool_opts_l
5873b3a8eb9SGleb Smirnoff %type	<v.tagged>		tagged
5883b3a8eb9SGleb Smirnoff %type	<v.rtableid>		rtable
5895062afffSKristof Provost %type	<v.watermarks>		syncookie_opts
5902b29ceb8SKristof Provost %type	<v.etherproto>		etherproto etherproto_list etherproto_item
5912b29ceb8SKristof Provost %type	<v.etherfromto>		etherfromto
5922b29ceb8SKristof Provost %type	<v.etheraddr>		etherfrom etherto
5938a8af942SKristof Provost %type	<v.bridge_to>		bridge
59487a89d6eSKristof Provost %type	<v.mac>			xmac mac mac_list macspec
5953b3a8eb9SGleb Smirnoff %%
5963b3a8eb9SGleb Smirnoff 
5973b3a8eb9SGleb Smirnoff ruleset		: /* empty */
5983b3a8eb9SGleb Smirnoff 		| ruleset include '\n'
5993b3a8eb9SGleb Smirnoff 		| ruleset '\n'
6003b3a8eb9SGleb Smirnoff 		| ruleset option '\n'
6012b29ceb8SKristof Provost 		| ruleset etherrule '\n'
602c5131afeSKristof Provost 		| ruleset etheranchorrule '\n'
6033b3a8eb9SGleb Smirnoff 		| ruleset scrubrule '\n'
6043b3a8eb9SGleb Smirnoff 		| ruleset natrule '\n'
6053b3a8eb9SGleb Smirnoff 		| ruleset binatrule '\n'
6063b3a8eb9SGleb Smirnoff 		| ruleset pfrule '\n'
6073b3a8eb9SGleb Smirnoff 		| ruleset anchorrule '\n'
6083b3a8eb9SGleb Smirnoff 		| ruleset loadrule '\n'
6093b3a8eb9SGleb Smirnoff 		| ruleset altqif '\n'
6103b3a8eb9SGleb Smirnoff 		| ruleset queuespec '\n'
6113b3a8eb9SGleb Smirnoff 		| ruleset varset '\n'
6123b3a8eb9SGleb Smirnoff 		| ruleset antispoof '\n'
6133b3a8eb9SGleb Smirnoff 		| ruleset tabledef '\n'
6143b3a8eb9SGleb Smirnoff 		| '{' fakeanchor '}' '\n';
6153b3a8eb9SGleb Smirnoff 		| ruleset error '\n'		{ file->errors++; }
6163b3a8eb9SGleb Smirnoff 		;
6173b3a8eb9SGleb Smirnoff 
6183b3a8eb9SGleb Smirnoff include		: INCLUDE STRING		{
6193b3a8eb9SGleb Smirnoff 			struct file	*nfile;
6203b3a8eb9SGleb Smirnoff 
6213b3a8eb9SGleb Smirnoff 			if ((nfile = pushfile($2, 0)) == NULL) {
6223b3a8eb9SGleb Smirnoff 				yyerror("failed to include file %s", $2);
6233b3a8eb9SGleb Smirnoff 				free($2);
6243b3a8eb9SGleb Smirnoff 				YYERROR;
6253b3a8eb9SGleb Smirnoff 			}
6263b3a8eb9SGleb Smirnoff 			free($2);
6273b3a8eb9SGleb Smirnoff 
6283b3a8eb9SGleb Smirnoff 			file = nfile;
6293b3a8eb9SGleb Smirnoff 			lungetc('\n');
6303b3a8eb9SGleb Smirnoff 		}
6313b3a8eb9SGleb Smirnoff 		;
6323b3a8eb9SGleb Smirnoff 
6333b3a8eb9SGleb Smirnoff /*
6343b3a8eb9SGleb Smirnoff  * apply to previouslys specified rule: must be careful to note
6353b3a8eb9SGleb Smirnoff  * what that is: pf or nat or binat or rdr
6363b3a8eb9SGleb Smirnoff  */
6373b3a8eb9SGleb Smirnoff fakeanchor	: fakeanchor '\n'
6383b3a8eb9SGleb Smirnoff 		| fakeanchor anchorrule '\n'
6393b3a8eb9SGleb Smirnoff 		| fakeanchor binatrule '\n'
6403b3a8eb9SGleb Smirnoff 		| fakeanchor natrule '\n'
6413b3a8eb9SGleb Smirnoff 		| fakeanchor pfrule '\n'
6423b3a8eb9SGleb Smirnoff 		| fakeanchor error '\n'
6433b3a8eb9SGleb Smirnoff 		;
6443b3a8eb9SGleb Smirnoff 
6453b3a8eb9SGleb Smirnoff optimizer	: string	{
6463b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "none"))
6473b3a8eb9SGleb Smirnoff 				$$ = 0;
6483b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "basic"))
6493b3a8eb9SGleb Smirnoff 				$$ = PF_OPTIMIZE_BASIC;
6503b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "profile"))
6513b3a8eb9SGleb Smirnoff 				$$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
6523b3a8eb9SGleb Smirnoff 			else {
6533b3a8eb9SGleb Smirnoff 				yyerror("unknown ruleset-optimization %s", $1);
6543b3a8eb9SGleb Smirnoff 				YYERROR;
6553b3a8eb9SGleb Smirnoff 			}
6563b3a8eb9SGleb Smirnoff 		}
6573b3a8eb9SGleb Smirnoff 		;
6583b3a8eb9SGleb Smirnoff 
65939282ef3SKajetan Staszkiewicz optnodf		: /* empty */	{ $$ = 0; }
66039282ef3SKajetan Staszkiewicz 		| NODF		{ $$ = 1; }
66139282ef3SKajetan Staszkiewicz 		;
66239282ef3SKajetan Staszkiewicz 
66339282ef3SKajetan Staszkiewicz option		: SET REASSEMBLE yesno optnodf		{
66439282ef3SKajetan Staszkiewicz 			if (check_rulestate(PFCTL_STATE_OPTION))
66539282ef3SKajetan Staszkiewicz 				YYERROR;
66639282ef3SKajetan Staszkiewicz 			pfctl_set_reassembly(pf, $3, $4);
66739282ef3SKajetan Staszkiewicz 		}
66839282ef3SKajetan Staszkiewicz 		| SET OPTIMIZATION STRING		{
6693b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
6703b3a8eb9SGleb Smirnoff 				free($3);
6713b3a8eb9SGleb Smirnoff 				YYERROR;
6723b3a8eb9SGleb Smirnoff 			}
6733b3a8eb9SGleb Smirnoff 			if (pfctl_set_optimization(pf, $3) != 0) {
6743b3a8eb9SGleb Smirnoff 				yyerror("unknown optimization %s", $3);
6753b3a8eb9SGleb Smirnoff 				free($3);
6763b3a8eb9SGleb Smirnoff 				YYERROR;
6773b3a8eb9SGleb Smirnoff 			}
6783b3a8eb9SGleb Smirnoff 			free($3);
6793b3a8eb9SGleb Smirnoff 		}
6803b3a8eb9SGleb Smirnoff 		| SET RULESET_OPTIMIZATION optimizer {
6813b3a8eb9SGleb Smirnoff 			if (!(pf->opts & PF_OPT_OPTIMIZE)) {
6823b3a8eb9SGleb Smirnoff 				pf->opts |= PF_OPT_OPTIMIZE;
6833b3a8eb9SGleb Smirnoff 				pf->optimize = $3;
6843b3a8eb9SGleb Smirnoff 			}
6853b3a8eb9SGleb Smirnoff 		}
6863b3a8eb9SGleb Smirnoff 		| SET TIMEOUT timeout_spec
6873b3a8eb9SGleb Smirnoff 		| SET TIMEOUT '{' optnl timeout_list '}'
6883b3a8eb9SGleb Smirnoff 		| SET LIMIT limit_spec
6893b3a8eb9SGleb Smirnoff 		| SET LIMIT '{' optnl limit_list '}'
6903b3a8eb9SGleb Smirnoff 		| SET LOGINTERFACE stringall		{
6913b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
6923b3a8eb9SGleb Smirnoff 				free($3);
6933b3a8eb9SGleb Smirnoff 				YYERROR;
6943b3a8eb9SGleb Smirnoff 			}
6953b3a8eb9SGleb Smirnoff 			if (pfctl_set_logif(pf, $3) != 0) {
6963b3a8eb9SGleb Smirnoff 				yyerror("error setting loginterface %s", $3);
6973b3a8eb9SGleb Smirnoff 				free($3);
6983b3a8eb9SGleb Smirnoff 				YYERROR;
6993b3a8eb9SGleb Smirnoff 			}
7003b3a8eb9SGleb Smirnoff 			free($3);
7013b3a8eb9SGleb Smirnoff 		}
7023b3a8eb9SGleb Smirnoff 		| SET HOSTID number {
7033b3a8eb9SGleb Smirnoff 			if ($3 == 0 || $3 > UINT_MAX) {
7043b3a8eb9SGleb Smirnoff 				yyerror("hostid must be non-zero");
7053b3a8eb9SGleb Smirnoff 				YYERROR;
7063b3a8eb9SGleb Smirnoff 			}
7074aafc73dSKristof Provost 			pfctl_set_hostid(pf, $3);
7083b3a8eb9SGleb Smirnoff 		}
7093b3a8eb9SGleb Smirnoff 		| SET BLOCKPOLICY DROP	{
7103b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
7113b3a8eb9SGleb Smirnoff 				printf("set block-policy drop\n");
7123b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION))
7133b3a8eb9SGleb Smirnoff 				YYERROR;
7143b3a8eb9SGleb Smirnoff 			blockpolicy = PFRULE_DROP;
7153b3a8eb9SGleb Smirnoff 		}
7163b3a8eb9SGleb Smirnoff 		| SET BLOCKPOLICY RETURN {
7173b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
7183b3a8eb9SGleb Smirnoff 				printf("set block-policy return\n");
7193b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION))
7203b3a8eb9SGleb Smirnoff 				YYERROR;
7213b3a8eb9SGleb Smirnoff 			blockpolicy = PFRULE_RETURN;
7223b3a8eb9SGleb Smirnoff 		}
723150182e3SKristof Provost 		| SET FAILPOLICY DROP	{
724150182e3SKristof Provost 			if (pf->opts & PF_OPT_VERBOSE)
725150182e3SKristof Provost 				printf("set fail-policy drop\n");
726150182e3SKristof Provost 			if (check_rulestate(PFCTL_STATE_OPTION))
727150182e3SKristof Provost 				YYERROR;
728150182e3SKristof Provost 			failpolicy = PFRULE_DROP;
729150182e3SKristof Provost 		}
730150182e3SKristof Provost 		| SET FAILPOLICY RETURN {
731150182e3SKristof Provost 			if (pf->opts & PF_OPT_VERBOSE)
732150182e3SKristof Provost 				printf("set fail-policy return\n");
733150182e3SKristof Provost 			if (check_rulestate(PFCTL_STATE_OPTION))
734150182e3SKristof Provost 				YYERROR;
735150182e3SKristof Provost 			failpolicy = PFRULE_RETURN;
736150182e3SKristof Provost 		}
7373b3a8eb9SGleb Smirnoff 		| SET REQUIREORDER yesno {
7383b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
7393b3a8eb9SGleb Smirnoff 				printf("set require-order %s\n",
7403b3a8eb9SGleb Smirnoff 				    $3 == 1 ? "yes" : "no");
7413b3a8eb9SGleb Smirnoff 			require_order = $3;
7423b3a8eb9SGleb Smirnoff 		}
7433b3a8eb9SGleb Smirnoff 		| SET FINGERPRINTS STRING {
7443b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
7453b3a8eb9SGleb Smirnoff 				printf("set fingerprints \"%s\"\n", $3);
7463b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
7473b3a8eb9SGleb Smirnoff 				free($3);
7483b3a8eb9SGleb Smirnoff 				YYERROR;
7493b3a8eb9SGleb Smirnoff 			}
7503b3a8eb9SGleb Smirnoff 			if (!pf->anchor->name[0]) {
7513b3a8eb9SGleb Smirnoff 				if (pfctl_file_fingerprints(pf->dev,
7523b3a8eb9SGleb Smirnoff 				    pf->opts, $3)) {
7533b3a8eb9SGleb Smirnoff 					yyerror("error loading "
7543b3a8eb9SGleb Smirnoff 					    "fingerprints %s", $3);
7553b3a8eb9SGleb Smirnoff 					free($3);
7563b3a8eb9SGleb Smirnoff 					YYERROR;
7573b3a8eb9SGleb Smirnoff 				}
7583b3a8eb9SGleb Smirnoff 			}
7593b3a8eb9SGleb Smirnoff 			free($3);
7603b3a8eb9SGleb Smirnoff 		}
7613b3a8eb9SGleb Smirnoff 		| SET STATEPOLICY statelock {
7623b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
7633b3a8eb9SGleb Smirnoff 				switch ($3) {
7643b3a8eb9SGleb Smirnoff 				case 0:
7653b3a8eb9SGleb Smirnoff 					printf("set state-policy floating\n");
7663b3a8eb9SGleb Smirnoff 					break;
7673b3a8eb9SGleb Smirnoff 				case PFRULE_IFBOUND:
7683b3a8eb9SGleb Smirnoff 					printf("set state-policy if-bound\n");
7693b3a8eb9SGleb Smirnoff 					break;
7703b3a8eb9SGleb Smirnoff 				}
7713b3a8eb9SGleb Smirnoff 			default_statelock = $3;
7723b3a8eb9SGleb Smirnoff 		}
7733b3a8eb9SGleb Smirnoff 		| SET DEBUG STRING {
7743b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
7753b3a8eb9SGleb Smirnoff 				free($3);
7763b3a8eb9SGleb Smirnoff 				YYERROR;
7773b3a8eb9SGleb Smirnoff 			}
778c36c90a2SKristof Provost 			if (pfctl_do_set_debug(pf, $3) != 0) {
7793b3a8eb9SGleb Smirnoff 				yyerror("error setting debuglevel %s", $3);
7803b3a8eb9SGleb Smirnoff 				free($3);
7813b3a8eb9SGleb Smirnoff 				YYERROR;
7823b3a8eb9SGleb Smirnoff 			}
7833b3a8eb9SGleb Smirnoff 			free($3);
7843b3a8eb9SGleb Smirnoff 		}
7853b3a8eb9SGleb Smirnoff 		| SET SKIP interface {
7863b3a8eb9SGleb Smirnoff 			if (expand_skip_interface($3) != 0) {
7873b3a8eb9SGleb Smirnoff 				yyerror("error setting skip interface(s)");
7883b3a8eb9SGleb Smirnoff 				YYERROR;
7893b3a8eb9SGleb Smirnoff 			}
7903b3a8eb9SGleb Smirnoff 		}
7913b3a8eb9SGleb Smirnoff 		| SET STATEDEFAULTS state_opt_list {
7923b3a8eb9SGleb Smirnoff 			if (keep_state_defaults != NULL) {
7933b3a8eb9SGleb Smirnoff 				yyerror("cannot redefine state-defaults");
7943b3a8eb9SGleb Smirnoff 				YYERROR;
7953b3a8eb9SGleb Smirnoff 			}
7963b3a8eb9SGleb Smirnoff 			keep_state_defaults = $3;
7973b3a8eb9SGleb Smirnoff 		}
79842ec75f8SKristof Provost 		| SET KEEPCOUNTERS {
79942ec75f8SKristof Provost 			pf->keep_counters = true;
80042ec75f8SKristof Provost 		}
8015062afffSKristof Provost 		| SET SYNCOOKIES syncookie_val syncookie_opts {
8025062afffSKristof Provost 			if (pfctl_cfg_syncookies(pf, $3, $4)) {
8035062afffSKristof Provost 				yyerror("error setting syncookies");
8045062afffSKristof Provost 				YYERROR;
8055062afffSKristof Provost 			}
806c69121c4SKristof Provost 		}
807c69121c4SKristof Provost 		;
808c69121c4SKristof Provost 
809c69121c4SKristof Provost syncookie_val  : STRING        {
810c69121c4SKristof Provost 			if (!strcmp($1, "never"))
811c69121c4SKristof Provost 				$$ = PFCTL_SYNCOOKIES_NEVER;
8125062afffSKristof Provost 			else if (!strcmp($1, "adaptive"))
8135062afffSKristof Provost 				$$ = PFCTL_SYNCOOKIES_ADAPTIVE;
814c69121c4SKristof Provost 			else if (!strcmp($1, "always"))
815c69121c4SKristof Provost 				$$ = PFCTL_SYNCOOKIES_ALWAYS;
816c69121c4SKristof Provost 			else {
817c69121c4SKristof Provost 				yyerror("illegal value for syncookies");
818c69121c4SKristof Provost 				YYERROR;
819c69121c4SKristof Provost 			}
820c69121c4SKristof Provost 		}
8213b3a8eb9SGleb Smirnoff 		;
8225062afffSKristof Provost syncookie_opts  : /* empty */                   { $$ = NULL; }
8235062afffSKristof Provost 		| {
8245062afffSKristof Provost 			memset(&syncookie_opts, 0, sizeof(syncookie_opts));
8255062afffSKristof Provost 		  } '(' syncookie_opt_l ')'     { $$ = &syncookie_opts; }
8265062afffSKristof Provost 		;
8275062afffSKristof Provost 
8285062afffSKristof Provost syncookie_opt_l : syncookie_opt_l comma syncookie_opt
8295062afffSKristof Provost 		| syncookie_opt
8305062afffSKristof Provost 		;
8315062afffSKristof Provost 
8325062afffSKristof Provost syncookie_opt   : STRING STRING {
8335062afffSKristof Provost 			double   val;
8345062afffSKristof Provost 			char    *cp;
8355062afffSKristof Provost 
8365062afffSKristof Provost 			val = strtod($2, &cp);
8375062afffSKristof Provost 			if (cp == NULL || strcmp(cp, "%"))
8385062afffSKristof Provost 				YYERROR;
8395062afffSKristof Provost 			if (val <= 0 || val > 100) {
8405062afffSKristof Provost 				yyerror("illegal percentage value");
8415062afffSKristof Provost 				YYERROR;
8425062afffSKristof Provost 			}
8435062afffSKristof Provost 			if (!strcmp($1, "start")) {
8445062afffSKristof Provost 				syncookie_opts.hi = val;
8455062afffSKristof Provost 			} else if (!strcmp($1, "end")) {
8465062afffSKristof Provost 				syncookie_opts.lo = val;
8475062afffSKristof Provost 			} else {
8485062afffSKristof Provost 				yyerror("illegal syncookie option");
8495062afffSKristof Provost 				YYERROR;
8505062afffSKristof Provost 			}
8515062afffSKristof Provost 		}
8525062afffSKristof Provost 		;
8533b3a8eb9SGleb Smirnoff 
8543b3a8eb9SGleb Smirnoff stringall	: STRING	{ $$ = $1; }
8553b3a8eb9SGleb Smirnoff 		| ALL		{
8563b3a8eb9SGleb Smirnoff 			if (($$ = strdup("all")) == NULL) {
8573b3a8eb9SGleb Smirnoff 				err(1, "stringall: strdup");
8583b3a8eb9SGleb Smirnoff 			}
8593b3a8eb9SGleb Smirnoff 		}
8603b3a8eb9SGleb Smirnoff 		;
8613b3a8eb9SGleb Smirnoff 
8623b3a8eb9SGleb Smirnoff string		: STRING string				{
8633b3a8eb9SGleb Smirnoff 			if (asprintf(&$$, "%s %s", $1, $2) == -1)
8643b3a8eb9SGleb Smirnoff 				err(1, "string: asprintf");
8653b3a8eb9SGleb Smirnoff 			free($1);
8663b3a8eb9SGleb Smirnoff 			free($2);
8673b3a8eb9SGleb Smirnoff 		}
8683b3a8eb9SGleb Smirnoff 		| STRING
8693b3a8eb9SGleb Smirnoff 		;
8703b3a8eb9SGleb Smirnoff 
8713b3a8eb9SGleb Smirnoff varstring	: numberstring varstring 		{
8723b3a8eb9SGleb Smirnoff 			if (asprintf(&$$, "%s %s", $1, $2) == -1)
8733b3a8eb9SGleb Smirnoff 				err(1, "string: asprintf");
8743b3a8eb9SGleb Smirnoff 			free($1);
8753b3a8eb9SGleb Smirnoff 			free($2);
8763b3a8eb9SGleb Smirnoff 		}
8773b3a8eb9SGleb Smirnoff 		| numberstring
8783b3a8eb9SGleb Smirnoff 		;
8793b3a8eb9SGleb Smirnoff 
8803b3a8eb9SGleb Smirnoff numberstring	: NUMBER				{
8813b3a8eb9SGleb Smirnoff 			char	*s;
8823b3a8eb9SGleb Smirnoff 			if (asprintf(&s, "%lld", (long long)$1) == -1) {
8833b3a8eb9SGleb Smirnoff 				yyerror("string: asprintf");
8843b3a8eb9SGleb Smirnoff 				YYERROR;
8853b3a8eb9SGleb Smirnoff 			}
8863b3a8eb9SGleb Smirnoff 			$$ = s;
8873b3a8eb9SGleb Smirnoff 		}
8883b3a8eb9SGleb Smirnoff 		| STRING
8893b3a8eb9SGleb Smirnoff 		;
8903b3a8eb9SGleb Smirnoff 
8913b3a8eb9SGleb Smirnoff varset		: STRING '=' varstring	{
892d3f65324SKristof Provost 			char *s = $1;
8933b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE)
8943b3a8eb9SGleb Smirnoff 				printf("%s = \"%s\"\n", $1, $3);
895d3f65324SKristof Provost 			while (*s++) {
896d3f65324SKristof Provost 				if (isspace((unsigned char)*s)) {
897d3f65324SKristof Provost 					yyerror("macro name cannot contain "
898d3f65324SKristof Provost 					   "whitespace");
899d3f65324SKristof Provost 					YYERROR;
900d3f65324SKristof Provost 				}
901d3f65324SKristof Provost 			}
9023b3a8eb9SGleb Smirnoff 			if (symset($1, $3, 0) == -1)
9033b3a8eb9SGleb Smirnoff 				err(1, "cannot store variable %s", $1);
9043b3a8eb9SGleb Smirnoff 			free($1);
9053b3a8eb9SGleb Smirnoff 			free($3);
9063b3a8eb9SGleb Smirnoff 		}
9073b3a8eb9SGleb Smirnoff 		;
9083b3a8eb9SGleb Smirnoff 
9093b3a8eb9SGleb Smirnoff anchorname	: STRING			{ $$ = $1; }
9103b3a8eb9SGleb Smirnoff 		| /* empty */			{ $$ = NULL; }
9113b3a8eb9SGleb Smirnoff 		;
9123b3a8eb9SGleb Smirnoff 
9133b3a8eb9SGleb Smirnoff pfa_anchorlist	: /* empty */
9143b3a8eb9SGleb Smirnoff 		| pfa_anchorlist '\n'
9153b3a8eb9SGleb Smirnoff 		| pfa_anchorlist pfrule '\n'
9163b3a8eb9SGleb Smirnoff 		| pfa_anchorlist anchorrule '\n'
9173b3a8eb9SGleb Smirnoff 		;
9183b3a8eb9SGleb Smirnoff 
9193b3a8eb9SGleb Smirnoff pfa_anchor	: '{'
9203b3a8eb9SGleb Smirnoff 		{
9213b3a8eb9SGleb Smirnoff 			char ta[PF_ANCHOR_NAME_SIZE];
922e9eb0941SKristof Provost 			struct pfctl_ruleset *rs;
9233b3a8eb9SGleb Smirnoff 
9242fa6223aSGordon Bergling 			/* stepping into a brace anchor */
9253b3a8eb9SGleb Smirnoff 			pf->asd++;
9263b3a8eb9SGleb Smirnoff 			pf->bn++;
9273b3a8eb9SGleb Smirnoff 
928585a5ed0SKristof Provost 			/*
929585a5ed0SKristof Provost 			* Anchor contents are parsed before the anchor rule
930585a5ed0SKristof Provost 			* production completes, so we don't know the real
931585a5ed0SKristof Provost 			* location yet. Create a holding ruleset in the root;
932585a5ed0SKristof Provost 			* contents will be moved afterwards.
933585a5ed0SKristof Provost 			*/
9343b3a8eb9SGleb Smirnoff 			snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
9353b3a8eb9SGleb Smirnoff 			rs = pf_find_or_create_ruleset(ta);
9363b3a8eb9SGleb Smirnoff 			if (rs == NULL)
9373b3a8eb9SGleb Smirnoff 				err(1, "pfa_anchor: pf_find_or_create_ruleset");
9383b3a8eb9SGleb Smirnoff 			pf->astack[pf->asd] = rs->anchor;
9393b3a8eb9SGleb Smirnoff 			pf->anchor = rs->anchor;
9403b3a8eb9SGleb Smirnoff 		} '\n' pfa_anchorlist '}'
9413b3a8eb9SGleb Smirnoff 		{
9423b3a8eb9SGleb Smirnoff 			pf->alast = pf->anchor;
9433b3a8eb9SGleb Smirnoff 			pf->asd--;
9443b3a8eb9SGleb Smirnoff 			pf->anchor = pf->astack[pf->asd];
9453b3a8eb9SGleb Smirnoff 		}
9463b3a8eb9SGleb Smirnoff 		| /* empty */
9473b3a8eb9SGleb Smirnoff 		;
9483b3a8eb9SGleb Smirnoff 
9493b3a8eb9SGleb Smirnoff anchorrule	: ANCHOR anchorname dir quick interface af proto fromto
9503b3a8eb9SGleb Smirnoff 		    filter_opts pfa_anchor
9513b3a8eb9SGleb Smirnoff 		{
952e9eb0941SKristof Provost 			struct pfctl_rule	r;
9533b3a8eb9SGleb Smirnoff 			struct node_proto	*proto;
9543b3a8eb9SGleb Smirnoff 
9553b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_FILTER)) {
9563b3a8eb9SGleb Smirnoff 				if ($2)
9573b3a8eb9SGleb Smirnoff 					free($2);
9583b3a8eb9SGleb Smirnoff 				YYERROR;
9593b3a8eb9SGleb Smirnoff 			}
9603b3a8eb9SGleb Smirnoff 
9613b3a8eb9SGleb Smirnoff 			if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
9623b3a8eb9SGleb Smirnoff 				free($2);
9633b3a8eb9SGleb Smirnoff 				yyerror("anchor names beginning with '_' "
9643b3a8eb9SGleb Smirnoff 				    "are reserved for internal use");
9653b3a8eb9SGleb Smirnoff 				YYERROR;
9663b3a8eb9SGleb Smirnoff 			}
9673b3a8eb9SGleb Smirnoff 
9683b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
9693b3a8eb9SGleb Smirnoff 			if (pf->astack[pf->asd + 1]) {
970585a5ed0SKristof Provost 				if ($2 && strchr($2, '/') != NULL) {
971585a5ed0SKristof Provost 					free($2);
972585a5ed0SKristof Provost 					yyerror("anchor paths containing '/' "
973585a5ed0SKristof Provost 					   "cannot be used for inline anchors.");
974585a5ed0SKristof Provost 					YYERROR;
975585a5ed0SKristof Provost 				}
976585a5ed0SKristof Provost 
977585a5ed0SKristof Provost 				/* Move inline rules into relative location. */
978e9eb0941SKristof Provost 				pfctl_anchor_setup(&r,
9793b3a8eb9SGleb Smirnoff 				    &pf->astack[pf->asd]->ruleset,
9803b3a8eb9SGleb Smirnoff 				    $2 ? $2 : pf->alast->name);
9813b3a8eb9SGleb Smirnoff 
9823b3a8eb9SGleb Smirnoff 				if (r.anchor == NULL)
9833b3a8eb9SGleb Smirnoff 					err(1, "anchorrule: unable to "
9843b3a8eb9SGleb Smirnoff 					    "create ruleset");
9853b3a8eb9SGleb Smirnoff 
9863b3a8eb9SGleb Smirnoff 				if (pf->alast != r.anchor) {
9873b3a8eb9SGleb Smirnoff 					if (r.anchor->match) {
9883b3a8eb9SGleb Smirnoff 						yyerror("inline anchor '%s' "
9893b3a8eb9SGleb Smirnoff 						    "already exists",
9903b3a8eb9SGleb Smirnoff 						    r.anchor->name);
9913b3a8eb9SGleb Smirnoff 						YYERROR;
9923b3a8eb9SGleb Smirnoff 					}
9933b3a8eb9SGleb Smirnoff 					mv_rules(&pf->alast->ruleset,
9943b3a8eb9SGleb Smirnoff 					    &r.anchor->ruleset);
9953b3a8eb9SGleb Smirnoff 				}
9963b3a8eb9SGleb Smirnoff 				pf_remove_if_empty_ruleset(&pf->alast->ruleset);
9973b3a8eb9SGleb Smirnoff 				pf->alast = r.anchor;
9983b3a8eb9SGleb Smirnoff 			} else {
9993b3a8eb9SGleb Smirnoff 				if (!$2) {
10003b3a8eb9SGleb Smirnoff 					yyerror("anchors without explicit "
10013b3a8eb9SGleb Smirnoff 					    "rules must specify a name");
10023b3a8eb9SGleb Smirnoff 					YYERROR;
10033b3a8eb9SGleb Smirnoff 				}
10043b3a8eb9SGleb Smirnoff 			}
10053b3a8eb9SGleb Smirnoff 			r.direction = $3;
10063b3a8eb9SGleb Smirnoff 			r.quick = $4.quick;
10073b3a8eb9SGleb Smirnoff 			r.af = $6;
10083b3a8eb9SGleb Smirnoff 			r.prob = $9.prob;
10093b3a8eb9SGleb Smirnoff 			r.rtableid = $9.rtableid;
101076c5eeccSKristof Provost 			r.ridentifier = $9.ridentifier;
10113b3a8eb9SGleb Smirnoff 
10123b3a8eb9SGleb Smirnoff 			if ($9.tag)
10133b3a8eb9SGleb Smirnoff 				if (strlcpy(r.tagname, $9.tag,
10143b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
10153b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
10163b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
10173b3a8eb9SGleb Smirnoff 					YYERROR;
10183b3a8eb9SGleb Smirnoff 				}
10193b3a8eb9SGleb Smirnoff 			if ($9.match_tag)
10203b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $9.match_tag,
10213b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
10223b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
10233b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
10243b3a8eb9SGleb Smirnoff 					YYERROR;
10253b3a8eb9SGleb Smirnoff 				}
10263b3a8eb9SGleb Smirnoff 			r.match_tag_not = $9.match_tag_not;
10273b3a8eb9SGleb Smirnoff 			if (rule_label(&r, $9.label))
10283b3a8eb9SGleb Smirnoff 				YYERROR;
10296fcc8e04SKristof Provost 			for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
10306fcc8e04SKristof Provost 				free($9.label[i]);
10313b3a8eb9SGleb Smirnoff 			r.flags = $9.flags.b1;
10323b3a8eb9SGleb Smirnoff 			r.flagset = $9.flags.b2;
10333b3a8eb9SGleb Smirnoff 			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
10343b3a8eb9SGleb Smirnoff 				yyerror("flags always false");
10353b3a8eb9SGleb Smirnoff 				YYERROR;
10363b3a8eb9SGleb Smirnoff 			}
10373b3a8eb9SGleb Smirnoff 			if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
10383b3a8eb9SGleb Smirnoff 				for (proto = $7; proto != NULL &&
10393b3a8eb9SGleb Smirnoff 				    proto->proto != IPPROTO_TCP;
10403b3a8eb9SGleb Smirnoff 				    proto = proto->next)
10413b3a8eb9SGleb Smirnoff 					;	/* nothing */
10423b3a8eb9SGleb Smirnoff 				if (proto == NULL && $7 != NULL) {
10433b3a8eb9SGleb Smirnoff 					if ($9.flags.b1 || $9.flags.b2)
10443b3a8eb9SGleb Smirnoff 						yyerror(
10453b3a8eb9SGleb Smirnoff 						    "flags only apply to tcp");
10463b3a8eb9SGleb Smirnoff 					if ($8.src_os)
10473b3a8eb9SGleb Smirnoff 						yyerror(
10483b3a8eb9SGleb Smirnoff 						    "OS fingerprinting only "
10493b3a8eb9SGleb Smirnoff 						    "applies to tcp");
10503b3a8eb9SGleb Smirnoff 					YYERROR;
10513b3a8eb9SGleb Smirnoff 				}
10523b3a8eb9SGleb Smirnoff 			}
10533b3a8eb9SGleb Smirnoff 
10543b3a8eb9SGleb Smirnoff 			r.tos = $9.tos;
10553b3a8eb9SGleb Smirnoff 
10563b3a8eb9SGleb Smirnoff 			if ($9.keep.action) {
10573b3a8eb9SGleb Smirnoff 				yyerror("cannot specify state handling "
10583b3a8eb9SGleb Smirnoff 				    "on anchors");
10593b3a8eb9SGleb Smirnoff 				YYERROR;
10603b3a8eb9SGleb Smirnoff 			}
10613b3a8eb9SGleb Smirnoff 
10623b3a8eb9SGleb Smirnoff 			if ($9.match_tag)
10633b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $9.match_tag,
10643b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
10653b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
10663b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
10673b3a8eb9SGleb Smirnoff 					YYERROR;
10683b3a8eb9SGleb Smirnoff 				}
10693b3a8eb9SGleb Smirnoff 			r.match_tag_not = $9.match_tag_not;
10703e248e0fSKristof Provost 			if ($9.marker & FOM_PRIO) {
10713e248e0fSKristof Provost 				if ($9.prio == 0)
10723e248e0fSKristof Provost 					r.prio = PF_PRIO_ZERO;
10733e248e0fSKristof Provost 				else
10743e248e0fSKristof Provost 					r.prio = $9.prio;
10753e248e0fSKristof Provost 			}
10763e248e0fSKristof Provost 			if ($9.marker & FOM_SETPRIO) {
10773e248e0fSKristof Provost 				r.set_prio[0] = $9.set_prio[0];
10783e248e0fSKristof Provost 				r.set_prio[1] = $9.set_prio[1];
10793e248e0fSKristof Provost 				r.scrub_flags |= PFSTATE_SETPRIO;
10803e248e0fSKristof Provost 			}
10813b3a8eb9SGleb Smirnoff 
10823b3a8eb9SGleb Smirnoff 			decide_address_family($8.src.host, &r.af);
10833b3a8eb9SGleb Smirnoff 			decide_address_family($8.dst.host, &r.af);
10843b3a8eb9SGleb Smirnoff 
10850972294eSKristof Provost 			expand_rule(&r, $5, NULL, NULL, NULL, NULL, NULL, NULL,
10860972294eSKristof Provost 			    $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host,
10870972294eSKristof Provost 			    $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec,
10883b3a8eb9SGleb Smirnoff 			    pf->astack[pf->asd + 1] ? pf->alast->name : $2);
10893b3a8eb9SGleb Smirnoff 			free($2);
10903b3a8eb9SGleb Smirnoff 			pf->astack[pf->asd + 1] = NULL;
10913b3a8eb9SGleb Smirnoff 		}
10923b3a8eb9SGleb Smirnoff 		| NATANCHOR string interface af proto fromto rtable {
1093e9eb0941SKristof Provost 			struct pfctl_rule	r;
10943b3a8eb9SGleb Smirnoff 
10953b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT)) {
10963b3a8eb9SGleb Smirnoff 				free($2);
10973b3a8eb9SGleb Smirnoff 				YYERROR;
10983b3a8eb9SGleb Smirnoff 			}
10993b3a8eb9SGleb Smirnoff 
11003b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
11013b3a8eb9SGleb Smirnoff 			r.action = PF_NAT;
11023b3a8eb9SGleb Smirnoff 			r.af = $4;
11033b3a8eb9SGleb Smirnoff 			r.rtableid = $7;
11043b3a8eb9SGleb Smirnoff 
11053b3a8eb9SGleb Smirnoff 			decide_address_family($6.src.host, &r.af);
11063b3a8eb9SGleb Smirnoff 			decide_address_family($6.dst.host, &r.af);
11073b3a8eb9SGleb Smirnoff 
11080972294eSKristof Provost 			expand_rule(&r, $3, NULL, NULL, NULL, NULL, NULL, NULL,
11090972294eSKristof Provost 			    $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host,
11100972294eSKristof Provost 			    $6.dst.port, 0, 0, 0, 0, $2);
11113b3a8eb9SGleb Smirnoff 			free($2);
11123b3a8eb9SGleb Smirnoff 		}
11133b3a8eb9SGleb Smirnoff 		| RDRANCHOR string interface af proto fromto rtable {
1114e9eb0941SKristof Provost 			struct pfctl_rule	r;
11153b3a8eb9SGleb Smirnoff 
11163b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT)) {
11173b3a8eb9SGleb Smirnoff 				free($2);
11183b3a8eb9SGleb Smirnoff 				YYERROR;
11193b3a8eb9SGleb Smirnoff 			}
11203b3a8eb9SGleb Smirnoff 
11213b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
11223b3a8eb9SGleb Smirnoff 			r.action = PF_RDR;
11233b3a8eb9SGleb Smirnoff 			r.af = $4;
11243b3a8eb9SGleb Smirnoff 			r.rtableid = $7;
11253b3a8eb9SGleb Smirnoff 
11263b3a8eb9SGleb Smirnoff 			decide_address_family($6.src.host, &r.af);
11273b3a8eb9SGleb Smirnoff 			decide_address_family($6.dst.host, &r.af);
11283b3a8eb9SGleb Smirnoff 
11293b3a8eb9SGleb Smirnoff 			if ($6.src.port != NULL) {
11303b3a8eb9SGleb Smirnoff 				yyerror("source port parameter not supported"
11313b3a8eb9SGleb Smirnoff 				    " in rdr-anchor");
11323b3a8eb9SGleb Smirnoff 				YYERROR;
11333b3a8eb9SGleb Smirnoff 			}
11343b3a8eb9SGleb Smirnoff 			if ($6.dst.port != NULL) {
11353b3a8eb9SGleb Smirnoff 				if ($6.dst.port->next != NULL) {
11363b3a8eb9SGleb Smirnoff 					yyerror("destination port list "
11373b3a8eb9SGleb Smirnoff 					    "expansion not supported in "
11383b3a8eb9SGleb Smirnoff 					    "rdr-anchor");
11393b3a8eb9SGleb Smirnoff 					YYERROR;
11403b3a8eb9SGleb Smirnoff 				} else if ($6.dst.port->op != PF_OP_EQ) {
11413b3a8eb9SGleb Smirnoff 					yyerror("destination port operators"
11423b3a8eb9SGleb Smirnoff 					    " not supported in rdr-anchor");
11433b3a8eb9SGleb Smirnoff 					YYERROR;
11443b3a8eb9SGleb Smirnoff 				}
11453b3a8eb9SGleb Smirnoff 				r.dst.port[0] = $6.dst.port->port[0];
11463b3a8eb9SGleb Smirnoff 				r.dst.port[1] = $6.dst.port->port[1];
11473b3a8eb9SGleb Smirnoff 				r.dst.port_op = $6.dst.port->op;
11483b3a8eb9SGleb Smirnoff 			}
11493b3a8eb9SGleb Smirnoff 
11500972294eSKristof Provost 			expand_rule(&r, $3, NULL, NULL, NULL, NULL, NULL, NULL,
11510972294eSKristof Provost 			    $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host,
11520972294eSKristof Provost 			    $6.dst.port, 0, 0, 0, 0, $2);
11533b3a8eb9SGleb Smirnoff 			free($2);
11543b3a8eb9SGleb Smirnoff 		}
11553b3a8eb9SGleb Smirnoff 		| BINATANCHOR string interface af proto fromto rtable {
1156e9eb0941SKristof Provost 			struct pfctl_rule	r;
11573b3a8eb9SGleb Smirnoff 
11583b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT)) {
11593b3a8eb9SGleb Smirnoff 				free($2);
11603b3a8eb9SGleb Smirnoff 				YYERROR;
11613b3a8eb9SGleb Smirnoff 			}
11623b3a8eb9SGleb Smirnoff 
11633b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
11643b3a8eb9SGleb Smirnoff 			r.action = PF_BINAT;
11653b3a8eb9SGleb Smirnoff 			r.af = $4;
11663b3a8eb9SGleb Smirnoff 			r.rtableid = $7;
11673b3a8eb9SGleb Smirnoff 			if ($5 != NULL) {
11683b3a8eb9SGleb Smirnoff 				if ($5->next != NULL) {
11693b3a8eb9SGleb Smirnoff 					yyerror("proto list expansion"
11703b3a8eb9SGleb Smirnoff 					    " not supported in binat-anchor");
11713b3a8eb9SGleb Smirnoff 					YYERROR;
11723b3a8eb9SGleb Smirnoff 				}
11733b3a8eb9SGleb Smirnoff 				r.proto = $5->proto;
11743b3a8eb9SGleb Smirnoff 				free($5);
11753b3a8eb9SGleb Smirnoff 			}
11763b3a8eb9SGleb Smirnoff 
11773b3a8eb9SGleb Smirnoff 			if ($6.src.host != NULL || $6.src.port != NULL ||
11783b3a8eb9SGleb Smirnoff 			    $6.dst.host != NULL || $6.dst.port != NULL) {
11793b3a8eb9SGleb Smirnoff 				yyerror("fromto parameter not supported"
11803b3a8eb9SGleb Smirnoff 				    " in binat-anchor");
11813b3a8eb9SGleb Smirnoff 				YYERROR;
11823b3a8eb9SGleb Smirnoff 			}
11833b3a8eb9SGleb Smirnoff 
11843b3a8eb9SGleb Smirnoff 			decide_address_family($6.src.host, &r.af);
11853b3a8eb9SGleb Smirnoff 			decide_address_family($6.dst.host, &r.af);
11863b3a8eb9SGleb Smirnoff 
11870d71f9f3SKristof Provost 			pfctl_append_rule(pf, &r, $2);
11883b3a8eb9SGleb Smirnoff 			free($2);
11893b3a8eb9SGleb Smirnoff 		}
11903b3a8eb9SGleb Smirnoff 		;
11913b3a8eb9SGleb Smirnoff 
11923b3a8eb9SGleb Smirnoff loadrule	: LOAD ANCHOR string FROM string	{
11933b3a8eb9SGleb Smirnoff 			struct loadanchors	*loadanchor;
11943b3a8eb9SGleb Smirnoff 
11953b3a8eb9SGleb Smirnoff 			if (strlen(pf->anchor->name) + 1 +
11963b3a8eb9SGleb Smirnoff 			    strlen($3) >= MAXPATHLEN) {
11973b3a8eb9SGleb Smirnoff 				yyerror("anchorname %s too long, max %u\n",
11983b3a8eb9SGleb Smirnoff 				    $3, MAXPATHLEN - 1);
11993b3a8eb9SGleb Smirnoff 				free($3);
12003b3a8eb9SGleb Smirnoff 				YYERROR;
12013b3a8eb9SGleb Smirnoff 			}
12023b3a8eb9SGleb Smirnoff 			loadanchor = calloc(1, sizeof(struct loadanchors));
12033b3a8eb9SGleb Smirnoff 			if (loadanchor == NULL)
12043b3a8eb9SGleb Smirnoff 				err(1, "loadrule: calloc");
12053b3a8eb9SGleb Smirnoff 			if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
12063b3a8eb9SGleb Smirnoff 			    NULL)
12073b3a8eb9SGleb Smirnoff 				err(1, "loadrule: malloc");
12083b3a8eb9SGleb Smirnoff 			if (pf->anchor->name[0])
12093b3a8eb9SGleb Smirnoff 				snprintf(loadanchor->anchorname, MAXPATHLEN,
12103b3a8eb9SGleb Smirnoff 				    "%s/%s", pf->anchor->name, $3);
12113b3a8eb9SGleb Smirnoff 			else
12123b3a8eb9SGleb Smirnoff 				strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
12133b3a8eb9SGleb Smirnoff 			if ((loadanchor->filename = strdup($5)) == NULL)
12143b3a8eb9SGleb Smirnoff 				err(1, "loadrule: strdup");
12153b3a8eb9SGleb Smirnoff 
12163b3a8eb9SGleb Smirnoff 			TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
12173b3a8eb9SGleb Smirnoff 			    entries);
12183b3a8eb9SGleb Smirnoff 
12193b3a8eb9SGleb Smirnoff 			free($3);
12203b3a8eb9SGleb Smirnoff 			free($5);
12213b3a8eb9SGleb Smirnoff 		};
12223b3a8eb9SGleb Smirnoff 
12233b3a8eb9SGleb Smirnoff scrubaction	: no SCRUB {
12243b3a8eb9SGleb Smirnoff 			$$.b2 = $$.w = 0;
12253b3a8eb9SGleb Smirnoff 			if ($1)
12263b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NOSCRUB;
12273b3a8eb9SGleb Smirnoff 			else
12283b3a8eb9SGleb Smirnoff 				$$.b1 = PF_SCRUB;
12293b3a8eb9SGleb Smirnoff 		}
12303b3a8eb9SGleb Smirnoff 		;
12313b3a8eb9SGleb Smirnoff 
12328a8af942SKristof Provost etherrule	: ETHER action dir quick interface bridge etherproto etherfromto l3fromto etherfilter_opts
12332b29ceb8SKristof Provost 		{
12342b29ceb8SKristof Provost 			struct pfctl_eth_rule	r;
12352b29ceb8SKristof Provost 
12362b29ceb8SKristof Provost 			bzero(&r, sizeof(r));
12372b29ceb8SKristof Provost 
12382b29ceb8SKristof Provost 			if (check_rulestate(PFCTL_STATE_ETHER))
12392b29ceb8SKristof Provost 				YYERROR;
12402b29ceb8SKristof Provost 
12412b29ceb8SKristof Provost 			r.action = $2.b1;
12422b29ceb8SKristof Provost 			r.direction = $3;
12432b29ceb8SKristof Provost 			r.quick = $4.quick;
12448a8af942SKristof Provost 			if ($10.tag != NULL)
1245dc3ee89cSKristof Provost 				strlcpy(r.tagname, $10.tag, sizeof(r.tagname));
12468a8af942SKristof Provost 			if ($10.match_tag)
12478a8af942SKristof Provost 				if (strlcpy(r.match_tagname, $10.match_tag,
12481f61367fSKristof Provost 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
12491f61367fSKristof Provost 					yyerror("tag too long, max %u chars",
12501f61367fSKristof Provost 					    PF_TAG_NAME_SIZE - 1);
12511f61367fSKristof Provost 					YYERROR;
12521f61367fSKristof Provost 				}
12538a8af942SKristof Provost 			r.match_tag_not = $10.match_tag_not;
12548a8af942SKristof Provost 			if ($10.queues.qname != NULL)
1255dc3ee89cSKristof Provost 				strlcpy(r.qname, $10.queues.qname, sizeof(r.qname));
12568a8af942SKristof Provost 			r.dnpipe = $10.dnpipe;
12578a8af942SKristof Provost 			r.dnflags = $10.free_flags;
1258ef661d4aSChristian McDonald 			if (eth_rule_label(&r, $10.label))
1259ef661d4aSChristian McDonald 				YYERROR;
1260ef661d4aSChristian McDonald 			for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
1261ef661d4aSChristian McDonald 				free($10.label[i]);
1262ef661d4aSChristian McDonald 			r.ridentifier = $10.ridentifier;
12632b29ceb8SKristof Provost 
12648a8af942SKristof Provost 			expand_eth_rule(&r, $5, $7, $8.src, $8.dst,
12658a8af942SKristof Provost 			    $9.src.host, $9.dst.host, $6, "");
1266c5131afeSKristof Provost 		}
1267c5131afeSKristof Provost 		;
1268c5131afeSKristof Provost 
1269c5131afeSKristof Provost etherpfa_anchorlist	: /* empty */
1270c5131afeSKristof Provost 		| etherpfa_anchorlist '\n'
1271c5131afeSKristof Provost 		| etherpfa_anchorlist etherrule '\n'
1272c5131afeSKristof Provost 		| etherpfa_anchorlist etheranchorrule '\n'
1273c5131afeSKristof Provost 		;
1274c5131afeSKristof Provost 
1275c5131afeSKristof Provost etherpfa_anchor	: '{'
1276c5131afeSKristof Provost 		{
1277c5131afeSKristof Provost 			char ta[PF_ANCHOR_NAME_SIZE];
1278c5131afeSKristof Provost 			struct pfctl_eth_ruleset *rs;
1279c5131afeSKristof Provost 
1280c5131afeSKristof Provost 			/* steping into a brace anchor */
1281c5131afeSKristof Provost 			pf->asd++;
1282c5131afeSKristof Provost 			pf->bn++;
1283c5131afeSKristof Provost 
1284c5131afeSKristof Provost 			/* create a holding ruleset in the root */
1285c5131afeSKristof Provost 			snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
1286c5131afeSKristof Provost 			rs = pf_find_or_create_eth_ruleset(ta);
1287c5131afeSKristof Provost 			if (rs == NULL)
1288c5131afeSKristof Provost 				err(1, "etherpfa_anchor: pf_find_or_create_eth_ruleset");
1289c5131afeSKristof Provost 			pf->eastack[pf->asd] = rs->anchor;
1290c5131afeSKristof Provost 			pf->eanchor = rs->anchor;
1291c5131afeSKristof Provost 		} '\n' etherpfa_anchorlist '}'
1292c5131afeSKristof Provost 		{
1293c5131afeSKristof Provost 			pf->ealast = pf->eanchor;
1294c5131afeSKristof Provost 			pf->asd--;
1295c5131afeSKristof Provost 			pf->eanchor = pf->eastack[pf->asd];
1296c5131afeSKristof Provost 		}
1297c5131afeSKristof Provost 		| /* empty */
1298c5131afeSKristof Provost 		;
1299c5131afeSKristof Provost 
13008a42005dSKristof Provost etheranchorrule	: ETHER ANCHOR anchorname dir quick interface etherproto etherfromto l3fromto etherpfa_anchor
1301c5131afeSKristof Provost 		{
1302c5131afeSKristof Provost 			struct pfctl_eth_rule	r;
1303c5131afeSKristof Provost 
1304c5131afeSKristof Provost 			if (check_rulestate(PFCTL_STATE_ETHER)) {
1305c5131afeSKristof Provost 				free($3);
1306c5131afeSKristof Provost 				YYERROR;
1307c5131afeSKristof Provost 			}
1308c5131afeSKristof Provost 
1309c5131afeSKristof Provost 			if ($3 && ($3[0] == '_' || strstr($3, "/_") != NULL)) {
1310c5131afeSKristof Provost 				free($3);
1311c5131afeSKristof Provost 				yyerror("anchor names beginning with '_' "
1312c5131afeSKristof Provost 				    "are reserved for internal use");
1313c5131afeSKristof Provost 				YYERROR;
1314c5131afeSKristof Provost 			}
1315c5131afeSKristof Provost 
1316c5131afeSKristof Provost 			memset(&r, 0, sizeof(r));
1317c5131afeSKristof Provost 			if (pf->eastack[pf->asd + 1]) {
1318cfa1a130SKristof Provost 				if ($3 && strchr($3, '/') != NULL) {
1319cfa1a130SKristof Provost 					free($3);
1320cfa1a130SKristof Provost 					yyerror("anchor paths containing '/' "
1321cfa1a130SKristof Provost 					   "cannot be used for inline anchors.");
1322cfa1a130SKristof Provost 					YYERROR;
1323cfa1a130SKristof Provost 				}
1324cfa1a130SKristof Provost 
1325cfa1a130SKristof Provost 				/* Move inline rules into relative location. */
1326c5131afeSKristof Provost 				pfctl_eth_anchor_setup(pf, &r,
1327c5131afeSKristof Provost 				    &pf->eastack[pf->asd]->ruleset,
1328c5131afeSKristof Provost 				    $3 ? $3 : pf->ealast->name);
1329c5131afeSKristof Provost 				if (r.anchor == NULL)
1330c5131afeSKristof Provost 					err(1, "etheranchorrule: unable to "
1331c5131afeSKristof Provost 					    "create ruleset");
1332c5131afeSKristof Provost 
1333c5131afeSKristof Provost 				if (pf->ealast != r.anchor) {
1334c5131afeSKristof Provost 					if (r.anchor->match) {
1335c5131afeSKristof Provost 						yyerror("inline anchor '%s' "
1336c5131afeSKristof Provost 						    "already exists",
1337c5131afeSKristof Provost 						    r.anchor->name);
1338c5131afeSKristof Provost 						YYERROR;
1339c5131afeSKristof Provost 					}
1340c5131afeSKristof Provost 					mv_eth_rules(&pf->ealast->ruleset,
1341c5131afeSKristof Provost 					    &r.anchor->ruleset);
1342c5131afeSKristof Provost 				}
1343c5131afeSKristof Provost 				pf_remove_if_empty_eth_ruleset(&pf->ealast->ruleset);
1344c5131afeSKristof Provost 				pf->ealast = r.anchor;
1345c5131afeSKristof Provost 			} else {
1346c5131afeSKristof Provost 				if (!$3) {
1347c5131afeSKristof Provost 					yyerror("anchors without explicit "
1348c5131afeSKristof Provost 					    "rules must specify a name");
1349c5131afeSKristof Provost 					YYERROR;
1350c5131afeSKristof Provost 				}
1351c5131afeSKristof Provost 			}
1352c5131afeSKristof Provost 
1353c5131afeSKristof Provost 			r.direction = $4;
1354c5131afeSKristof Provost 			r.quick = $5.quick;
1355c5131afeSKristof Provost 
1356c5131afeSKristof Provost 			expand_eth_rule(&r, $6, $7, $8.src, $8.dst,
13578a8af942SKristof Provost 			    $9.src.host, $9.dst.host, NULL,
1358c5131afeSKristof Provost 			    pf->eastack[pf->asd + 1] ? pf->ealast->name : $3);
1359c5131afeSKristof Provost 
1360c5131afeSKristof Provost 			free($3);
1361c5131afeSKristof Provost 			pf->eastack[pf->asd + 1] = NULL;
13622b29ceb8SKristof Provost 		}
13632b29ceb8SKristof Provost 		;
13642b29ceb8SKristof Provost 
13652b29ceb8SKristof Provost etherfilter_opts	:	{
13662b29ceb8SKristof Provost 				bzero(&filter_opts, sizeof filter_opts);
13672b29ceb8SKristof Provost 			}
13682b29ceb8SKristof Provost 		    etherfilter_opts_l
13692b29ceb8SKristof Provost 			{ $$ = filter_opts; }
13702b29ceb8SKristof Provost 		| /* empty */	{
13712b29ceb8SKristof Provost 			bzero(&filter_opts, sizeof filter_opts);
13722b29ceb8SKristof Provost 			$$ = filter_opts;
13732b29ceb8SKristof Provost 		}
13742b29ceb8SKristof Provost 		;
13752b29ceb8SKristof Provost 
13762b29ceb8SKristof Provost etherfilter_opts_l	: etherfilter_opts_l etherfilter_opt
13772b29ceb8SKristof Provost 			| etherfilter_opt
13782b29ceb8SKristof Provost 
13792b29ceb8SKristof Provost etherfilter_opt	: etherqname	{
13802b29ceb8SKristof Provost 			if (filter_opts.queues.qname) {
13812b29ceb8SKristof Provost 				yyerror("queue cannot be redefined");
13822b29ceb8SKristof Provost 				YYERROR;
13832b29ceb8SKristof Provost 			}
13842b29ceb8SKristof Provost 			filter_opts.queues = $1;
13852b29ceb8SKristof Provost 		}
1386ef661d4aSChristian McDonald 		| RIDENTIFIER number {
1387ef661d4aSChristian McDonald 			filter_opts.ridentifier = $2;
1388ef661d4aSChristian McDonald 		}
1389ef661d4aSChristian McDonald 		| label	{
1390ef661d4aSChristian McDonald 			if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) {
1391ef661d4aSChristian McDonald 				yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT);
1392ef661d4aSChristian McDonald 				YYERROR;
1393ef661d4aSChristian McDonald 			}
1394ef661d4aSChristian McDonald 			filter_opts.label[filter_opts.labelcount++] = $1;
1395ef661d4aSChristian McDonald 		}
13962b29ceb8SKristof Provost 		| TAG string				{
13972b29ceb8SKristof Provost 			filter_opts.tag = $2;
13982b29ceb8SKristof Provost 		}
13991f61367fSKristof Provost 		| not TAGGED string			{
14001f61367fSKristof Provost 			filter_opts.match_tag = $3;
14011f61367fSKristof Provost 			filter_opts.match_tag_not = $1;
14021f61367fSKristof Provost 		}
1403fb330f39SKristof Provost 		| DNPIPE number {
1404fb330f39SKristof Provost 			filter_opts.dnpipe = $2;
1405fb330f39SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
1406fb330f39SKristof Provost 		}
1407fb330f39SKristof Provost 		| DNQUEUE number {
1408fb330f39SKristof Provost 			filter_opts.dnpipe = $2;
1409fb330f39SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
1410fb330f39SKristof Provost 		}
14112b29ceb8SKristof Provost 		;
14122b29ceb8SKristof Provost 
14138a8af942SKristof Provost bridge		:	/* empty */		{
14148a8af942SKristof Provost 			$$ = NULL;
14158a8af942SKristof Provost 		}
14168a8af942SKristof Provost 		| BRIDGE_TO STRING {
14178a8af942SKristof Provost 			$$ = strdup($2);
14188a8af942SKristof Provost 		}
14198a8af942SKristof Provost 		;
14208a8af942SKristof Provost 
14213b3a8eb9SGleb Smirnoff scrubrule	: scrubaction dir logquick interface af proto fromto scrub_opts
14223b3a8eb9SGleb Smirnoff 		{
1423e9eb0941SKristof Provost 			struct pfctl_rule	r;
14243b3a8eb9SGleb Smirnoff 
14253b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_SCRUB))
14263b3a8eb9SGleb Smirnoff 				YYERROR;
14273b3a8eb9SGleb Smirnoff 
14283b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
14293b3a8eb9SGleb Smirnoff 
14303b3a8eb9SGleb Smirnoff 			r.action = $1.b1;
14313b3a8eb9SGleb Smirnoff 			r.direction = $2;
14323b3a8eb9SGleb Smirnoff 
14333b3a8eb9SGleb Smirnoff 			r.log = $3.log;
14343b3a8eb9SGleb Smirnoff 			r.logif = $3.logif;
14353b3a8eb9SGleb Smirnoff 			if ($3.quick) {
14363b3a8eb9SGleb Smirnoff 				yyerror("scrub rules do not support 'quick'");
14373b3a8eb9SGleb Smirnoff 				YYERROR;
14383b3a8eb9SGleb Smirnoff 			}
14393b3a8eb9SGleb Smirnoff 
14403b3a8eb9SGleb Smirnoff 			r.af = $5;
14413b3a8eb9SGleb Smirnoff 			if ($8.nodf)
14423b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_NODF;
14433b3a8eb9SGleb Smirnoff 			if ($8.randomid)
14443b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RANDOMID;
14453b3a8eb9SGleb Smirnoff 			if ($8.reassemble_tcp) {
14463b3a8eb9SGleb Smirnoff 				if (r.direction != PF_INOUT) {
14473b3a8eb9SGleb Smirnoff 					yyerror("reassemble tcp rules can not "
14483b3a8eb9SGleb Smirnoff 					    "specify direction");
14493b3a8eb9SGleb Smirnoff 					YYERROR;
14503b3a8eb9SGleb Smirnoff 				}
14513b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_REASSEMBLE_TCP;
14523b3a8eb9SGleb Smirnoff 			}
14533b3a8eb9SGleb Smirnoff 			if ($8.minttl)
14543b3a8eb9SGleb Smirnoff 				r.min_ttl = $8.minttl;
14553b3a8eb9SGleb Smirnoff 			if ($8.maxmss)
14563b3a8eb9SGleb Smirnoff 				r.max_mss = $8.maxmss;
145739282ef3SKajetan Staszkiewicz 			if ($8.marker & FOM_SETTOS) {
14583b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_SET_TOS;
14593b3a8eb9SGleb Smirnoff 				r.set_tos = $8.settos;
14603b3a8eb9SGleb Smirnoff 			}
14613b3a8eb9SGleb Smirnoff 			if ($8.fragcache)
14623b3a8eb9SGleb Smirnoff 				r.rule_flag |= $8.fragcache;
14633b3a8eb9SGleb Smirnoff 			if ($8.match_tag)
14643b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $8.match_tag,
14653b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
14663b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
14673b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
14683b3a8eb9SGleb Smirnoff 					YYERROR;
14693b3a8eb9SGleb Smirnoff 				}
14703b3a8eb9SGleb Smirnoff 			r.match_tag_not = $8.match_tag_not;
14713b3a8eb9SGleb Smirnoff 			r.rtableid = $8.rtableid;
14723b3a8eb9SGleb Smirnoff 
14730972294eSKristof Provost 			expand_rule(&r, $4, NULL, NULL, NULL, NULL, NULL, NULL,
14740972294eSKristof Provost 			    $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host,
14750972294eSKristof Provost 			    $7.dst.port, NULL, NULL, NULL, NULL, "");
14763b3a8eb9SGleb Smirnoff 		}
14773b3a8eb9SGleb Smirnoff 		;
14783b3a8eb9SGleb Smirnoff 
14793b3a8eb9SGleb Smirnoff scrub_opts	:	{
14803b3a8eb9SGleb Smirnoff 				bzero(&scrub_opts, sizeof scrub_opts);
14813b3a8eb9SGleb Smirnoff 				scrub_opts.rtableid = -1;
14823b3a8eb9SGleb Smirnoff 			}
14833b3a8eb9SGleb Smirnoff 		    scrub_opts_l
14843b3a8eb9SGleb Smirnoff 			{ $$ = scrub_opts; }
14853b3a8eb9SGleb Smirnoff 		| /* empty */ {
14863b3a8eb9SGleb Smirnoff 			bzero(&scrub_opts, sizeof scrub_opts);
14873b3a8eb9SGleb Smirnoff 			scrub_opts.rtableid = -1;
14883b3a8eb9SGleb Smirnoff 			$$ = scrub_opts;
14893b3a8eb9SGleb Smirnoff 		}
14903b3a8eb9SGleb Smirnoff 		;
14913b3a8eb9SGleb Smirnoff 
149239282ef3SKajetan Staszkiewicz scrub_opts_l	: scrub_opts_l comma scrub_opt
14933b3a8eb9SGleb Smirnoff 		| scrub_opt
14943b3a8eb9SGleb Smirnoff 		;
14953b3a8eb9SGleb Smirnoff 
14963b3a8eb9SGleb Smirnoff scrub_opt	: NODF	{
14973b3a8eb9SGleb Smirnoff 			if (scrub_opts.nodf) {
14983b3a8eb9SGleb Smirnoff 				yyerror("no-df cannot be respecified");
14993b3a8eb9SGleb Smirnoff 				YYERROR;
15003b3a8eb9SGleb Smirnoff 			}
15013b3a8eb9SGleb Smirnoff 			scrub_opts.nodf = 1;
15023b3a8eb9SGleb Smirnoff 		}
15033b3a8eb9SGleb Smirnoff 		| MINTTL NUMBER {
150439282ef3SKajetan Staszkiewicz 			if (scrub_opts.marker & FOM_MINTTL) {
15053b3a8eb9SGleb Smirnoff 				yyerror("min-ttl cannot be respecified");
15063b3a8eb9SGleb Smirnoff 				YYERROR;
15073b3a8eb9SGleb Smirnoff 			}
15083b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 255) {
15093b3a8eb9SGleb Smirnoff 				yyerror("illegal min-ttl value %d", $2);
15103b3a8eb9SGleb Smirnoff 				YYERROR;
15113b3a8eb9SGleb Smirnoff 			}
151239282ef3SKajetan Staszkiewicz 			scrub_opts.marker |= FOM_MINTTL;
15133b3a8eb9SGleb Smirnoff 			scrub_opts.minttl = $2;
15143b3a8eb9SGleb Smirnoff 		}
15153b3a8eb9SGleb Smirnoff 		| MAXMSS NUMBER {
151639282ef3SKajetan Staszkiewicz 			if (scrub_opts.marker & FOM_MAXMSS) {
15173b3a8eb9SGleb Smirnoff 				yyerror("max-mss cannot be respecified");
15183b3a8eb9SGleb Smirnoff 				YYERROR;
15193b3a8eb9SGleb Smirnoff 			}
15203b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 65535) {
15213b3a8eb9SGleb Smirnoff 				yyerror("illegal max-mss value %d", $2);
15223b3a8eb9SGleb Smirnoff 				YYERROR;
15233b3a8eb9SGleb Smirnoff 			}
152439282ef3SKajetan Staszkiewicz 			scrub_opts.marker |= FOM_MAXMSS;
15253b3a8eb9SGleb Smirnoff 			scrub_opts.maxmss = $2;
15263b3a8eb9SGleb Smirnoff 		}
15273b3a8eb9SGleb Smirnoff 		| SETTOS tos {
152839282ef3SKajetan Staszkiewicz 			if (scrub_opts.marker & FOM_SETTOS) {
15293b3a8eb9SGleb Smirnoff 				yyerror("set-tos cannot be respecified");
15303b3a8eb9SGleb Smirnoff 				YYERROR;
15313b3a8eb9SGleb Smirnoff 			}
153239282ef3SKajetan Staszkiewicz 			scrub_opts.marker |= FOM_SETTOS;
15333b3a8eb9SGleb Smirnoff 			scrub_opts.settos = $2;
15343b3a8eb9SGleb Smirnoff 		}
15353b3a8eb9SGleb Smirnoff 		| fragcache {
153639282ef3SKajetan Staszkiewicz 			if (scrub_opts.marker & FOM_FRAGCACHE) {
15373b3a8eb9SGleb Smirnoff 				yyerror("fragcache cannot be respecified");
15383b3a8eb9SGleb Smirnoff 				YYERROR;
15393b3a8eb9SGleb Smirnoff 			}
154039282ef3SKajetan Staszkiewicz 			scrub_opts.marker |= FOM_FRAGCACHE;
15413b3a8eb9SGleb Smirnoff 			scrub_opts.fragcache = $1;
15423b3a8eb9SGleb Smirnoff 		}
15433b3a8eb9SGleb Smirnoff 		| REASSEMBLE STRING {
15443b3a8eb9SGleb Smirnoff 			if (strcasecmp($2, "tcp") != 0) {
15453b3a8eb9SGleb Smirnoff 				yyerror("scrub reassemble supports only tcp, "
15463b3a8eb9SGleb Smirnoff 				    "not '%s'", $2);
15473b3a8eb9SGleb Smirnoff 				free($2);
15483b3a8eb9SGleb Smirnoff 				YYERROR;
15493b3a8eb9SGleb Smirnoff 			}
15503b3a8eb9SGleb Smirnoff 			free($2);
15513b3a8eb9SGleb Smirnoff 			if (scrub_opts.reassemble_tcp) {
15523b3a8eb9SGleb Smirnoff 				yyerror("reassemble tcp cannot be respecified");
15533b3a8eb9SGleb Smirnoff 				YYERROR;
15543b3a8eb9SGleb Smirnoff 			}
15553b3a8eb9SGleb Smirnoff 			scrub_opts.reassemble_tcp = 1;
15563b3a8eb9SGleb Smirnoff 		}
15573b3a8eb9SGleb Smirnoff 		| RANDOMID {
15583b3a8eb9SGleb Smirnoff 			if (scrub_opts.randomid) {
15593b3a8eb9SGleb Smirnoff 				yyerror("random-id cannot be respecified");
15603b3a8eb9SGleb Smirnoff 				YYERROR;
15613b3a8eb9SGleb Smirnoff 			}
15623b3a8eb9SGleb Smirnoff 			scrub_opts.randomid = 1;
15633b3a8eb9SGleb Smirnoff 		}
15643b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER				{
15653b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
15663b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
15673b3a8eb9SGleb Smirnoff 				YYERROR;
15683b3a8eb9SGleb Smirnoff 			}
15693b3a8eb9SGleb Smirnoff 			scrub_opts.rtableid = $2;
15703b3a8eb9SGleb Smirnoff 		}
15713b3a8eb9SGleb Smirnoff 		| not TAGGED string			{
15723b3a8eb9SGleb Smirnoff 			scrub_opts.match_tag = $3;
15733b3a8eb9SGleb Smirnoff 			scrub_opts.match_tag_not = $1;
15743b3a8eb9SGleb Smirnoff 		}
15753b3a8eb9SGleb Smirnoff 		;
15763b3a8eb9SGleb Smirnoff 
15773b3a8eb9SGleb Smirnoff fragcache	: FRAGMENT REASSEMBLE		{ $$ = 0; /* default */ }
157857e047e5SKristof Provost 		| FRAGMENT NO REASSEMBLE	{ $$ = PFRULE_FRAGMENT_NOREASS; }
15793b3a8eb9SGleb Smirnoff 		;
15803b3a8eb9SGleb Smirnoff 
15813b3a8eb9SGleb Smirnoff antispoof	: ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
1582e9eb0941SKristof Provost 			struct pfctl_rule	 r;
15833b3a8eb9SGleb Smirnoff 			struct node_host	*h = NULL, *hh;
15843b3a8eb9SGleb Smirnoff 			struct node_if		*i, *j;
15853b3a8eb9SGleb Smirnoff 
15863b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_FILTER))
15873b3a8eb9SGleb Smirnoff 				YYERROR;
15883b3a8eb9SGleb Smirnoff 
15893b3a8eb9SGleb Smirnoff 			for (i = $3; i; i = i->next) {
15903b3a8eb9SGleb Smirnoff 				bzero(&r, sizeof(r));
15913b3a8eb9SGleb Smirnoff 
15923b3a8eb9SGleb Smirnoff 				r.action = PF_DROP;
15933b3a8eb9SGleb Smirnoff 				r.direction = PF_IN;
15943b3a8eb9SGleb Smirnoff 				r.log = $2.log;
15953b3a8eb9SGleb Smirnoff 				r.logif = $2.logif;
15963b3a8eb9SGleb Smirnoff 				r.quick = $2.quick;
15973b3a8eb9SGleb Smirnoff 				r.af = $4;
159876c5eeccSKristof Provost 				r.ridentifier = $5.ridentifier;
15993b3a8eb9SGleb Smirnoff 				if (rule_label(&r, $5.label))
16003b3a8eb9SGleb Smirnoff 					YYERROR;
16013b3a8eb9SGleb Smirnoff 				r.rtableid = $5.rtableid;
16023b3a8eb9SGleb Smirnoff 				j = calloc(1, sizeof(struct node_if));
16033b3a8eb9SGleb Smirnoff 				if (j == NULL)
16043b3a8eb9SGleb Smirnoff 					err(1, "antispoof: calloc");
16053b3a8eb9SGleb Smirnoff 				if (strlcpy(j->ifname, i->ifname,
16063b3a8eb9SGleb Smirnoff 				    sizeof(j->ifname)) >= sizeof(j->ifname)) {
16073b3a8eb9SGleb Smirnoff 					free(j);
16083b3a8eb9SGleb Smirnoff 					yyerror("interface name too long");
16093b3a8eb9SGleb Smirnoff 					YYERROR;
16103b3a8eb9SGleb Smirnoff 				}
16113b3a8eb9SGleb Smirnoff 				j->not = 1;
16123b3a8eb9SGleb Smirnoff 				if (i->dynamic) {
16133b3a8eb9SGleb Smirnoff 					h = calloc(1, sizeof(*h));
16143b3a8eb9SGleb Smirnoff 					if (h == NULL)
16153b3a8eb9SGleb Smirnoff 						err(1, "address: calloc");
16163b3a8eb9SGleb Smirnoff 					h->addr.type = PF_ADDR_DYNIFTL;
16173b3a8eb9SGleb Smirnoff 					set_ipmask(h, 128);
16183b3a8eb9SGleb Smirnoff 					if (strlcpy(h->addr.v.ifname, i->ifname,
16193b3a8eb9SGleb Smirnoff 					    sizeof(h->addr.v.ifname)) >=
16203b3a8eb9SGleb Smirnoff 					    sizeof(h->addr.v.ifname)) {
16213b3a8eb9SGleb Smirnoff 						free(h);
16223b3a8eb9SGleb Smirnoff 						yyerror(
16233b3a8eb9SGleb Smirnoff 						    "interface name too long");
16243b3a8eb9SGleb Smirnoff 						YYERROR;
16253b3a8eb9SGleb Smirnoff 					}
16263b3a8eb9SGleb Smirnoff 					hh = malloc(sizeof(*hh));
16273b3a8eb9SGleb Smirnoff 					if (hh == NULL)
16283b3a8eb9SGleb Smirnoff 						 err(1, "address: malloc");
16293b3a8eb9SGleb Smirnoff 					bcopy(h, hh, sizeof(*hh));
16303b3a8eb9SGleb Smirnoff 					h->addr.iflags = PFI_AFLAG_NETWORK;
16313b3a8eb9SGleb Smirnoff 				} else {
16323b3a8eb9SGleb Smirnoff 					h = ifa_lookup(j->ifname,
16333b3a8eb9SGleb Smirnoff 					    PFI_AFLAG_NETWORK);
16343b3a8eb9SGleb Smirnoff 					hh = NULL;
16353b3a8eb9SGleb Smirnoff 				}
16363b3a8eb9SGleb Smirnoff 
16373b3a8eb9SGleb Smirnoff 				if (h != NULL)
16380972294eSKristof Provost 					expand_rule(&r, j, NULL, NULL, NULL, NULL, NULL, NULL,
16390972294eSKristof Provost 					    NULL, NULL, h, NULL, NULL, NULL, NULL, NULL,
16402339ead6SKristof Provost 					    NULL, NULL, "");
16413b3a8eb9SGleb Smirnoff 
16423b3a8eb9SGleb Smirnoff 				if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
16433b3a8eb9SGleb Smirnoff 					bzero(&r, sizeof(r));
16443b3a8eb9SGleb Smirnoff 
16453b3a8eb9SGleb Smirnoff 					r.action = PF_DROP;
16463b3a8eb9SGleb Smirnoff 					r.direction = PF_IN;
16473b3a8eb9SGleb Smirnoff 					r.log = $2.log;
16483b3a8eb9SGleb Smirnoff 					r.logif = $2.logif;
16493b3a8eb9SGleb Smirnoff 					r.quick = $2.quick;
16503b3a8eb9SGleb Smirnoff 					r.af = $4;
165176c5eeccSKristof Provost 					r.ridentifier = $5.ridentifier;
16523b3a8eb9SGleb Smirnoff 					if (rule_label(&r, $5.label))
16533b3a8eb9SGleb Smirnoff 						YYERROR;
16543b3a8eb9SGleb Smirnoff 					r.rtableid = $5.rtableid;
16553b3a8eb9SGleb Smirnoff 					if (hh != NULL)
16563b3a8eb9SGleb Smirnoff 						h = hh;
16573b3a8eb9SGleb Smirnoff 					else
16583b3a8eb9SGleb Smirnoff 						h = ifa_lookup(i->ifname, 0);
16593b3a8eb9SGleb Smirnoff 					if (h != NULL)
1660f88019e8SKristof Provost 						expand_rule(&r, NULL, NULL, NULL, NULL, NULL,
16610972294eSKristof Provost 						    NULL, NULL, NULL, NULL, h, NULL, NULL,
16622339ead6SKristof Provost 						    NULL, NULL, NULL, NULL, NULL, "");
16633b3a8eb9SGleb Smirnoff 				} else
16643b3a8eb9SGleb Smirnoff 					free(hh);
16653b3a8eb9SGleb Smirnoff 			}
16666fcc8e04SKristof Provost 			for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
16676fcc8e04SKristof Provost 				free($5.label[i]);
16683b3a8eb9SGleb Smirnoff 		}
16693b3a8eb9SGleb Smirnoff 		;
16703b3a8eb9SGleb Smirnoff 
16713b3a8eb9SGleb Smirnoff antispoof_ifspc	: FOR antispoof_if			{ $$ = $2; }
16723b3a8eb9SGleb Smirnoff 		| FOR '{' optnl antispoof_iflst '}'	{ $$ = $4; }
16733b3a8eb9SGleb Smirnoff 		;
16743b3a8eb9SGleb Smirnoff 
16753b3a8eb9SGleb Smirnoff antispoof_iflst	: antispoof_if optnl			{ $$ = $1; }
16763b3a8eb9SGleb Smirnoff 		| antispoof_iflst comma antispoof_if optnl {
16773b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
16783b3a8eb9SGleb Smirnoff 			$1->tail = $3;
16793b3a8eb9SGleb Smirnoff 			$$ = $1;
16803b3a8eb9SGleb Smirnoff 		}
16813b3a8eb9SGleb Smirnoff 		;
16823b3a8eb9SGleb Smirnoff 
16833b3a8eb9SGleb Smirnoff antispoof_if	: if_item				{ $$ = $1; }
16843b3a8eb9SGleb Smirnoff 		| '(' if_item ')'			{
16853b3a8eb9SGleb Smirnoff 			$2->dynamic = 1;
16863b3a8eb9SGleb Smirnoff 			$$ = $2;
16873b3a8eb9SGleb Smirnoff 		}
16883b3a8eb9SGleb Smirnoff 		;
16893b3a8eb9SGleb Smirnoff 
16903b3a8eb9SGleb Smirnoff antispoof_opts	:	{
16913b3a8eb9SGleb Smirnoff 				bzero(&antispoof_opts, sizeof antispoof_opts);
16923b3a8eb9SGleb Smirnoff 				antispoof_opts.rtableid = -1;
16933b3a8eb9SGleb Smirnoff 			}
16943b3a8eb9SGleb Smirnoff 		    antispoof_opts_l
16953b3a8eb9SGleb Smirnoff 			{ $$ = antispoof_opts; }
16963b3a8eb9SGleb Smirnoff 		| /* empty */	{
16973b3a8eb9SGleb Smirnoff 			bzero(&antispoof_opts, sizeof antispoof_opts);
16983b3a8eb9SGleb Smirnoff 			antispoof_opts.rtableid = -1;
16993b3a8eb9SGleb Smirnoff 			$$ = antispoof_opts;
17003b3a8eb9SGleb Smirnoff 		}
17013b3a8eb9SGleb Smirnoff 		;
17023b3a8eb9SGleb Smirnoff 
17033b3a8eb9SGleb Smirnoff antispoof_opts_l	: antispoof_opts_l antispoof_opt
17043b3a8eb9SGleb Smirnoff 			| antispoof_opt
17053b3a8eb9SGleb Smirnoff 			;
17063b3a8eb9SGleb Smirnoff 
17073b3a8eb9SGleb Smirnoff antispoof_opt	: label	{
17086fcc8e04SKristof Provost 			if (antispoof_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) {
17096fcc8e04SKristof Provost 				yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT);
17103b3a8eb9SGleb Smirnoff 				YYERROR;
17113b3a8eb9SGleb Smirnoff 			}
17126fcc8e04SKristof Provost 			antispoof_opts.label[antispoof_opts.labelcount++] = $1;
17133b3a8eb9SGleb Smirnoff 		}
171476c5eeccSKristof Provost 		| RIDENTIFIER number {
171576c5eeccSKristof Provost 			antispoof_opts.ridentifier = $2;
171676c5eeccSKristof Provost 		}
17173b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER				{
17183b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
17193b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
17203b3a8eb9SGleb Smirnoff 				YYERROR;
17213b3a8eb9SGleb Smirnoff 			}
17223b3a8eb9SGleb Smirnoff 			antispoof_opts.rtableid = $2;
17233b3a8eb9SGleb Smirnoff 		}
17243b3a8eb9SGleb Smirnoff 		;
17253b3a8eb9SGleb Smirnoff 
17263b3a8eb9SGleb Smirnoff not		: '!'		{ $$ = 1; }
17273b3a8eb9SGleb Smirnoff 		| /* empty */	{ $$ = 0; }
17283b3a8eb9SGleb Smirnoff 		;
17293b3a8eb9SGleb Smirnoff 
17303b3a8eb9SGleb Smirnoff tabledef	: TABLE '<' STRING '>' table_opts {
17313b3a8eb9SGleb Smirnoff 			struct node_host	 *h, *nh;
17323b3a8eb9SGleb Smirnoff 			struct node_tinit	 *ti, *nti;
17333b3a8eb9SGleb Smirnoff 
17343b3a8eb9SGleb Smirnoff 			if (strlen($3) >= PF_TABLE_NAME_SIZE) {
17353b3a8eb9SGleb Smirnoff 				yyerror("table name too long, max %d chars",
17363b3a8eb9SGleb Smirnoff 				    PF_TABLE_NAME_SIZE - 1);
17373b3a8eb9SGleb Smirnoff 				free($3);
17383b3a8eb9SGleb Smirnoff 				YYERROR;
17393b3a8eb9SGleb Smirnoff 			}
17403b3a8eb9SGleb Smirnoff 			if (pf->loadopt & PFCTL_FLAG_TABLE)
17413b3a8eb9SGleb Smirnoff 				if (process_tabledef($3, &$5)) {
17423b3a8eb9SGleb Smirnoff 					free($3);
17433b3a8eb9SGleb Smirnoff 					YYERROR;
17443b3a8eb9SGleb Smirnoff 				}
17453b3a8eb9SGleb Smirnoff 			free($3);
17463b3a8eb9SGleb Smirnoff 			for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
17473b3a8eb9SGleb Smirnoff 			    ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
17483b3a8eb9SGleb Smirnoff 				if (ti->file)
17493b3a8eb9SGleb Smirnoff 					free(ti->file);
17503b3a8eb9SGleb Smirnoff 				for (h = ti->host; h != NULL; h = nh) {
17513b3a8eb9SGleb Smirnoff 					nh = h->next;
17523b3a8eb9SGleb Smirnoff 					free(h);
17533b3a8eb9SGleb Smirnoff 				}
17543b3a8eb9SGleb Smirnoff 				nti = SIMPLEQ_NEXT(ti, entries);
17553b3a8eb9SGleb Smirnoff 				free(ti);
17563b3a8eb9SGleb Smirnoff 			}
17573b3a8eb9SGleb Smirnoff 		}
17583b3a8eb9SGleb Smirnoff 		;
17593b3a8eb9SGleb Smirnoff 
17603b3a8eb9SGleb Smirnoff table_opts	:	{
17613b3a8eb9SGleb Smirnoff 			bzero(&table_opts, sizeof table_opts);
17623b3a8eb9SGleb Smirnoff 			SIMPLEQ_INIT(&table_opts.init_nodes);
17633b3a8eb9SGleb Smirnoff 		}
17643b3a8eb9SGleb Smirnoff 		    table_opts_l
17653b3a8eb9SGleb Smirnoff 			{ $$ = table_opts; }
17663b3a8eb9SGleb Smirnoff 		| /* empty */
17673b3a8eb9SGleb Smirnoff 			{
17683b3a8eb9SGleb Smirnoff 			bzero(&table_opts, sizeof table_opts);
17693b3a8eb9SGleb Smirnoff 			SIMPLEQ_INIT(&table_opts.init_nodes);
17703b3a8eb9SGleb Smirnoff 			$$ = table_opts;
17713b3a8eb9SGleb Smirnoff 		}
17723b3a8eb9SGleb Smirnoff 		;
17733b3a8eb9SGleb Smirnoff 
17743b3a8eb9SGleb Smirnoff table_opts_l	: table_opts_l table_opt
17753b3a8eb9SGleb Smirnoff 		| table_opt
17763b3a8eb9SGleb Smirnoff 		;
17773b3a8eb9SGleb Smirnoff 
17783b3a8eb9SGleb Smirnoff table_opt	: STRING		{
17793b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "const"))
17803b3a8eb9SGleb Smirnoff 				table_opts.flags |= PFR_TFLAG_CONST;
17813b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "persist"))
17823b3a8eb9SGleb Smirnoff 				table_opts.flags |= PFR_TFLAG_PERSIST;
17833b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "counters"))
17843b3a8eb9SGleb Smirnoff 				table_opts.flags |= PFR_TFLAG_COUNTERS;
17853b3a8eb9SGleb Smirnoff 			else {
17863b3a8eb9SGleb Smirnoff 				yyerror("invalid table option '%s'", $1);
17873b3a8eb9SGleb Smirnoff 				free($1);
17883b3a8eb9SGleb Smirnoff 				YYERROR;
17893b3a8eb9SGleb Smirnoff 			}
17903b3a8eb9SGleb Smirnoff 			free($1);
17913b3a8eb9SGleb Smirnoff 		}
17923b3a8eb9SGleb Smirnoff 		| '{' optnl '}'		{ table_opts.init_addr = 1; }
17933b3a8eb9SGleb Smirnoff 		| '{' optnl host_list '}'	{
17943b3a8eb9SGleb Smirnoff 			struct node_host	*n;
17953b3a8eb9SGleb Smirnoff 			struct node_tinit	*ti;
17963b3a8eb9SGleb Smirnoff 
17973b3a8eb9SGleb Smirnoff 			for (n = $3; n != NULL; n = n->next) {
17983b3a8eb9SGleb Smirnoff 				switch (n->addr.type) {
17993b3a8eb9SGleb Smirnoff 				case PF_ADDR_ADDRMASK:
18003b3a8eb9SGleb Smirnoff 					continue; /* ok */
18013b3a8eb9SGleb Smirnoff 				case PF_ADDR_RANGE:
18023b3a8eb9SGleb Smirnoff 					yyerror("address ranges are not "
18033b3a8eb9SGleb Smirnoff 					    "permitted inside tables");
18043b3a8eb9SGleb Smirnoff 					break;
18053b3a8eb9SGleb Smirnoff 				case PF_ADDR_DYNIFTL:
18063b3a8eb9SGleb Smirnoff 					yyerror("dynamic addresses are not "
18073b3a8eb9SGleb Smirnoff 					    "permitted inside tables");
18083b3a8eb9SGleb Smirnoff 					break;
18093b3a8eb9SGleb Smirnoff 				case PF_ADDR_TABLE:
18103b3a8eb9SGleb Smirnoff 					yyerror("tables cannot contain tables");
18113b3a8eb9SGleb Smirnoff 					break;
18123b3a8eb9SGleb Smirnoff 				case PF_ADDR_NOROUTE:
18133b3a8eb9SGleb Smirnoff 					yyerror("\"no-route\" is not permitted "
18143b3a8eb9SGleb Smirnoff 					    "inside tables");
18153b3a8eb9SGleb Smirnoff 					break;
18163b3a8eb9SGleb Smirnoff 				case PF_ADDR_URPFFAILED:
18173b3a8eb9SGleb Smirnoff 					yyerror("\"urpf-failed\" is not "
18183b3a8eb9SGleb Smirnoff 					    "permitted inside tables");
18193b3a8eb9SGleb Smirnoff 					break;
18203b3a8eb9SGleb Smirnoff 				default:
18213b3a8eb9SGleb Smirnoff 					yyerror("unknown address type %d",
18223b3a8eb9SGleb Smirnoff 					    n->addr.type);
18233b3a8eb9SGleb Smirnoff 				}
18243b3a8eb9SGleb Smirnoff 				YYERROR;
18253b3a8eb9SGleb Smirnoff 			}
18263b3a8eb9SGleb Smirnoff 			if (!(ti = calloc(1, sizeof(*ti))))
18273b3a8eb9SGleb Smirnoff 				err(1, "table_opt: calloc");
18283b3a8eb9SGleb Smirnoff 			ti->host = $3;
18293b3a8eb9SGleb Smirnoff 			SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
18303b3a8eb9SGleb Smirnoff 			    entries);
18313b3a8eb9SGleb Smirnoff 			table_opts.init_addr = 1;
18323b3a8eb9SGleb Smirnoff 		}
18333b3a8eb9SGleb Smirnoff 		| FILENAME STRING	{
18343b3a8eb9SGleb Smirnoff 			struct node_tinit	*ti;
18353b3a8eb9SGleb Smirnoff 
18363b3a8eb9SGleb Smirnoff 			if (!(ti = calloc(1, sizeof(*ti))))
18373b3a8eb9SGleb Smirnoff 				err(1, "table_opt: calloc");
18383b3a8eb9SGleb Smirnoff 			ti->file = $2;
18393b3a8eb9SGleb Smirnoff 			SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
18403b3a8eb9SGleb Smirnoff 			    entries);
18413b3a8eb9SGleb Smirnoff 			table_opts.init_addr = 1;
18423b3a8eb9SGleb Smirnoff 		}
18433b3a8eb9SGleb Smirnoff 		;
18443b3a8eb9SGleb Smirnoff 
18453b3a8eb9SGleb Smirnoff altqif		: ALTQ interface queue_opts QUEUE qassign {
18463b3a8eb9SGleb Smirnoff 			struct pf_altq	a;
18473b3a8eb9SGleb Smirnoff 
18483b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_QUEUE))
18493b3a8eb9SGleb Smirnoff 				YYERROR;
18503b3a8eb9SGleb Smirnoff 
18513b3a8eb9SGleb Smirnoff 			memset(&a, 0, sizeof(a));
18523b3a8eb9SGleb Smirnoff 			if ($3.scheduler.qtype == ALTQT_NONE) {
18533b3a8eb9SGleb Smirnoff 				yyerror("no scheduler specified!");
18543b3a8eb9SGleb Smirnoff 				YYERROR;
18553b3a8eb9SGleb Smirnoff 			}
18563b3a8eb9SGleb Smirnoff 			a.scheduler = $3.scheduler.qtype;
18573b3a8eb9SGleb Smirnoff 			a.qlimit = $3.qlimit;
18583b3a8eb9SGleb Smirnoff 			a.tbrsize = $3.tbrsize;
18590a70aaf8SLuiz Otavio O Souza 			if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
18603b3a8eb9SGleb Smirnoff 				yyerror("no child queues specified");
18613b3a8eb9SGleb Smirnoff 				YYERROR;
18623b3a8eb9SGleb Smirnoff 			}
18633b3a8eb9SGleb Smirnoff 			if (expand_altq(&a, $2, $5, $3.queue_bwspec,
18643b3a8eb9SGleb Smirnoff 			    &$3.scheduler))
18653b3a8eb9SGleb Smirnoff 				YYERROR;
18663b3a8eb9SGleb Smirnoff 		}
18673b3a8eb9SGleb Smirnoff 		;
18683b3a8eb9SGleb Smirnoff 
18693b3a8eb9SGleb Smirnoff queuespec	: QUEUE STRING interface queue_opts qassign {
18703b3a8eb9SGleb Smirnoff 			struct pf_altq	a;
18713b3a8eb9SGleb Smirnoff 
18723b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_QUEUE)) {
18733b3a8eb9SGleb Smirnoff 				free($2);
18743b3a8eb9SGleb Smirnoff 				YYERROR;
18753b3a8eb9SGleb Smirnoff 			}
18763b3a8eb9SGleb Smirnoff 
18773b3a8eb9SGleb Smirnoff 			memset(&a, 0, sizeof(a));
18783b3a8eb9SGleb Smirnoff 
18793b3a8eb9SGleb Smirnoff 			if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
18803b3a8eb9SGleb Smirnoff 			    sizeof(a.qname)) {
18813b3a8eb9SGleb Smirnoff 				yyerror("queue name too long (max "
18823b3a8eb9SGleb Smirnoff 				    "%d chars)", PF_QNAME_SIZE-1);
18833b3a8eb9SGleb Smirnoff 				free($2);
18843b3a8eb9SGleb Smirnoff 				YYERROR;
18853b3a8eb9SGleb Smirnoff 			}
18863b3a8eb9SGleb Smirnoff 			free($2);
18873b3a8eb9SGleb Smirnoff 			if ($4.tbrsize) {
18883b3a8eb9SGleb Smirnoff 				yyerror("cannot specify tbrsize for queue");
18893b3a8eb9SGleb Smirnoff 				YYERROR;
18903b3a8eb9SGleb Smirnoff 			}
18913b3a8eb9SGleb Smirnoff 			if ($4.priority > 255) {
18923b3a8eb9SGleb Smirnoff 				yyerror("priority out of range: max 255");
18933b3a8eb9SGleb Smirnoff 				YYERROR;
18943b3a8eb9SGleb Smirnoff 			}
18953b3a8eb9SGleb Smirnoff 			a.priority = $4.priority;
18963b3a8eb9SGleb Smirnoff 			a.qlimit = $4.qlimit;
18973b3a8eb9SGleb Smirnoff 			a.scheduler = $4.scheduler.qtype;
18983b3a8eb9SGleb Smirnoff 			if (expand_queue(&a, $3, $5, $4.queue_bwspec,
18993b3a8eb9SGleb Smirnoff 			    &$4.scheduler)) {
19003b3a8eb9SGleb Smirnoff 				yyerror("errors in queue definition");
19013b3a8eb9SGleb Smirnoff 				YYERROR;
19023b3a8eb9SGleb Smirnoff 			}
19033b3a8eb9SGleb Smirnoff 		}
19043b3a8eb9SGleb Smirnoff 		;
19053b3a8eb9SGleb Smirnoff 
19063b3a8eb9SGleb Smirnoff queue_opts	:	{
19073b3a8eb9SGleb Smirnoff 			bzero(&queue_opts, sizeof queue_opts);
19083b3a8eb9SGleb Smirnoff 			queue_opts.priority = DEFAULT_PRIORITY;
19093b3a8eb9SGleb Smirnoff 			queue_opts.qlimit = DEFAULT_QLIMIT;
19103b3a8eb9SGleb Smirnoff 			queue_opts.scheduler.qtype = ALTQT_NONE;
19113b3a8eb9SGleb Smirnoff 			queue_opts.queue_bwspec.bw_percent = 100;
19123b3a8eb9SGleb Smirnoff 		}
19133b3a8eb9SGleb Smirnoff 		    queue_opts_l
19143b3a8eb9SGleb Smirnoff 			{ $$ = queue_opts; }
19153b3a8eb9SGleb Smirnoff 		| /* empty */ {
19163b3a8eb9SGleb Smirnoff 			bzero(&queue_opts, sizeof queue_opts);
19173b3a8eb9SGleb Smirnoff 			queue_opts.priority = DEFAULT_PRIORITY;
19183b3a8eb9SGleb Smirnoff 			queue_opts.qlimit = DEFAULT_QLIMIT;
19193b3a8eb9SGleb Smirnoff 			queue_opts.scheduler.qtype = ALTQT_NONE;
19203b3a8eb9SGleb Smirnoff 			queue_opts.queue_bwspec.bw_percent = 100;
19213b3a8eb9SGleb Smirnoff 			$$ = queue_opts;
19223b3a8eb9SGleb Smirnoff 		}
19233b3a8eb9SGleb Smirnoff 		;
19243b3a8eb9SGleb Smirnoff 
19253b3a8eb9SGleb Smirnoff queue_opts_l	: queue_opts_l queue_opt
19263b3a8eb9SGleb Smirnoff 		| queue_opt
19273b3a8eb9SGleb Smirnoff 		;
19283b3a8eb9SGleb Smirnoff 
19293b3a8eb9SGleb Smirnoff queue_opt	: BANDWIDTH bandwidth	{
19303b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_BWSPEC) {
19313b3a8eb9SGleb Smirnoff 				yyerror("bandwidth cannot be respecified");
19323b3a8eb9SGleb Smirnoff 				YYERROR;
19333b3a8eb9SGleb Smirnoff 			}
19343b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_BWSPEC;
19353b3a8eb9SGleb Smirnoff 			queue_opts.queue_bwspec = $2;
19363b3a8eb9SGleb Smirnoff 		}
19373b3a8eb9SGleb Smirnoff 		| PRIORITY NUMBER	{
19383b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_PRIORITY) {
19393b3a8eb9SGleb Smirnoff 				yyerror("priority cannot be respecified");
19403b3a8eb9SGleb Smirnoff 				YYERROR;
19413b3a8eb9SGleb Smirnoff 			}
19423b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 255) {
19433b3a8eb9SGleb Smirnoff 				yyerror("priority out of range: max 255");
19443b3a8eb9SGleb Smirnoff 				YYERROR;
19453b3a8eb9SGleb Smirnoff 			}
19463b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_PRIORITY;
19473b3a8eb9SGleb Smirnoff 			queue_opts.priority = $2;
19483b3a8eb9SGleb Smirnoff 		}
19493b3a8eb9SGleb Smirnoff 		| QLIMIT NUMBER	{
19503b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_QLIMIT) {
19513b3a8eb9SGleb Smirnoff 				yyerror("qlimit cannot be respecified");
19523b3a8eb9SGleb Smirnoff 				YYERROR;
19533b3a8eb9SGleb Smirnoff 			}
19543b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > 65535) {
19553b3a8eb9SGleb Smirnoff 				yyerror("qlimit out of range: max 65535");
19563b3a8eb9SGleb Smirnoff 				YYERROR;
19573b3a8eb9SGleb Smirnoff 			}
19583b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_QLIMIT;
19593b3a8eb9SGleb Smirnoff 			queue_opts.qlimit = $2;
19603b3a8eb9SGleb Smirnoff 		}
19613b3a8eb9SGleb Smirnoff 		| scheduler	{
19623b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_SCHEDULER) {
19633b3a8eb9SGleb Smirnoff 				yyerror("scheduler cannot be respecified");
19643b3a8eb9SGleb Smirnoff 				YYERROR;
19653b3a8eb9SGleb Smirnoff 			}
19663b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_SCHEDULER;
19673b3a8eb9SGleb Smirnoff 			queue_opts.scheduler = $1;
19683b3a8eb9SGleb Smirnoff 		}
19693b3a8eb9SGleb Smirnoff 		| TBRSIZE NUMBER	{
19703b3a8eb9SGleb Smirnoff 			if (queue_opts.marker & QOM_TBRSIZE) {
19713b3a8eb9SGleb Smirnoff 				yyerror("tbrsize cannot be respecified");
19723b3a8eb9SGleb Smirnoff 				YYERROR;
19733b3a8eb9SGleb Smirnoff 			}
1974249cc75fSPatrick Kelsey 			if ($2 < 0 || $2 > UINT_MAX) {
1975249cc75fSPatrick Kelsey 				yyerror("tbrsize too big: max %u", UINT_MAX);
19763b3a8eb9SGleb Smirnoff 				YYERROR;
19773b3a8eb9SGleb Smirnoff 			}
19783b3a8eb9SGleb Smirnoff 			queue_opts.marker |= QOM_TBRSIZE;
19793b3a8eb9SGleb Smirnoff 			queue_opts.tbrsize = $2;
19803b3a8eb9SGleb Smirnoff 		}
19813b3a8eb9SGleb Smirnoff 		;
19823b3a8eb9SGleb Smirnoff 
19833b3a8eb9SGleb Smirnoff bandwidth	: STRING {
19843b3a8eb9SGleb Smirnoff 			double	 bps;
19853b3a8eb9SGleb Smirnoff 			char	*cp;
19863b3a8eb9SGleb Smirnoff 
19873b3a8eb9SGleb Smirnoff 			$$.bw_percent = 0;
19883b3a8eb9SGleb Smirnoff 
19893b3a8eb9SGleb Smirnoff 			bps = strtod($1, &cp);
19903b3a8eb9SGleb Smirnoff 			if (cp != NULL) {
1991db1bbde6SLuiz Otavio O Souza 				if (strlen(cp) > 1) {
1992db1bbde6SLuiz Otavio O Souza 					char *cu = cp + 1;
1993db1bbde6SLuiz Otavio O Souza 					if (!strcmp(cu, "Bit") ||
1994db1bbde6SLuiz Otavio O Souza 					    !strcmp(cu, "B") ||
1995db1bbde6SLuiz Otavio O Souza 					    !strcmp(cu, "bit") ||
1996db1bbde6SLuiz Otavio O Souza 					    !strcmp(cu, "b")) {
1997db1bbde6SLuiz Otavio O Souza 						*cu = 0;
1998db1bbde6SLuiz Otavio O Souza 					}
1999db1bbde6SLuiz Otavio O Souza 				}
20003b3a8eb9SGleb Smirnoff 				if (!strcmp(cp, "b"))
20013b3a8eb9SGleb Smirnoff 					; /* nothing */
2002db1bbde6SLuiz Otavio O Souza 				else if (!strcmp(cp, "K"))
20033b3a8eb9SGleb Smirnoff 					bps *= 1000;
2004db1bbde6SLuiz Otavio O Souza 				else if (!strcmp(cp, "M"))
20053b3a8eb9SGleb Smirnoff 					bps *= 1000 * 1000;
2006db1bbde6SLuiz Otavio O Souza 				else if (!strcmp(cp, "G"))
20073b3a8eb9SGleb Smirnoff 					bps *= 1000 * 1000 * 1000;
20083b3a8eb9SGleb Smirnoff 				else if (!strcmp(cp, "%")) {
20093b3a8eb9SGleb Smirnoff 					if (bps < 0 || bps > 100) {
20103b3a8eb9SGleb Smirnoff 						yyerror("bandwidth spec "
20113b3a8eb9SGleb Smirnoff 						    "out of range");
20123b3a8eb9SGleb Smirnoff 						free($1);
20133b3a8eb9SGleb Smirnoff 						YYERROR;
20143b3a8eb9SGleb Smirnoff 					}
20153b3a8eb9SGleb Smirnoff 					$$.bw_percent = bps;
20163b3a8eb9SGleb Smirnoff 					bps = 0;
20173b3a8eb9SGleb Smirnoff 				} else {
20183b3a8eb9SGleb Smirnoff 					yyerror("unknown unit %s", cp);
20193b3a8eb9SGleb Smirnoff 					free($1);
20203b3a8eb9SGleb Smirnoff 					YYERROR;
20213b3a8eb9SGleb Smirnoff 				}
20223b3a8eb9SGleb Smirnoff 			}
20233b3a8eb9SGleb Smirnoff 			free($1);
2024249cc75fSPatrick Kelsey 			$$.bw_absolute = (u_int64_t)bps;
20253b3a8eb9SGleb Smirnoff 		}
20263b3a8eb9SGleb Smirnoff 		| NUMBER {
2027249cc75fSPatrick Kelsey 			if ($1 < 0 || $1 >= LLONG_MAX) {
20283b3a8eb9SGleb Smirnoff 				yyerror("bandwidth number too big");
20293b3a8eb9SGleb Smirnoff 				YYERROR;
20303b3a8eb9SGleb Smirnoff 			}
20313b3a8eb9SGleb Smirnoff 			$$.bw_percent = 0;
20323b3a8eb9SGleb Smirnoff 			$$.bw_absolute = $1;
20333b3a8eb9SGleb Smirnoff 		}
20343b3a8eb9SGleb Smirnoff 		;
20353b3a8eb9SGleb Smirnoff 
20363b3a8eb9SGleb Smirnoff scheduler	: CBQ				{
20373b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_CBQ;
20383b3a8eb9SGleb Smirnoff 			$$.data.cbq_opts.flags = 0;
20393b3a8eb9SGleb Smirnoff 		}
20403b3a8eb9SGleb Smirnoff 		| CBQ '(' cbqflags_list ')'	{
20413b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_CBQ;
20423b3a8eb9SGleb Smirnoff 			$$.data.cbq_opts.flags = $3;
20433b3a8eb9SGleb Smirnoff 		}
20443b3a8eb9SGleb Smirnoff 		| PRIQ				{
20453b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_PRIQ;
20463b3a8eb9SGleb Smirnoff 			$$.data.priq_opts.flags = 0;
20473b3a8eb9SGleb Smirnoff 		}
20483b3a8eb9SGleb Smirnoff 		| PRIQ '(' priqflags_list ')'	{
20493b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_PRIQ;
20503b3a8eb9SGleb Smirnoff 			$$.data.priq_opts.flags = $3;
20513b3a8eb9SGleb Smirnoff 		}
20523b3a8eb9SGleb Smirnoff 		| HFSC				{
20533b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_HFSC;
20543b3a8eb9SGleb Smirnoff 			bzero(&$$.data.hfsc_opts,
20553b3a8eb9SGleb Smirnoff 			    sizeof(struct node_hfsc_opts));
20563b3a8eb9SGleb Smirnoff 		}
20573b3a8eb9SGleb Smirnoff 		| HFSC '(' hfsc_opts ')'	{
20583b3a8eb9SGleb Smirnoff 			$$.qtype = ALTQT_HFSC;
20593b3a8eb9SGleb Smirnoff 			$$.data.hfsc_opts = $3;
20603b3a8eb9SGleb Smirnoff 		}
2061a5b789f6SErmal Luçi 		| FAIRQ				{
2062a5b789f6SErmal Luçi 			$$.qtype = ALTQT_FAIRQ;
2063a5b789f6SErmal Luçi 			bzero(&$$.data.fairq_opts,
2064a5b789f6SErmal Luçi 				sizeof(struct node_fairq_opts));
2065a5b789f6SErmal Luçi 		}
2066a5b789f6SErmal Luçi 		| FAIRQ '(' fairq_opts ')'      {
2067a5b789f6SErmal Luçi 			$$.qtype = ALTQT_FAIRQ;
2068a5b789f6SErmal Luçi 			$$.data.fairq_opts = $3;
2069a5b789f6SErmal Luçi 		}
20700a70aaf8SLuiz Otavio O Souza 		| CODEL				{
20710a70aaf8SLuiz Otavio O Souza 			$$.qtype = ALTQT_CODEL;
20720a70aaf8SLuiz Otavio O Souza 			bzero(&$$.data.codel_opts,
20730a70aaf8SLuiz Otavio O Souza 				sizeof(struct codel_opts));
20740a70aaf8SLuiz Otavio O Souza 		}
20750a70aaf8SLuiz Otavio O Souza 		| CODEL '(' codel_opts ')'	{
20760a70aaf8SLuiz Otavio O Souza 			$$.qtype = ALTQT_CODEL;
20770a70aaf8SLuiz Otavio O Souza 			$$.data.codel_opts = $3;
20780a70aaf8SLuiz Otavio O Souza 		}
20793b3a8eb9SGleb Smirnoff 		;
20803b3a8eb9SGleb Smirnoff 
20813b3a8eb9SGleb Smirnoff cbqflags_list	: cbqflags_item				{ $$ |= $1; }
20823b3a8eb9SGleb Smirnoff 		| cbqflags_list comma cbqflags_item	{ $$ |= $3; }
20833b3a8eb9SGleb Smirnoff 		;
20843b3a8eb9SGleb Smirnoff 
20853b3a8eb9SGleb Smirnoff cbqflags_item	: STRING	{
20863b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "default"))
20873b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_DEFCLASS;
20883b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "borrow"))
20893b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_BORROW;
20903b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "red"))
20913b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_RED;
20923b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "ecn"))
20933b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_RED|CBQCLF_ECN;
20943b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "rio"))
20953b3a8eb9SGleb Smirnoff 				$$ = CBQCLF_RIO;
20960a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
20970a70aaf8SLuiz Otavio O Souza 				$$ = CBQCLF_CODEL;
20983b3a8eb9SGleb Smirnoff 			else {
20993b3a8eb9SGleb Smirnoff 				yyerror("unknown cbq flag \"%s\"", $1);
21003b3a8eb9SGleb Smirnoff 				free($1);
21013b3a8eb9SGleb Smirnoff 				YYERROR;
21023b3a8eb9SGleb Smirnoff 			}
21033b3a8eb9SGleb Smirnoff 			free($1);
21043b3a8eb9SGleb Smirnoff 		}
21053b3a8eb9SGleb Smirnoff 		;
21063b3a8eb9SGleb Smirnoff 
21073b3a8eb9SGleb Smirnoff priqflags_list	: priqflags_item			{ $$ |= $1; }
21083b3a8eb9SGleb Smirnoff 		| priqflags_list comma priqflags_item	{ $$ |= $3; }
21093b3a8eb9SGleb Smirnoff 		;
21103b3a8eb9SGleb Smirnoff 
21113b3a8eb9SGleb Smirnoff priqflags_item	: STRING	{
21123b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "default"))
21133b3a8eb9SGleb Smirnoff 				$$ = PRCF_DEFAULTCLASS;
21143b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "red"))
21153b3a8eb9SGleb Smirnoff 				$$ = PRCF_RED;
21163b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "ecn"))
21173b3a8eb9SGleb Smirnoff 				$$ = PRCF_RED|PRCF_ECN;
21183b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "rio"))
21193b3a8eb9SGleb Smirnoff 				$$ = PRCF_RIO;
21200a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
21210a70aaf8SLuiz Otavio O Souza 				$$ = PRCF_CODEL;
21223b3a8eb9SGleb Smirnoff 			else {
21233b3a8eb9SGleb Smirnoff 				yyerror("unknown priq flag \"%s\"", $1);
21243b3a8eb9SGleb Smirnoff 				free($1);
21253b3a8eb9SGleb Smirnoff 				YYERROR;
21263b3a8eb9SGleb Smirnoff 			}
21273b3a8eb9SGleb Smirnoff 			free($1);
21283b3a8eb9SGleb Smirnoff 		}
21293b3a8eb9SGleb Smirnoff 		;
21303b3a8eb9SGleb Smirnoff 
21313b3a8eb9SGleb Smirnoff hfsc_opts	:	{
21323b3a8eb9SGleb Smirnoff 				bzero(&hfsc_opts,
21333b3a8eb9SGleb Smirnoff 				    sizeof(struct node_hfsc_opts));
21343b3a8eb9SGleb Smirnoff 			}
21353b3a8eb9SGleb Smirnoff 		    hfscopts_list				{
21363b3a8eb9SGleb Smirnoff 			$$ = hfsc_opts;
21373b3a8eb9SGleb Smirnoff 		}
21383b3a8eb9SGleb Smirnoff 		;
21393b3a8eb9SGleb Smirnoff 
21403b3a8eb9SGleb Smirnoff hfscopts_list	: hfscopts_item
21413b3a8eb9SGleb Smirnoff 		| hfscopts_list comma hfscopts_item
21423b3a8eb9SGleb Smirnoff 		;
21433b3a8eb9SGleb Smirnoff 
21443b3a8eb9SGleb Smirnoff hfscopts_item	: LINKSHARE bandwidth				{
21453b3a8eb9SGleb Smirnoff 			if (hfsc_opts.linkshare.used) {
21463b3a8eb9SGleb Smirnoff 				yyerror("linkshare already specified");
21473b3a8eb9SGleb Smirnoff 				YYERROR;
21483b3a8eb9SGleb Smirnoff 			}
21493b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.m2 = $2;
21503b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.used = 1;
21513b3a8eb9SGleb Smirnoff 		}
21523b3a8eb9SGleb Smirnoff 		| LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'
21533b3a8eb9SGleb Smirnoff 		    {
21543b3a8eb9SGleb Smirnoff 			if ($5 < 0 || $5 > INT_MAX) {
21553b3a8eb9SGleb Smirnoff 				yyerror("timing in curve out of range");
21563b3a8eb9SGleb Smirnoff 				YYERROR;
21573b3a8eb9SGleb Smirnoff 			}
21583b3a8eb9SGleb Smirnoff 			if (hfsc_opts.linkshare.used) {
21593b3a8eb9SGleb Smirnoff 				yyerror("linkshare already specified");
21603b3a8eb9SGleb Smirnoff 				YYERROR;
21613b3a8eb9SGleb Smirnoff 			}
21623b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.m1 = $3;
21633b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.d = $5;
21643b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.m2 = $7;
21653b3a8eb9SGleb Smirnoff 			hfsc_opts.linkshare.used = 1;
21663b3a8eb9SGleb Smirnoff 		}
21673b3a8eb9SGleb Smirnoff 		| REALTIME bandwidth				{
21683b3a8eb9SGleb Smirnoff 			if (hfsc_opts.realtime.used) {
21693b3a8eb9SGleb Smirnoff 				yyerror("realtime already specified");
21703b3a8eb9SGleb Smirnoff 				YYERROR;
21713b3a8eb9SGleb Smirnoff 			}
21723b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.m2 = $2;
21733b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.used = 1;
21743b3a8eb9SGleb Smirnoff 		}
21753b3a8eb9SGleb Smirnoff 		| REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'
21763b3a8eb9SGleb Smirnoff 		    {
21773b3a8eb9SGleb Smirnoff 			if ($5 < 0 || $5 > INT_MAX) {
21783b3a8eb9SGleb Smirnoff 				yyerror("timing in curve out of range");
21793b3a8eb9SGleb Smirnoff 				YYERROR;
21803b3a8eb9SGleb Smirnoff 			}
21813b3a8eb9SGleb Smirnoff 			if (hfsc_opts.realtime.used) {
21823b3a8eb9SGleb Smirnoff 				yyerror("realtime already specified");
21833b3a8eb9SGleb Smirnoff 				YYERROR;
21843b3a8eb9SGleb Smirnoff 			}
21853b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.m1 = $3;
21863b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.d = $5;
21873b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.m2 = $7;
21883b3a8eb9SGleb Smirnoff 			hfsc_opts.realtime.used = 1;
21893b3a8eb9SGleb Smirnoff 		}
21903b3a8eb9SGleb Smirnoff 		| UPPERLIMIT bandwidth				{
21913b3a8eb9SGleb Smirnoff 			if (hfsc_opts.upperlimit.used) {
21923b3a8eb9SGleb Smirnoff 				yyerror("upperlimit already specified");
21933b3a8eb9SGleb Smirnoff 				YYERROR;
21943b3a8eb9SGleb Smirnoff 			}
21953b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.m2 = $2;
21963b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.used = 1;
21973b3a8eb9SGleb Smirnoff 		}
21983b3a8eb9SGleb Smirnoff 		| UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'
21993b3a8eb9SGleb Smirnoff 		    {
22003b3a8eb9SGleb Smirnoff 			if ($5 < 0 || $5 > INT_MAX) {
22013b3a8eb9SGleb Smirnoff 				yyerror("timing in curve out of range");
22023b3a8eb9SGleb Smirnoff 				YYERROR;
22033b3a8eb9SGleb Smirnoff 			}
22043b3a8eb9SGleb Smirnoff 			if (hfsc_opts.upperlimit.used) {
22053b3a8eb9SGleb Smirnoff 				yyerror("upperlimit already specified");
22063b3a8eb9SGleb Smirnoff 				YYERROR;
22073b3a8eb9SGleb Smirnoff 			}
22083b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.m1 = $3;
22093b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.d = $5;
22103b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.m2 = $7;
22113b3a8eb9SGleb Smirnoff 			hfsc_opts.upperlimit.used = 1;
22123b3a8eb9SGleb Smirnoff 		}
22133b3a8eb9SGleb Smirnoff 		| STRING	{
22143b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "default"))
22153b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_DEFAULTCLASS;
22163b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "red"))
22173b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_RED;
22183b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "ecn"))
22193b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
22203b3a8eb9SGleb Smirnoff 			else if (!strcmp($1, "rio"))
22213b3a8eb9SGleb Smirnoff 				hfsc_opts.flags |= HFCF_RIO;
22220a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
22230a70aaf8SLuiz Otavio O Souza 				hfsc_opts.flags |= HFCF_CODEL;
22243b3a8eb9SGleb Smirnoff 			else {
22253b3a8eb9SGleb Smirnoff 				yyerror("unknown hfsc flag \"%s\"", $1);
22263b3a8eb9SGleb Smirnoff 				free($1);
22273b3a8eb9SGleb Smirnoff 				YYERROR;
22283b3a8eb9SGleb Smirnoff 			}
22293b3a8eb9SGleb Smirnoff 			free($1);
22303b3a8eb9SGleb Smirnoff 		}
22313b3a8eb9SGleb Smirnoff 		;
22323b3a8eb9SGleb Smirnoff 
2233a5b789f6SErmal Luçi fairq_opts	:	{
2234a5b789f6SErmal Luçi 				bzero(&fairq_opts,
2235a5b789f6SErmal Luçi 				    sizeof(struct node_fairq_opts));
2236a5b789f6SErmal Luçi 			}
2237a5b789f6SErmal Luçi 		    fairqopts_list				{
2238a5b789f6SErmal Luçi 			$$ = fairq_opts;
2239a5b789f6SErmal Luçi 		}
2240a5b789f6SErmal Luçi 		;
2241a5b789f6SErmal Luçi 
2242a5b789f6SErmal Luçi fairqopts_list	: fairqopts_item
2243a5b789f6SErmal Luçi 		| fairqopts_list comma fairqopts_item
2244a5b789f6SErmal Luçi 		;
2245a5b789f6SErmal Luçi 
2246a5b789f6SErmal Luçi fairqopts_item	: LINKSHARE bandwidth				{
2247a5b789f6SErmal Luçi 			if (fairq_opts.linkshare.used) {
2248a5b789f6SErmal Luçi 				yyerror("linkshare already specified");
2249a5b789f6SErmal Luçi 				YYERROR;
2250a5b789f6SErmal Luçi 			}
2251a5b789f6SErmal Luçi 			fairq_opts.linkshare.m2 = $2;
2252a5b789f6SErmal Luçi 			fairq_opts.linkshare.used = 1;
2253a5b789f6SErmal Luçi 		}
2254a5b789f6SErmal Luçi 		| LINKSHARE '(' bandwidth number bandwidth ')'	{
2255a5b789f6SErmal Luçi 			if (fairq_opts.linkshare.used) {
2256a5b789f6SErmal Luçi 				yyerror("linkshare already specified");
2257a5b789f6SErmal Luçi 				YYERROR;
2258a5b789f6SErmal Luçi 			}
2259a5b789f6SErmal Luçi 			fairq_opts.linkshare.m1 = $3;
2260a5b789f6SErmal Luçi 			fairq_opts.linkshare.d = $4;
2261a5b789f6SErmal Luçi 			fairq_opts.linkshare.m2 = $5;
2262a5b789f6SErmal Luçi 			fairq_opts.linkshare.used = 1;
2263a5b789f6SErmal Luçi 		}
2264a5b789f6SErmal Luçi 		| HOGS bandwidth {
2265a5b789f6SErmal Luçi 			fairq_opts.hogs_bw = $2;
2266a5b789f6SErmal Luçi 		}
2267a5b789f6SErmal Luçi 		| BUCKETS number {
2268a5b789f6SErmal Luçi 			fairq_opts.nbuckets = $2;
2269a5b789f6SErmal Luçi 		}
2270a5b789f6SErmal Luçi 		| STRING	{
2271a5b789f6SErmal Luçi 			if (!strcmp($1, "default"))
2272a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_DEFAULTCLASS;
2273a5b789f6SErmal Luçi 			else if (!strcmp($1, "red"))
2274a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_RED;
2275a5b789f6SErmal Luçi 			else if (!strcmp($1, "ecn"))
2276a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_RED|FARF_ECN;
2277a5b789f6SErmal Luçi 			else if (!strcmp($1, "rio"))
2278a5b789f6SErmal Luçi 				fairq_opts.flags |= FARF_RIO;
22790a70aaf8SLuiz Otavio O Souza 			else if (!strcmp($1, "codel"))
22800a70aaf8SLuiz Otavio O Souza 				fairq_opts.flags |= FARF_CODEL;
2281a5b789f6SErmal Luçi 			else {
2282a5b789f6SErmal Luçi 				yyerror("unknown fairq flag \"%s\"", $1);
2283a5b789f6SErmal Luçi 				free($1);
2284a5b789f6SErmal Luçi 				YYERROR;
2285a5b789f6SErmal Luçi 			}
2286a5b789f6SErmal Luçi 			free($1);
2287a5b789f6SErmal Luçi 		}
2288a5b789f6SErmal Luçi 		;
2289a5b789f6SErmal Luçi 
22900a70aaf8SLuiz Otavio O Souza codel_opts	:	{
22910a70aaf8SLuiz Otavio O Souza 				bzero(&codel_opts,
22920a70aaf8SLuiz Otavio O Souza 				    sizeof(struct codel_opts));
22930a70aaf8SLuiz Otavio O Souza 			}
22940a70aaf8SLuiz Otavio O Souza 		    codelopts_list				{
22950a70aaf8SLuiz Otavio O Souza 			$$ = codel_opts;
22960a70aaf8SLuiz Otavio O Souza 		}
22970a70aaf8SLuiz Otavio O Souza 		;
22980a70aaf8SLuiz Otavio O Souza 
22990a70aaf8SLuiz Otavio O Souza codelopts_list	: codelopts_item
23000a70aaf8SLuiz Otavio O Souza 		| codelopts_list comma codelopts_item
23010a70aaf8SLuiz Otavio O Souza 		;
23020a70aaf8SLuiz Otavio O Souza 
23030a70aaf8SLuiz Otavio O Souza codelopts_item	: INTERVAL number				{
23040a70aaf8SLuiz Otavio O Souza 			if (codel_opts.interval) {
23050a70aaf8SLuiz Otavio O Souza 				yyerror("interval already specified");
23060a70aaf8SLuiz Otavio O Souza 				YYERROR;
23070a70aaf8SLuiz Otavio O Souza 			}
23080a70aaf8SLuiz Otavio O Souza 			codel_opts.interval = $2;
23090a70aaf8SLuiz Otavio O Souza 		}
23100a70aaf8SLuiz Otavio O Souza 		| TARGET number					{
23110a70aaf8SLuiz Otavio O Souza 			if (codel_opts.target) {
23120a70aaf8SLuiz Otavio O Souza 				yyerror("target already specified");
23130a70aaf8SLuiz Otavio O Souza 				YYERROR;
23140a70aaf8SLuiz Otavio O Souza 			}
23150a70aaf8SLuiz Otavio O Souza 			codel_opts.target = $2;
23160a70aaf8SLuiz Otavio O Souza 		}
23170a70aaf8SLuiz Otavio O Souza 		| STRING					{
23180a70aaf8SLuiz Otavio O Souza 			if (!strcmp($1, "ecn"))
23190a70aaf8SLuiz Otavio O Souza 				codel_opts.ecn = 1;
23200a70aaf8SLuiz Otavio O Souza 			else {
23210a70aaf8SLuiz Otavio O Souza 				yyerror("unknown codel option \"%s\"", $1);
23220a70aaf8SLuiz Otavio O Souza 				free($1);
23230a70aaf8SLuiz Otavio O Souza 				YYERROR;
23240a70aaf8SLuiz Otavio O Souza 			}
23250a70aaf8SLuiz Otavio O Souza 			free($1);
23260a70aaf8SLuiz Otavio O Souza 		}
23270a70aaf8SLuiz Otavio O Souza 		;
23280a70aaf8SLuiz Otavio O Souza 
23293b3a8eb9SGleb Smirnoff qassign		: /* empty */		{ $$ = NULL; }
23303b3a8eb9SGleb Smirnoff 		| qassign_item		{ $$ = $1; }
23313b3a8eb9SGleb Smirnoff 		| '{' optnl qassign_list '}'	{ $$ = $3; }
23323b3a8eb9SGleb Smirnoff 		;
23333b3a8eb9SGleb Smirnoff 
23343b3a8eb9SGleb Smirnoff qassign_list	: qassign_item optnl		{ $$ = $1; }
23353b3a8eb9SGleb Smirnoff 		| qassign_list comma qassign_item optnl	{
23363b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
23373b3a8eb9SGleb Smirnoff 			$1->tail = $3;
23383b3a8eb9SGleb Smirnoff 			$$ = $1;
23393b3a8eb9SGleb Smirnoff 		}
23403b3a8eb9SGleb Smirnoff 		;
23413b3a8eb9SGleb Smirnoff 
23423b3a8eb9SGleb Smirnoff qassign_item	: STRING			{
23433b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_queue));
23443b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
23453b3a8eb9SGleb Smirnoff 				err(1, "qassign_item: calloc");
23463b3a8eb9SGleb Smirnoff 			if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
23473b3a8eb9SGleb Smirnoff 			    sizeof($$->queue)) {
23483b3a8eb9SGleb Smirnoff 				yyerror("queue name '%s' too long (max "
23493b3a8eb9SGleb Smirnoff 				    "%d chars)", $1, sizeof($$->queue)-1);
23503b3a8eb9SGleb Smirnoff 				free($1);
23513b3a8eb9SGleb Smirnoff 				free($$);
23523b3a8eb9SGleb Smirnoff 				YYERROR;
23533b3a8eb9SGleb Smirnoff 			}
23543b3a8eb9SGleb Smirnoff 			free($1);
23553b3a8eb9SGleb Smirnoff 			$$->next = NULL;
23563b3a8eb9SGleb Smirnoff 			$$->tail = $$;
23573b3a8eb9SGleb Smirnoff 		}
23583b3a8eb9SGleb Smirnoff 		;
23593b3a8eb9SGleb Smirnoff 
23603b3a8eb9SGleb Smirnoff pfrule		: action dir logquick interface route af proto fromto
23613b3a8eb9SGleb Smirnoff 		    filter_opts
23623b3a8eb9SGleb Smirnoff 		{
2363e9eb0941SKristof Provost 			struct pfctl_rule	 r;
23643b3a8eb9SGleb Smirnoff 			struct node_state_opt	*o;
23653b3a8eb9SGleb Smirnoff 			struct node_proto	*proto;
23663b3a8eb9SGleb Smirnoff 			int			 srctrack = 0;
23673b3a8eb9SGleb Smirnoff 			int			 statelock = 0;
23683b3a8eb9SGleb Smirnoff 			int			 adaptive = 0;
23693b3a8eb9SGleb Smirnoff 			int			 defaults = 0;
23703b3a8eb9SGleb Smirnoff 
23713b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_FILTER))
23723b3a8eb9SGleb Smirnoff 				YYERROR;
23733b3a8eb9SGleb Smirnoff 
23743b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
23753b3a8eb9SGleb Smirnoff 
23763b3a8eb9SGleb Smirnoff 			r.action = $1.b1;
23773b3a8eb9SGleb Smirnoff 			switch ($1.b2) {
23783b3a8eb9SGleb Smirnoff 			case PFRULE_RETURNRST:
23793b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RETURNRST;
23803b3a8eb9SGleb Smirnoff 				r.return_ttl = $1.w;
23813b3a8eb9SGleb Smirnoff 				break;
23823b3a8eb9SGleb Smirnoff 			case PFRULE_RETURNICMP:
23833b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RETURNICMP;
23843b3a8eb9SGleb Smirnoff 				r.return_icmp = $1.w;
23853b3a8eb9SGleb Smirnoff 				r.return_icmp6 = $1.w2;
23863b3a8eb9SGleb Smirnoff 				break;
23873b3a8eb9SGleb Smirnoff 			case PFRULE_RETURN:
23883b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_RETURN;
23893b3a8eb9SGleb Smirnoff 				r.return_icmp = $1.w;
23903b3a8eb9SGleb Smirnoff 				r.return_icmp6 = $1.w2;
23913b3a8eb9SGleb Smirnoff 				break;
23923b3a8eb9SGleb Smirnoff 			}
23933b3a8eb9SGleb Smirnoff 			r.direction = $2;
23943b3a8eb9SGleb Smirnoff 			r.log = $3.log;
23953b3a8eb9SGleb Smirnoff 			r.logif = $3.logif;
23963b3a8eb9SGleb Smirnoff 			r.quick = $3.quick;
23973b3a8eb9SGleb Smirnoff 			r.prob = $9.prob;
23983b3a8eb9SGleb Smirnoff 			r.rtableid = $9.rtableid;
23993b3a8eb9SGleb Smirnoff 
240039282ef3SKajetan Staszkiewicz 			if ($9.nodf)
240139282ef3SKajetan Staszkiewicz 				r.scrub_flags |= PFSTATE_NODF;
240239282ef3SKajetan Staszkiewicz 			if ($9.randomid)
240339282ef3SKajetan Staszkiewicz 				r.scrub_flags |= PFSTATE_RANDOMID;
240439282ef3SKajetan Staszkiewicz 			if ($9.minttl)
240539282ef3SKajetan Staszkiewicz 				r.min_ttl = $9.minttl;
240639282ef3SKajetan Staszkiewicz 			if ($9.max_mss)
240739282ef3SKajetan Staszkiewicz 				r.max_mss = $9.max_mss;
240839282ef3SKajetan Staszkiewicz 			if ($9.marker & FOM_SETTOS) {
240939282ef3SKajetan Staszkiewicz 				r.scrub_flags |= PFSTATE_SETTOS;
241039282ef3SKajetan Staszkiewicz 				r.set_tos = $9.settos;
241139282ef3SKajetan Staszkiewicz 			}
241239282ef3SKajetan Staszkiewicz 			if ($9.marker & FOM_SCRUB_TCP)
241339282ef3SKajetan Staszkiewicz 				r.scrub_flags |= PFSTATE_SCRUB_TCP;
241439282ef3SKajetan Staszkiewicz 
24153e248e0fSKristof Provost 			if ($9.marker & FOM_PRIO) {
24163e248e0fSKristof Provost 				if ($9.prio == 0)
24173e248e0fSKristof Provost 					r.prio = PF_PRIO_ZERO;
24183e248e0fSKristof Provost 				else
24193e248e0fSKristof Provost 					r.prio = $9.prio;
24203e248e0fSKristof Provost 			}
24213e248e0fSKristof Provost 			if ($9.marker & FOM_SETPRIO) {
24223e248e0fSKristof Provost 				r.set_prio[0] = $9.set_prio[0];
24233e248e0fSKristof Provost 				r.set_prio[1] = $9.set_prio[1];
24243e248e0fSKristof Provost 				r.scrub_flags |= PFSTATE_SETPRIO;
24253e248e0fSKristof Provost 			}
24263e248e0fSKristof Provost 
2427899e7976SKristof Provost 			if ($9.marker & FOM_AFTO)
2428f88019e8SKristof Provost 				r.rule_flag |= PFRULE_AFTO;
2429aa69fdf1SKristof Provost 
24303b3a8eb9SGleb Smirnoff 			r.af = $6;
24313b3a8eb9SGleb Smirnoff 			if ($9.tag)
24323b3a8eb9SGleb Smirnoff 				if (strlcpy(r.tagname, $9.tag,
24333b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
24343b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
24353b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
24363b3a8eb9SGleb Smirnoff 					YYERROR;
24373b3a8eb9SGleb Smirnoff 				}
24383b3a8eb9SGleb Smirnoff 			if ($9.match_tag)
24393b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $9.match_tag,
24403b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
24413b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
24423b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
24433b3a8eb9SGleb Smirnoff 					YYERROR;
24443b3a8eb9SGleb Smirnoff 				}
24453b3a8eb9SGleb Smirnoff 			r.match_tag_not = $9.match_tag_not;
24463b3a8eb9SGleb Smirnoff 			if (rule_label(&r, $9.label))
24473b3a8eb9SGleb Smirnoff 				YYERROR;
24486fcc8e04SKristof Provost 			for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
24496fcc8e04SKristof Provost 				free($9.label[i]);
245076c5eeccSKristof Provost 			r.ridentifier = $9.ridentifier;
24513b3a8eb9SGleb Smirnoff 			r.flags = $9.flags.b1;
24523b3a8eb9SGleb Smirnoff 			r.flagset = $9.flags.b2;
24533b3a8eb9SGleb Smirnoff 			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
24543b3a8eb9SGleb Smirnoff 				yyerror("flags always false");
24553b3a8eb9SGleb Smirnoff 				YYERROR;
24563b3a8eb9SGleb Smirnoff 			}
24573b3a8eb9SGleb Smirnoff 			if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
24583b3a8eb9SGleb Smirnoff 				for (proto = $7; proto != NULL &&
24593b3a8eb9SGleb Smirnoff 				    proto->proto != IPPROTO_TCP;
24603b3a8eb9SGleb Smirnoff 				    proto = proto->next)
24613b3a8eb9SGleb Smirnoff 					;	/* nothing */
24623b3a8eb9SGleb Smirnoff 				if (proto == NULL && $7 != NULL) {
24633b3a8eb9SGleb Smirnoff 					if ($9.flags.b1 || $9.flags.b2)
24643b3a8eb9SGleb Smirnoff 						yyerror(
24653b3a8eb9SGleb Smirnoff 						    "flags only apply to tcp");
24663b3a8eb9SGleb Smirnoff 					if ($8.src_os)
24673b3a8eb9SGleb Smirnoff 						yyerror(
24683b3a8eb9SGleb Smirnoff 						    "OS fingerprinting only "
24693b3a8eb9SGleb Smirnoff 						    "apply to tcp");
24703b3a8eb9SGleb Smirnoff 					YYERROR;
24713b3a8eb9SGleb Smirnoff 				}
24723b3a8eb9SGleb Smirnoff #if 0
24733b3a8eb9SGleb Smirnoff 				if (($9.flags.b1 & parse_flags("S")) == 0 &&
24743b3a8eb9SGleb Smirnoff 				    $8.src_os) {
24753b3a8eb9SGleb Smirnoff 					yyerror("OS fingerprinting requires "
24763b3a8eb9SGleb Smirnoff 					    "the SYN TCP flag (flags S/SA)");
24773b3a8eb9SGleb Smirnoff 					YYERROR;
24783b3a8eb9SGleb Smirnoff 				}
24793b3a8eb9SGleb Smirnoff #endif
24803b3a8eb9SGleb Smirnoff 			}
24813b3a8eb9SGleb Smirnoff 
24823b3a8eb9SGleb Smirnoff 			r.tos = $9.tos;
24833b3a8eb9SGleb Smirnoff 			r.keep_state = $9.keep.action;
24843b3a8eb9SGleb Smirnoff 			o = $9.keep.options;
24853b3a8eb9SGleb Smirnoff 
24863b3a8eb9SGleb Smirnoff 			/* 'keep state' by default on pass rules. */
24873b3a8eb9SGleb Smirnoff 			if (!r.keep_state && !r.action &&
24883b3a8eb9SGleb Smirnoff 			    !($9.marker & FOM_KEEP)) {
24893b3a8eb9SGleb Smirnoff 				r.keep_state = PF_STATE_NORMAL;
24903b3a8eb9SGleb Smirnoff 				o = keep_state_defaults;
24913b3a8eb9SGleb Smirnoff 				defaults = 1;
24923b3a8eb9SGleb Smirnoff 			}
24933b3a8eb9SGleb Smirnoff 
24943b3a8eb9SGleb Smirnoff 			while (o) {
24953b3a8eb9SGleb Smirnoff 				struct node_state_opt	*p = o;
24963b3a8eb9SGleb Smirnoff 
24973b3a8eb9SGleb Smirnoff 				switch (o->type) {
24983b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX:
24993b3a8eb9SGleb Smirnoff 					if (r.max_states) {
25003b3a8eb9SGleb Smirnoff 						yyerror("state option 'max' "
25013b3a8eb9SGleb Smirnoff 						    "multiple definitions");
25023b3a8eb9SGleb Smirnoff 						YYERROR;
25033b3a8eb9SGleb Smirnoff 					}
25043b3a8eb9SGleb Smirnoff 					r.max_states = o->data.max_states;
25053b3a8eb9SGleb Smirnoff 					break;
25063b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_NOSYNC:
25073b3a8eb9SGleb Smirnoff 					if (r.rule_flag & PFRULE_NOSYNC) {
25083b3a8eb9SGleb Smirnoff 						yyerror("state option 'sync' "
25093b3a8eb9SGleb Smirnoff 						    "multiple definitions");
25103b3a8eb9SGleb Smirnoff 						YYERROR;
25113b3a8eb9SGleb Smirnoff 					}
25123b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_NOSYNC;
25133b3a8eb9SGleb Smirnoff 					break;
25143b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_SRCTRACK:
25153b3a8eb9SGleb Smirnoff 					if (srctrack) {
25163b3a8eb9SGleb Smirnoff 						yyerror("state option "
25173b3a8eb9SGleb Smirnoff 						    "'source-track' "
25183b3a8eb9SGleb Smirnoff 						    "multiple definitions");
25193b3a8eb9SGleb Smirnoff 						YYERROR;
25203b3a8eb9SGleb Smirnoff 					}
25213b3a8eb9SGleb Smirnoff 					srctrack =  o->data.src_track;
25223b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK;
25233b3a8eb9SGleb Smirnoff 					break;
25243b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_STATES:
25253b3a8eb9SGleb Smirnoff 					if (r.max_src_states) {
25263b3a8eb9SGleb Smirnoff 						yyerror("state option "
25273b3a8eb9SGleb Smirnoff 						    "'max-src-states' "
25283b3a8eb9SGleb Smirnoff 						    "multiple definitions");
25293b3a8eb9SGleb Smirnoff 						YYERROR;
25303b3a8eb9SGleb Smirnoff 					}
25313b3a8eb9SGleb Smirnoff 					if (o->data.max_src_states == 0) {
25323b3a8eb9SGleb Smirnoff 						yyerror("'max-src-states' must "
25333b3a8eb9SGleb Smirnoff 						    "be > 0");
25343b3a8eb9SGleb Smirnoff 						YYERROR;
25353b3a8eb9SGleb Smirnoff 					}
25363b3a8eb9SGleb Smirnoff 					r.max_src_states =
25373b3a8eb9SGleb Smirnoff 					    o->data.max_src_states;
25383b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK;
25393b3a8eb9SGleb Smirnoff 					break;
25403b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_OVERLOAD:
25413b3a8eb9SGleb Smirnoff 					if (r.overload_tblname[0]) {
25423b3a8eb9SGleb Smirnoff 						yyerror("multiple 'overload' "
25433b3a8eb9SGleb Smirnoff 						    "table definitions");
25443b3a8eb9SGleb Smirnoff 						YYERROR;
25453b3a8eb9SGleb Smirnoff 					}
25463b3a8eb9SGleb Smirnoff 					if (strlcpy(r.overload_tblname,
25473b3a8eb9SGleb Smirnoff 					    o->data.overload.tblname,
25483b3a8eb9SGleb Smirnoff 					    PF_TABLE_NAME_SIZE) >=
25493b3a8eb9SGleb Smirnoff 					    PF_TABLE_NAME_SIZE) {
25503b3a8eb9SGleb Smirnoff 						yyerror("state option: "
25513b3a8eb9SGleb Smirnoff 						    "strlcpy");
25523b3a8eb9SGleb Smirnoff 						YYERROR;
25533b3a8eb9SGleb Smirnoff 					}
25543b3a8eb9SGleb Smirnoff 					r.flush = o->data.overload.flush;
25553b3a8eb9SGleb Smirnoff 					break;
25563b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_CONN:
25573b3a8eb9SGleb Smirnoff 					if (r.max_src_conn) {
25583b3a8eb9SGleb Smirnoff 						yyerror("state option "
25593b3a8eb9SGleb Smirnoff 						    "'max-src-conn' "
25603b3a8eb9SGleb Smirnoff 						    "multiple definitions");
25613b3a8eb9SGleb Smirnoff 						YYERROR;
25623b3a8eb9SGleb Smirnoff 					}
25633b3a8eb9SGleb Smirnoff 					if (o->data.max_src_conn == 0) {
25643b3a8eb9SGleb Smirnoff 						yyerror("'max-src-conn' "
25653b3a8eb9SGleb Smirnoff 						    "must be > 0");
25663b3a8eb9SGleb Smirnoff 						YYERROR;
25673b3a8eb9SGleb Smirnoff 					}
25683b3a8eb9SGleb Smirnoff 					r.max_src_conn =
25693b3a8eb9SGleb Smirnoff 					    o->data.max_src_conn;
25703b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK |
25713b3a8eb9SGleb Smirnoff 					    PFRULE_RULESRCTRACK;
25723b3a8eb9SGleb Smirnoff 					break;
25733b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_CONN_RATE:
25743b3a8eb9SGleb Smirnoff 					if (r.max_src_conn_rate.limit) {
25753b3a8eb9SGleb Smirnoff 						yyerror("state option "
25763b3a8eb9SGleb Smirnoff 						    "'max-src-conn-rate' "
25773b3a8eb9SGleb Smirnoff 						    "multiple definitions");
25783b3a8eb9SGleb Smirnoff 						YYERROR;
25793b3a8eb9SGleb Smirnoff 					}
25803b3a8eb9SGleb Smirnoff 					if (!o->data.max_src_conn_rate.limit ||
25813b3a8eb9SGleb Smirnoff 					    !o->data.max_src_conn_rate.seconds) {
25823b3a8eb9SGleb Smirnoff 						yyerror("'max-src-conn-rate' "
25833b3a8eb9SGleb Smirnoff 						    "values must be > 0");
25843b3a8eb9SGleb Smirnoff 						YYERROR;
25853b3a8eb9SGleb Smirnoff 					}
25863b3a8eb9SGleb Smirnoff 					if (o->data.max_src_conn_rate.limit >
25873b3a8eb9SGleb Smirnoff 					    PF_THRESHOLD_MAX) {
25883b3a8eb9SGleb Smirnoff 						yyerror("'max-src-conn-rate' "
25893b3a8eb9SGleb Smirnoff 						    "maximum rate must be < %u",
25903b3a8eb9SGleb Smirnoff 						    PF_THRESHOLD_MAX);
25913b3a8eb9SGleb Smirnoff 						YYERROR;
25923b3a8eb9SGleb Smirnoff 					}
25933b3a8eb9SGleb Smirnoff 					r.max_src_conn_rate.limit =
25943b3a8eb9SGleb Smirnoff 					    o->data.max_src_conn_rate.limit;
25953b3a8eb9SGleb Smirnoff 					r.max_src_conn_rate.seconds =
25963b3a8eb9SGleb Smirnoff 					    o->data.max_src_conn_rate.seconds;
25973b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK |
25983b3a8eb9SGleb Smirnoff 					    PFRULE_RULESRCTRACK;
25993b3a8eb9SGleb Smirnoff 					break;
26003b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_MAX_SRC_NODES:
26013b3a8eb9SGleb Smirnoff 					if (r.max_src_nodes) {
26023b3a8eb9SGleb Smirnoff 						yyerror("state option "
26033b3a8eb9SGleb Smirnoff 						    "'max-src-nodes' "
26043b3a8eb9SGleb Smirnoff 						    "multiple definitions");
26053b3a8eb9SGleb Smirnoff 						YYERROR;
26063b3a8eb9SGleb Smirnoff 					}
26073b3a8eb9SGleb Smirnoff 					if (o->data.max_src_nodes == 0) {
26083b3a8eb9SGleb Smirnoff 						yyerror("'max-src-nodes' must "
26093b3a8eb9SGleb Smirnoff 						    "be > 0");
26103b3a8eb9SGleb Smirnoff 						YYERROR;
26113b3a8eb9SGleb Smirnoff 					}
26123b3a8eb9SGleb Smirnoff 					r.max_src_nodes =
26133b3a8eb9SGleb Smirnoff 					    o->data.max_src_nodes;
26143b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_SRCTRACK |
26153b3a8eb9SGleb Smirnoff 					    PFRULE_RULESRCTRACK;
26163b3a8eb9SGleb Smirnoff 					break;
26173b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_STATELOCK:
26183b3a8eb9SGleb Smirnoff 					if (statelock) {
26193b3a8eb9SGleb Smirnoff 						yyerror("state locking option: "
26203b3a8eb9SGleb Smirnoff 						    "multiple definitions");
26213b3a8eb9SGleb Smirnoff 						YYERROR;
26223b3a8eb9SGleb Smirnoff 					}
26233b3a8eb9SGleb Smirnoff 					statelock = 1;
26243b3a8eb9SGleb Smirnoff 					r.rule_flag |= o->data.statelock;
26253b3a8eb9SGleb Smirnoff 					break;
26263b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_SLOPPY:
26273b3a8eb9SGleb Smirnoff 					if (r.rule_flag & PFRULE_STATESLOPPY) {
26283b3a8eb9SGleb Smirnoff 						yyerror("state sloppy option: "
26293b3a8eb9SGleb Smirnoff 						    "multiple definitions");
26303b3a8eb9SGleb Smirnoff 						YYERROR;
26313b3a8eb9SGleb Smirnoff 					}
26323b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_STATESLOPPY;
26333b3a8eb9SGleb Smirnoff 					break;
2634baf9b6d0SKristof Provost 				case PF_STATE_OPT_PFLOW:
2635baf9b6d0SKristof Provost 					if (r.rule_flag & PFRULE_PFLOW) {
2636baf9b6d0SKristof Provost 						yyerror("state pflow option: "
2637baf9b6d0SKristof Provost 						    "multiple definitions");
2638baf9b6d0SKristof Provost 						YYERROR;
2639baf9b6d0SKristof Provost 					}
2640baf9b6d0SKristof Provost 					r.rule_flag |= PFRULE_PFLOW;
2641baf9b6d0SKristof Provost 					break;
2642e4f2733dSKristof Provost 				case PF_STATE_OPT_ALLOW_RELATED:
2643e4f2733dSKristof Provost 					if (r.rule_flag & PFRULE_ALLOW_RELATED) {
2644e4f2733dSKristof Provost 						yyerror("state allow-related option: "
2645e4f2733dSKristof Provost 						    "multiple definitions");
2646e4f2733dSKristof Provost 						YYERROR;
2647e4f2733dSKristof Provost 					}
2648e4f2733dSKristof Provost 					r.rule_flag |= PFRULE_ALLOW_RELATED;
2649e4f2733dSKristof Provost 					break;
26503b3a8eb9SGleb Smirnoff 				case PF_STATE_OPT_TIMEOUT:
26513b3a8eb9SGleb Smirnoff 					if (o->data.timeout.number ==
26523b3a8eb9SGleb Smirnoff 					    PFTM_ADAPTIVE_START ||
26533b3a8eb9SGleb Smirnoff 					    o->data.timeout.number ==
26543b3a8eb9SGleb Smirnoff 					    PFTM_ADAPTIVE_END)
26553b3a8eb9SGleb Smirnoff 						adaptive = 1;
26563b3a8eb9SGleb Smirnoff 					if (r.timeout[o->data.timeout.number]) {
26573b3a8eb9SGleb Smirnoff 						yyerror("state timeout %s "
26583b3a8eb9SGleb Smirnoff 						    "multiple definitions",
26593b3a8eb9SGleb Smirnoff 						    pf_timeouts[o->data.
26603b3a8eb9SGleb Smirnoff 						    timeout.number].name);
26613b3a8eb9SGleb Smirnoff 						YYERROR;
26623b3a8eb9SGleb Smirnoff 					}
26633b3a8eb9SGleb Smirnoff 					r.timeout[o->data.timeout.number] =
26643b3a8eb9SGleb Smirnoff 					    o->data.timeout.seconds;
26653b3a8eb9SGleb Smirnoff 				}
26663b3a8eb9SGleb Smirnoff 				o = o->next;
26673b3a8eb9SGleb Smirnoff 				if (!defaults)
26683b3a8eb9SGleb Smirnoff 					free(p);
26693b3a8eb9SGleb Smirnoff 			}
26703b3a8eb9SGleb Smirnoff 
26713b3a8eb9SGleb Smirnoff 			/* 'flags S/SA' by default on stateful rules */
26723b3a8eb9SGleb Smirnoff 			if (!r.action && !r.flags && !r.flagset &&
26733b3a8eb9SGleb Smirnoff 			    !$9.fragment && !($9.marker & FOM_FLAGS) &&
26743b3a8eb9SGleb Smirnoff 			    r.keep_state) {
26753b3a8eb9SGleb Smirnoff 				r.flags = parse_flags("S");
26763b3a8eb9SGleb Smirnoff 				r.flagset =  parse_flags("SA");
26773b3a8eb9SGleb Smirnoff 			}
26783b3a8eb9SGleb Smirnoff 			if (!adaptive && r.max_states) {
26793b3a8eb9SGleb Smirnoff 				r.timeout[PFTM_ADAPTIVE_START] =
26803b3a8eb9SGleb Smirnoff 				    (r.max_states / 10) * 6;
26813b3a8eb9SGleb Smirnoff 				r.timeout[PFTM_ADAPTIVE_END] =
26823b3a8eb9SGleb Smirnoff 				    (r.max_states / 10) * 12;
26833b3a8eb9SGleb Smirnoff 			}
26843b3a8eb9SGleb Smirnoff 			if (r.rule_flag & PFRULE_SRCTRACK) {
26853b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_GLOBAL &&
26863b3a8eb9SGleb Smirnoff 				    r.max_src_nodes) {
26873b3a8eb9SGleb Smirnoff 					yyerror("'max-src-nodes' is "
26883b3a8eb9SGleb Smirnoff 					    "incompatible with "
26893b3a8eb9SGleb Smirnoff 					    "'source-track global'");
26903b3a8eb9SGleb Smirnoff 					YYERROR;
26913b3a8eb9SGleb Smirnoff 				}
26923b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_GLOBAL &&
26933b3a8eb9SGleb Smirnoff 				    r.max_src_conn) {
26943b3a8eb9SGleb Smirnoff 					yyerror("'max-src-conn' is "
26953b3a8eb9SGleb Smirnoff 					    "incompatible with "
26963b3a8eb9SGleb Smirnoff 					    "'source-track global'");
26973b3a8eb9SGleb Smirnoff 					YYERROR;
26983b3a8eb9SGleb Smirnoff 				}
26993b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_GLOBAL &&
27003b3a8eb9SGleb Smirnoff 				    r.max_src_conn_rate.seconds) {
27013b3a8eb9SGleb Smirnoff 					yyerror("'max-src-conn-rate' is "
27023b3a8eb9SGleb Smirnoff 					    "incompatible with "
27033b3a8eb9SGleb Smirnoff 					    "'source-track global'");
27043b3a8eb9SGleb Smirnoff 					YYERROR;
27053b3a8eb9SGleb Smirnoff 				}
27063b3a8eb9SGleb Smirnoff 				if (r.timeout[PFTM_SRC_NODE] <
27073b3a8eb9SGleb Smirnoff 				    r.max_src_conn_rate.seconds)
27083b3a8eb9SGleb Smirnoff 					r.timeout[PFTM_SRC_NODE] =
27093b3a8eb9SGleb Smirnoff 					    r.max_src_conn_rate.seconds;
27103b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_SRCTRACK;
27113b3a8eb9SGleb Smirnoff 				if (srctrack == PF_SRCTRACK_RULE)
27123b3a8eb9SGleb Smirnoff 					r.rule_flag |= PFRULE_RULESRCTRACK;
27133b3a8eb9SGleb Smirnoff 			}
27143b3a8eb9SGleb Smirnoff 			if (r.keep_state && !statelock)
27153b3a8eb9SGleb Smirnoff 				r.rule_flag |= default_statelock;
27163b3a8eb9SGleb Smirnoff 
27173b3a8eb9SGleb Smirnoff 			if ($9.fragment)
27183b3a8eb9SGleb Smirnoff 				r.rule_flag |= PFRULE_FRAGMENT;
27193b3a8eb9SGleb Smirnoff 			r.allow_opts = $9.allowopts;
27203b3a8eb9SGleb Smirnoff 
27213b3a8eb9SGleb Smirnoff 			decide_address_family($8.src.host, &r.af);
27223b3a8eb9SGleb Smirnoff 			decide_address_family($8.dst.host, &r.af);
27233b3a8eb9SGleb Smirnoff 
27243b3a8eb9SGleb Smirnoff 			if ($5.rt) {
27253b3a8eb9SGleb Smirnoff 				if (!r.direction) {
27263b3a8eb9SGleb Smirnoff 					yyerror("direction must be explicit "
27273b3a8eb9SGleb Smirnoff 					    "with rules that specify routing");
27283b3a8eb9SGleb Smirnoff 					YYERROR;
27293b3a8eb9SGleb Smirnoff 				}
27303b3a8eb9SGleb Smirnoff 				r.rt = $5.rt;
27310972294eSKristof Provost 				r.route.opts = $5.pool_opts;
27323b3a8eb9SGleb Smirnoff 				if ($5.key != NULL)
27330972294eSKristof Provost 					memcpy(&r.route.key, $5.key,
27343b3a8eb9SGleb Smirnoff 					    sizeof(struct pf_poolhashkey));
27353b3a8eb9SGleb Smirnoff 			}
2736813196a1SKristof Provost 			if (r.rt) {
27373b3a8eb9SGleb Smirnoff 				decide_address_family($5.host, &r.af);
2738ca0e6934SKristof Provost 				if (!(r.rule_flag & PFRULE_AFTO))
27393b3a8eb9SGleb Smirnoff 					remove_invalid_hosts(&$5.host, &r.af);
27403b3a8eb9SGleb Smirnoff 				if ($5.host == NULL) {
27413b3a8eb9SGleb Smirnoff 					yyerror("no routing address with "
27423b3a8eb9SGleb Smirnoff 					    "matching address family found.");
27433b3a8eb9SGleb Smirnoff 					YYERROR;
27443b3a8eb9SGleb Smirnoff 				}
27450972294eSKristof Provost 				if ((r.route.opts & PF_POOL_TYPEMASK) ==
27463b3a8eb9SGleb Smirnoff 				    PF_POOL_NONE && ($5.host->next != NULL ||
27473b3a8eb9SGleb Smirnoff 				    $5.host->addr.type == PF_ADDR_TABLE ||
27483b3a8eb9SGleb Smirnoff 				    DYNIF_MULTIADDR($5.host->addr)))
27490972294eSKristof Provost 					r.route.opts |= PF_POOL_ROUNDROBIN;
27500972294eSKristof Provost 				if ((r.route.opts & PF_POOL_TYPEMASK) !=
27513b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
27523b3a8eb9SGleb Smirnoff 				    disallow_table($5.host, "tables are only "
27533b3a8eb9SGleb Smirnoff 				    "supported in round-robin routing pools"))
27543b3a8eb9SGleb Smirnoff 					YYERROR;
27550972294eSKristof Provost 				if ((r.route.opts & PF_POOL_TYPEMASK) !=
27563b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
27573b3a8eb9SGleb Smirnoff 				    disallow_alias($5.host, "interface (%s) "
27583b3a8eb9SGleb Smirnoff 				    "is only supported in round-robin "
27593b3a8eb9SGleb Smirnoff 				    "routing pools"))
27603b3a8eb9SGleb Smirnoff 					YYERROR;
27613b3a8eb9SGleb Smirnoff 				if ($5.host->next != NULL) {
27620972294eSKristof Provost 					if ((r.route.opts & PF_POOL_TYPEMASK) !=
27633b3a8eb9SGleb Smirnoff 					    PF_POOL_ROUNDROBIN) {
27640972294eSKristof Provost 						yyerror("r.route.opts must "
27653b3a8eb9SGleb Smirnoff 						    "be PF_POOL_ROUNDROBIN");
27663b3a8eb9SGleb Smirnoff 						YYERROR;
27673b3a8eb9SGleb Smirnoff 					}
27683b3a8eb9SGleb Smirnoff 				}
27693b3a8eb9SGleb Smirnoff 			}
27703b3a8eb9SGleb Smirnoff 			if ($9.queues.qname != NULL) {
27713b3a8eb9SGleb Smirnoff 				if (strlcpy(r.qname, $9.queues.qname,
27723b3a8eb9SGleb Smirnoff 				    sizeof(r.qname)) >= sizeof(r.qname)) {
27733b3a8eb9SGleb Smirnoff 					yyerror("rule qname too long (max "
27743b3a8eb9SGleb Smirnoff 					    "%d chars)", sizeof(r.qname)-1);
27753b3a8eb9SGleb Smirnoff 					YYERROR;
27763b3a8eb9SGleb Smirnoff 				}
27773b3a8eb9SGleb Smirnoff 				free($9.queues.qname);
27783b3a8eb9SGleb Smirnoff 			}
27793b3a8eb9SGleb Smirnoff 			if ($9.queues.pqname != NULL) {
27803b3a8eb9SGleb Smirnoff 				if (strlcpy(r.pqname, $9.queues.pqname,
27813b3a8eb9SGleb Smirnoff 				    sizeof(r.pqname)) >= sizeof(r.pqname)) {
27823b3a8eb9SGleb Smirnoff 					yyerror("rule pqname too long (max "
27833b3a8eb9SGleb Smirnoff 					    "%d chars)", sizeof(r.pqname)-1);
27843b3a8eb9SGleb Smirnoff 					YYERROR;
27853b3a8eb9SGleb Smirnoff 				}
27863b3a8eb9SGleb Smirnoff 				free($9.queues.pqname);
27873b3a8eb9SGleb Smirnoff 			}
27883b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
27893b3a8eb9SGleb Smirnoff 			r.divert.port = $9.divert.port;
27903b3a8eb9SGleb Smirnoff #else
27913b3a8eb9SGleb Smirnoff 			if ((r.divert.port = $9.divert.port)) {
27923b3a8eb9SGleb Smirnoff 				if (r.direction == PF_OUT) {
27933b3a8eb9SGleb Smirnoff 					if ($9.divert.addr) {
27943b3a8eb9SGleb Smirnoff 						yyerror("address specified "
27953b3a8eb9SGleb Smirnoff 						    "for outgoing divert");
27963b3a8eb9SGleb Smirnoff 						YYERROR;
27973b3a8eb9SGleb Smirnoff 					}
27983b3a8eb9SGleb Smirnoff 					bzero(&r.divert.addr,
27993b3a8eb9SGleb Smirnoff 					    sizeof(r.divert.addr));
28003b3a8eb9SGleb Smirnoff 				} else {
28013b3a8eb9SGleb Smirnoff 					if (!$9.divert.addr) {
28023b3a8eb9SGleb Smirnoff 						yyerror("no address specified "
28033b3a8eb9SGleb Smirnoff 						    "for incoming divert");
28043b3a8eb9SGleb Smirnoff 						YYERROR;
28053b3a8eb9SGleb Smirnoff 					}
28063b3a8eb9SGleb Smirnoff 					if ($9.divert.addr->af != r.af) {
28073b3a8eb9SGleb Smirnoff 						yyerror("address family "
28083b3a8eb9SGleb Smirnoff 						    "mismatch for divert");
28093b3a8eb9SGleb Smirnoff 						YYERROR;
28103b3a8eb9SGleb Smirnoff 					}
28113b3a8eb9SGleb Smirnoff 					r.divert.addr =
28123b3a8eb9SGleb Smirnoff 					    $9.divert.addr->addr.v.a.addr;
28133b3a8eb9SGleb Smirnoff 				}
28143b3a8eb9SGleb Smirnoff 			}
28153b3a8eb9SGleb Smirnoff #endif
28163b3a8eb9SGleb Smirnoff 
281763b3c1c7SKristof Provost 			if ($9.dnpipe || $9.dnrpipe) {
281863b3c1c7SKristof Provost 				r.dnpipe = $9.dnpipe;
281963b3c1c7SKristof Provost 				r.dnrpipe = $9.dnrpipe;
282063b3c1c7SKristof Provost 				if ($9.free_flags & PFRULE_DN_IS_PIPE)
282163b3c1c7SKristof Provost 					r.free_flags |= PFRULE_DN_IS_PIPE;
282263b3c1c7SKristof Provost 				else
282363b3c1c7SKristof Provost 					r.free_flags |= PFRULE_DN_IS_QUEUE;
282463b3c1c7SKristof Provost 			}
282563b3c1c7SKristof Provost 
2826e0dcc51dSKristof Provost 			if ($9.marker & FOM_AFTO) {
2827aa69fdf1SKristof Provost 				r.naf = $9.nat.af;
2828aa69fdf1SKristof Provost 
2829aa69fdf1SKristof Provost 				r.nat.opts = $9.nat.pool_opts.type;
2830aa69fdf1SKristof Provost 				r.nat.opts |= $9.nat.pool_opts.opts;
2831e0dcc51dSKristof Provost 
2832e0dcc51dSKristof Provost 				if ((r.nat.opts & PF_POOL_TYPEMASK) !=
2833e0dcc51dSKristof Provost 				    PF_POOL_ROUNDROBIN &&
2834e0dcc51dSKristof Provost 				    disallow_table($9.nat.rdr->host, "tables are only "
2835e0dcc51dSKristof Provost 				    "supported in round-robin pools"))
2836e0dcc51dSKristof Provost 					YYERROR;
2837e0dcc51dSKristof Provost 			}
2838e0dcc51dSKristof Provost 
28390972294eSKristof Provost 			expand_rule(&r, $4, &$9.nat, &$9.rdr, &$9.rroute,
28400972294eSKristof Provost 			    NULL, $9.nat.rdr ? $9.nat.rdr->host : NULL, $5.host,
2841aa69fdf1SKristof Provost 			    $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host,
2842aa69fdf1SKristof Provost 			    $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, "");
28433b3a8eb9SGleb Smirnoff 		}
28443b3a8eb9SGleb Smirnoff 		;
28453b3a8eb9SGleb Smirnoff 
28463b3a8eb9SGleb Smirnoff filter_opts	:	{
28473b3a8eb9SGleb Smirnoff 				bzero(&filter_opts, sizeof filter_opts);
28483b3a8eb9SGleb Smirnoff 				filter_opts.rtableid = -1;
28493b3a8eb9SGleb Smirnoff 			}
28503b3a8eb9SGleb Smirnoff 		    filter_opts_l
28513b3a8eb9SGleb Smirnoff 			{ $$ = filter_opts; }
28523b3a8eb9SGleb Smirnoff 		| /* empty */	{
28533b3a8eb9SGleb Smirnoff 			bzero(&filter_opts, sizeof filter_opts);
28543b3a8eb9SGleb Smirnoff 			filter_opts.rtableid = -1;
28553b3a8eb9SGleb Smirnoff 			$$ = filter_opts;
28563b3a8eb9SGleb Smirnoff 		}
28573b3a8eb9SGleb Smirnoff 		;
28583b3a8eb9SGleb Smirnoff 
28593b3a8eb9SGleb Smirnoff filter_opts_l	: filter_opts_l filter_opt
28603b3a8eb9SGleb Smirnoff 		| filter_opt
28613b3a8eb9SGleb Smirnoff 		;
28623b3a8eb9SGleb Smirnoff 
28633b3a8eb9SGleb Smirnoff filter_opt	: USER uids {
28643b3a8eb9SGleb Smirnoff 			if (filter_opts.uid)
28653b3a8eb9SGleb Smirnoff 				$2->tail->next = filter_opts.uid;
28663b3a8eb9SGleb Smirnoff 			filter_opts.uid = $2;
28673b3a8eb9SGleb Smirnoff 		}
28683b3a8eb9SGleb Smirnoff 		| GROUP gids {
28693b3a8eb9SGleb Smirnoff 			if (filter_opts.gid)
28703b3a8eb9SGleb Smirnoff 				$2->tail->next = filter_opts.gid;
28713b3a8eb9SGleb Smirnoff 			filter_opts.gid = $2;
28723b3a8eb9SGleb Smirnoff 		}
28733b3a8eb9SGleb Smirnoff 		| flags {
28743b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_FLAGS) {
28753b3a8eb9SGleb Smirnoff 				yyerror("flags cannot be redefined");
28763b3a8eb9SGleb Smirnoff 				YYERROR;
28773b3a8eb9SGleb Smirnoff 			}
28783b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_FLAGS;
28793b3a8eb9SGleb Smirnoff 			filter_opts.flags.b1 |= $1.b1;
28803b3a8eb9SGleb Smirnoff 			filter_opts.flags.b2 |= $1.b2;
28813b3a8eb9SGleb Smirnoff 			filter_opts.flags.w |= $1.w;
28823b3a8eb9SGleb Smirnoff 			filter_opts.flags.w2 |= $1.w2;
28833b3a8eb9SGleb Smirnoff 		}
28843b3a8eb9SGleb Smirnoff 		| icmpspec {
28853b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_ICMP) {
28863b3a8eb9SGleb Smirnoff 				yyerror("icmp-type cannot be redefined");
28873b3a8eb9SGleb Smirnoff 				YYERROR;
28883b3a8eb9SGleb Smirnoff 			}
28893b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_ICMP;
28903b3a8eb9SGleb Smirnoff 			filter_opts.icmpspec = $1;
28913b3a8eb9SGleb Smirnoff 		}
28923e248e0fSKristof Provost 		| PRIO NUMBER {
28933e248e0fSKristof Provost 			if (filter_opts.marker & FOM_PRIO) {
28943e248e0fSKristof Provost 				yyerror("prio cannot be redefined");
28953e248e0fSKristof Provost 				YYERROR;
28963e248e0fSKristof Provost 			}
28973e248e0fSKristof Provost 			if ($2 < 0 || $2 > PF_PRIO_MAX) {
28983e248e0fSKristof Provost 				yyerror("prio must be 0 - %u", PF_PRIO_MAX);
28993e248e0fSKristof Provost 				YYERROR;
29003e248e0fSKristof Provost 			}
29013e248e0fSKristof Provost 			filter_opts.marker |= FOM_PRIO;
29023e248e0fSKristof Provost 			filter_opts.prio = $2;
29033e248e0fSKristof Provost 		}
29043b3a8eb9SGleb Smirnoff 		| TOS tos {
29053b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_TOS) {
29063b3a8eb9SGleb Smirnoff 				yyerror("tos cannot be redefined");
29073b3a8eb9SGleb Smirnoff 				YYERROR;
29083b3a8eb9SGleb Smirnoff 			}
29093b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_TOS;
29103b3a8eb9SGleb Smirnoff 			filter_opts.tos = $2;
29113b3a8eb9SGleb Smirnoff 		}
29123b3a8eb9SGleb Smirnoff 		| keep {
29133b3a8eb9SGleb Smirnoff 			if (filter_opts.marker & FOM_KEEP) {
29143b3a8eb9SGleb Smirnoff 				yyerror("modulate or keep cannot be redefined");
29153b3a8eb9SGleb Smirnoff 				YYERROR;
29163b3a8eb9SGleb Smirnoff 			}
29173b3a8eb9SGleb Smirnoff 			filter_opts.marker |= FOM_KEEP;
29183b3a8eb9SGleb Smirnoff 			filter_opts.keep.action = $1.action;
29193b3a8eb9SGleb Smirnoff 			filter_opts.keep.options = $1.options;
29203b3a8eb9SGleb Smirnoff 		}
292176c5eeccSKristof Provost 		| RIDENTIFIER number {
292276c5eeccSKristof Provost 			filter_opts.ridentifier = $2;
292376c5eeccSKristof Provost 		}
29243b3a8eb9SGleb Smirnoff 		| FRAGMENT {
29253b3a8eb9SGleb Smirnoff 			filter_opts.fragment = 1;
29263b3a8eb9SGleb Smirnoff 		}
29273b3a8eb9SGleb Smirnoff 		| ALLOWOPTS {
29283b3a8eb9SGleb Smirnoff 			filter_opts.allowopts = 1;
29293b3a8eb9SGleb Smirnoff 		}
29303b3a8eb9SGleb Smirnoff 		| label	{
29316fcc8e04SKristof Provost 			if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) {
29326fcc8e04SKristof Provost 				yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT);
29333b3a8eb9SGleb Smirnoff 				YYERROR;
29343b3a8eb9SGleb Smirnoff 			}
29356fcc8e04SKristof Provost 			filter_opts.label[filter_opts.labelcount++] = $1;
29363b3a8eb9SGleb Smirnoff 		}
29373b3a8eb9SGleb Smirnoff 		| qname	{
29383b3a8eb9SGleb Smirnoff 			if (filter_opts.queues.qname) {
29393b3a8eb9SGleb Smirnoff 				yyerror("queue cannot be redefined");
29403b3a8eb9SGleb Smirnoff 				YYERROR;
29413b3a8eb9SGleb Smirnoff 			}
29423b3a8eb9SGleb Smirnoff 			filter_opts.queues = $1;
29433b3a8eb9SGleb Smirnoff 		}
294463b3c1c7SKristof Provost 		| DNPIPE number {
294563b3c1c7SKristof Provost 			filter_opts.dnpipe = $2;
294663b3c1c7SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
294763b3c1c7SKristof Provost 		}
294863b3c1c7SKristof Provost 		| DNPIPE '(' number ')' {
294963b3c1c7SKristof Provost 			filter_opts.dnpipe = $3;
295063b3c1c7SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
295163b3c1c7SKristof Provost 		}
295263b3c1c7SKristof Provost 		| DNPIPE '(' number comma number ')' {
295363b3c1c7SKristof Provost 			filter_opts.dnrpipe = $5;
295463b3c1c7SKristof Provost 			filter_opts.dnpipe = $3;
295563b3c1c7SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
295663b3c1c7SKristof Provost 		}
295763b3c1c7SKristof Provost 		| DNQUEUE number {
295863b3c1c7SKristof Provost 			filter_opts.dnpipe = $2;
295963b3c1c7SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
296063b3c1c7SKristof Provost 		}
296163b3c1c7SKristof Provost 		| DNQUEUE '(' number comma number ')' {
296263b3c1c7SKristof Provost 			filter_opts.dnrpipe = $5;
296363b3c1c7SKristof Provost 			filter_opts.dnpipe = $3;
296463b3c1c7SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
296563b3c1c7SKristof Provost 		}
296663b3c1c7SKristof Provost 		| DNQUEUE '(' number ')' {
296763b3c1c7SKristof Provost 			filter_opts.dnpipe = $3;
296863b3c1c7SKristof Provost 			filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
296963b3c1c7SKristof Provost 		}
29703b3a8eb9SGleb Smirnoff 		| TAG string				{
29713b3a8eb9SGleb Smirnoff 			filter_opts.tag = $2;
29723b3a8eb9SGleb Smirnoff 		}
29733b3a8eb9SGleb Smirnoff 		| not TAGGED string			{
29743b3a8eb9SGleb Smirnoff 			filter_opts.match_tag = $3;
29753b3a8eb9SGleb Smirnoff 			filter_opts.match_tag_not = $1;
29763b3a8eb9SGleb Smirnoff 		}
2977*71594e32SKristof Provost 		| not RECEIVEDON if_item {
29782339ead6SKristof Provost 			if (filter_opts.rcv) {
29792339ead6SKristof Provost 				yyerror("cannot respecify received-on");
29802339ead6SKristof Provost 				YYERROR;
29812339ead6SKristof Provost 			}
2982*71594e32SKristof Provost 			filter_opts.rcv = $3;
2983*71594e32SKristof Provost 			filter_opts.rcv->not = $1;
29842339ead6SKristof Provost 		}
29853b3a8eb9SGleb Smirnoff 		| PROBABILITY probability		{
29863b3a8eb9SGleb Smirnoff 			double	p;
29873b3a8eb9SGleb Smirnoff 
29883b3a8eb9SGleb Smirnoff 			p = floor($2 * UINT_MAX + 0.5);
29893b3a8eb9SGleb Smirnoff 			if (p < 0.0 || p > UINT_MAX) {
29903b3a8eb9SGleb Smirnoff 				yyerror("invalid probability: %lf", p);
29913b3a8eb9SGleb Smirnoff 				YYERROR;
29923b3a8eb9SGleb Smirnoff 			}
29933b3a8eb9SGleb Smirnoff 			filter_opts.prob = (u_int32_t)p;
29943b3a8eb9SGleb Smirnoff 			if (filter_opts.prob == 0)
29953b3a8eb9SGleb Smirnoff 				filter_opts.prob = 1;
29963b3a8eb9SGleb Smirnoff 		}
29973b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER				{
29983b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
29993b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
30003b3a8eb9SGleb Smirnoff 				YYERROR;
30013b3a8eb9SGleb Smirnoff 			}
30023b3a8eb9SGleb Smirnoff 			filter_opts.rtableid = $2;
30033b3a8eb9SGleb Smirnoff 		}
30043b3a8eb9SGleb Smirnoff 		| DIVERTTO portplain {
30053b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
30063b3a8eb9SGleb Smirnoff 			filter_opts.divert.port = $2.a;
30073b3a8eb9SGleb Smirnoff 			if (!filter_opts.divert.port) {
30083b3a8eb9SGleb Smirnoff 				yyerror("invalid divert port: %u", ntohs($2.a));
30093b3a8eb9SGleb Smirnoff 				YYERROR;
30103b3a8eb9SGleb Smirnoff 			}
30113b3a8eb9SGleb Smirnoff #endif
30123b3a8eb9SGleb Smirnoff 		}
30133b3a8eb9SGleb Smirnoff 		| DIVERTTO STRING PORT portplain {
30143b3a8eb9SGleb Smirnoff #ifndef __FreeBSD__
30153b3a8eb9SGleb Smirnoff 			if ((filter_opts.divert.addr = host($2)) == NULL) {
30163b3a8eb9SGleb Smirnoff 				yyerror("could not parse divert address: %s",
30173b3a8eb9SGleb Smirnoff 				    $2);
30183b3a8eb9SGleb Smirnoff 				free($2);
30193b3a8eb9SGleb Smirnoff 				YYERROR;
30203b3a8eb9SGleb Smirnoff 			}
30213b3a8eb9SGleb Smirnoff #else
30223b3a8eb9SGleb Smirnoff 			if ($2)
30233b3a8eb9SGleb Smirnoff #endif
30243b3a8eb9SGleb Smirnoff 			free($2);
30253b3a8eb9SGleb Smirnoff 			filter_opts.divert.port = $4.a;
30263b3a8eb9SGleb Smirnoff 			if (!filter_opts.divert.port) {
30273b3a8eb9SGleb Smirnoff 				yyerror("invalid divert port: %u", ntohs($4.a));
30283b3a8eb9SGleb Smirnoff 				YYERROR;
30293b3a8eb9SGleb Smirnoff 			}
30303b3a8eb9SGleb Smirnoff 		}
30313b3a8eb9SGleb Smirnoff 		| DIVERTREPLY {
30323b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
30333b3a8eb9SGleb Smirnoff 			yyerror("divert-reply has no meaning in FreeBSD pf(4)");
30343b3a8eb9SGleb Smirnoff 			YYERROR;
30353b3a8eb9SGleb Smirnoff #else
30363b3a8eb9SGleb Smirnoff 			filter_opts.divert.port = 1;	/* some random value */
30373b3a8eb9SGleb Smirnoff #endif
30383b3a8eb9SGleb Smirnoff 		}
303939282ef3SKajetan Staszkiewicz 		| SCRUB '(' scrub_opts ')' {
304039282ef3SKajetan Staszkiewicz 			filter_opts.nodf = $3.nodf;
304139282ef3SKajetan Staszkiewicz 			filter_opts.minttl = $3.minttl;
304239282ef3SKajetan Staszkiewicz 			if ($3.marker & FOM_SETTOS) {
304339282ef3SKajetan Staszkiewicz 				/* Old style rules are "scrub set-tos 0x42"
304439282ef3SKajetan Staszkiewicz 				 * New style are "set tos 0x42 scrub (...)"
304539282ef3SKajetan Staszkiewicz 				 * What is in "scrub(...)"" is unfortunately the
304639282ef3SKajetan Staszkiewicz 				 * original scrub syntax so it would overwrite
304739282ef3SKajetan Staszkiewicz 				 * "set tos" of a pass/match rule.
304839282ef3SKajetan Staszkiewicz 				 */
304939282ef3SKajetan Staszkiewicz 				filter_opts.settos = $3.settos;
305039282ef3SKajetan Staszkiewicz 			}
305139282ef3SKajetan Staszkiewicz 			filter_opts.randomid = $3.randomid;
305239282ef3SKajetan Staszkiewicz 			filter_opts.max_mss = $3.maxmss;
305339282ef3SKajetan Staszkiewicz 			if ($3.reassemble_tcp)
305439282ef3SKajetan Staszkiewicz 				filter_opts.marker |= FOM_SCRUB_TCP;
305539282ef3SKajetan Staszkiewicz 			filter_opts.marker |= $3.marker;
305639282ef3SKajetan Staszkiewicz 		}
3057aa69fdf1SKristof Provost 		| AFTO af FROM redirspec pool_opts {
3058aa69fdf1SKristof Provost 			if (filter_opts.nat.rdr) {
3059aa69fdf1SKristof Provost 				yyerror("cannot respecify af-to");
3060aa69fdf1SKristof Provost 				YYERROR;
3061aa69fdf1SKristof Provost 			}
3062aa69fdf1SKristof Provost 			if ($2 == 0) {
3063aa69fdf1SKristof Provost 				yyerror("no address family specified");
3064aa69fdf1SKristof Provost 				YYERROR;
3065aa69fdf1SKristof Provost 			}
3066aa69fdf1SKristof Provost 			if ($4->af && $4->af != $2) {
3067aa69fdf1SKristof Provost 				yyerror("af-to addresses must be in the "
3068aa69fdf1SKristof Provost 				   "target address family");
3069aa69fdf1SKristof Provost 				YYERROR;
3070aa69fdf1SKristof Provost 			}
3071aa69fdf1SKristof Provost 			filter_opts.nat.af = $2;
3072aa69fdf1SKristof Provost 			filter_opts.nat.rdr = calloc(1, sizeof(struct redirection));
3073aa69fdf1SKristof Provost 			if (filter_opts.nat.rdr == NULL)
3074aa69fdf1SKristof Provost 				err(1, "af-to: calloc");
3075aa69fdf1SKristof Provost 			filter_opts.nat.rdr->host = $4;
3076aa69fdf1SKristof Provost 			memcpy(&filter_opts.nat.pool_opts, &$5,
3077aa69fdf1SKristof Provost 			    sizeof(filter_opts.nat.pool_opts));
3078aa69fdf1SKristof Provost 			filter_opts.rdr.rdr =
3079aa69fdf1SKristof Provost 			    calloc(1, sizeof(struct redirection));
3080aa69fdf1SKristof Provost 			bzero(&filter_opts.rdr.pool_opts,
3081aa69fdf1SKristof Provost 			    sizeof(filter_opts.rdr.pool_opts));
3082aa69fdf1SKristof Provost 			filter_opts.marker |= FOM_AFTO;
3083aa69fdf1SKristof Provost 		}
3084aa69fdf1SKristof Provost 		| AFTO af FROM redirspec pool_opts TO redirspec pool_opts {
3085aa69fdf1SKristof Provost 			if (filter_opts.nat.rdr) {
3086aa69fdf1SKristof Provost 				yyerror("cannot respecify af-to");
3087aa69fdf1SKristof Provost 				YYERROR;
3088aa69fdf1SKristof Provost 			}
3089aa69fdf1SKristof Provost 			if ($2 == 0) {
3090aa69fdf1SKristof Provost 				yyerror("no address family specified");
3091aa69fdf1SKristof Provost 				YYERROR;
3092aa69fdf1SKristof Provost 			}
3093aa69fdf1SKristof Provost 				if (($4->af && $4->af != $2) ||
3094aa69fdf1SKristof Provost 				($7->af && $7->af != $2)) {
3095aa69fdf1SKristof Provost 				yyerror("af-to addresses must be in the "
3096aa69fdf1SKristof Provost 				   "target address family");
3097aa69fdf1SKristof Provost 				YYERROR;
3098aa69fdf1SKristof Provost 			}
3099aa69fdf1SKristof Provost 			filter_opts.nat.af = $2;
3100aa69fdf1SKristof Provost 			filter_opts.nat.rdr = calloc(1, sizeof(struct redirection));
3101aa69fdf1SKristof Provost 			if (filter_opts.nat.rdr == NULL)
3102aa69fdf1SKristof Provost 				err(1, "af-to: calloc");
3103aa69fdf1SKristof Provost 			filter_opts.nat.rdr->host = $4;
3104aa69fdf1SKristof Provost 			memcpy(&filter_opts.nat.pool_opts, &$5,
3105aa69fdf1SKristof Provost 			    sizeof(filter_opts.nat.pool_opts));
3106aa69fdf1SKristof Provost 			filter_opts.rdr.af = $2;
3107aa69fdf1SKristof Provost 			filter_opts.rdr.rdr = calloc(1, sizeof(struct redirection));
3108aa69fdf1SKristof Provost 			if (filter_opts.rdr.rdr == NULL)
3109aa69fdf1SKristof Provost 				err(1, "af-to: calloc");
3110aa69fdf1SKristof Provost 			filter_opts.rdr.rdr->host = $7;
3111aa69fdf1SKristof Provost 			memcpy(&filter_opts.nat.pool_opts, &$8,
3112aa69fdf1SKristof Provost 			    sizeof(filter_opts.nat.pool_opts));
3113aa69fdf1SKristof Provost 			filter_opts.marker |= FOM_AFTO;
3114aa69fdf1SKristof Provost 		}
31153e248e0fSKristof Provost 		| filter_sets
31163e248e0fSKristof Provost 		;
31173e248e0fSKristof Provost 
31183e248e0fSKristof Provost filter_sets	: SET '(' filter_sets_l ')'	{ $$ = filter_opts; }
31193e248e0fSKristof Provost 		| SET filter_set		{ $$ = filter_opts; }
31203e248e0fSKristof Provost 		;
31213e248e0fSKristof Provost 
31223e248e0fSKristof Provost filter_sets_l	: filter_sets_l comma filter_set
31233e248e0fSKristof Provost 		| filter_set
31243e248e0fSKristof Provost 		;
31253e248e0fSKristof Provost 
31263e248e0fSKristof Provost filter_set	: prio {
31273e248e0fSKristof Provost 			if (filter_opts.marker & FOM_SETPRIO) {
31283e248e0fSKristof Provost 				yyerror("prio cannot be redefined");
31293e248e0fSKristof Provost 				YYERROR;
31303e248e0fSKristof Provost 			}
31313e248e0fSKristof Provost 			filter_opts.marker |= FOM_SETPRIO;
31323e248e0fSKristof Provost 			filter_opts.set_prio[0] = $1.b1;
31333e248e0fSKristof Provost 			filter_opts.set_prio[1] = $1.b2;
31343e248e0fSKristof Provost 		}
313539282ef3SKajetan Staszkiewicz 		| TOS tos {
313639282ef3SKajetan Staszkiewicz 			if (filter_opts.marker & FOM_SETTOS) {
313739282ef3SKajetan Staszkiewicz 				yyerror("tos cannot be respecified");
313839282ef3SKajetan Staszkiewicz 				YYERROR;
313939282ef3SKajetan Staszkiewicz 			}
314039282ef3SKajetan Staszkiewicz 			filter_opts.marker |= FOM_SETTOS;
314139282ef3SKajetan Staszkiewicz 			filter_opts.settos = $2;
314239282ef3SKajetan Staszkiewicz 		}
31433e248e0fSKristof Provost prio		: PRIO NUMBER {
31443e248e0fSKristof Provost 			if ($2 < 0 || $2 > PF_PRIO_MAX) {
31453e248e0fSKristof Provost 				yyerror("prio must be 0 - %u", PF_PRIO_MAX);
31463e248e0fSKristof Provost 				YYERROR;
31473e248e0fSKristof Provost 			}
31483e248e0fSKristof Provost 			$$.b1 = $$.b2 = $2;
31493e248e0fSKristof Provost 		}
31503e248e0fSKristof Provost 		| PRIO '(' NUMBER comma NUMBER ')' {
31513e248e0fSKristof Provost 			if ($3 < 0 || $3 > PF_PRIO_MAX ||
31523e248e0fSKristof Provost 			    $5 < 0 || $5 > PF_PRIO_MAX) {
31533e248e0fSKristof Provost 				yyerror("prio must be 0 - %u", PF_PRIO_MAX);
31543e248e0fSKristof Provost 				YYERROR;
31553e248e0fSKristof Provost 			}
31563e248e0fSKristof Provost 			$$.b1 = $3;
31573e248e0fSKristof Provost 			$$.b2 = $5;
31583e248e0fSKristof Provost 		}
31593b3a8eb9SGleb Smirnoff 		;
31603b3a8eb9SGleb Smirnoff 
31613b3a8eb9SGleb Smirnoff probability	: STRING				{
31623b3a8eb9SGleb Smirnoff 			char	*e;
31633b3a8eb9SGleb Smirnoff 			double	 p = strtod($1, &e);
31643b3a8eb9SGleb Smirnoff 
31653b3a8eb9SGleb Smirnoff 			if (*e == '%') {
31663b3a8eb9SGleb Smirnoff 				p *= 0.01;
31673b3a8eb9SGleb Smirnoff 				e++;
31683b3a8eb9SGleb Smirnoff 			}
31693b3a8eb9SGleb Smirnoff 			if (*e) {
31703b3a8eb9SGleb Smirnoff 				yyerror("invalid probability: %s", $1);
31713b3a8eb9SGleb Smirnoff 				free($1);
31723b3a8eb9SGleb Smirnoff 				YYERROR;
31733b3a8eb9SGleb Smirnoff 			}
31743b3a8eb9SGleb Smirnoff 			free($1);
31753b3a8eb9SGleb Smirnoff 			$$ = p;
31763b3a8eb9SGleb Smirnoff 		}
31773b3a8eb9SGleb Smirnoff 		| NUMBER				{
31783b3a8eb9SGleb Smirnoff 			$$ = (double)$1;
31793b3a8eb9SGleb Smirnoff 		}
31803b3a8eb9SGleb Smirnoff 		;
31813b3a8eb9SGleb Smirnoff 
31823b3a8eb9SGleb Smirnoff 
3183150182e3SKristof Provost action		: PASS 			{
3184150182e3SKristof Provost 			$$.b1 = PF_PASS;
3185150182e3SKristof Provost 			$$.b2 = failpolicy;
3186150182e3SKristof Provost 			$$.w = returnicmpdefault;
3187150182e3SKristof Provost 			$$.w2 = returnicmp6default;
3188150182e3SKristof Provost 		}
3189ef950daaSKristof Provost 		| MATCH			{ $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; }
31903b3a8eb9SGleb Smirnoff 		| BLOCK blockspec	{ $$ = $2; $$.b1 = PF_DROP; }
31913b3a8eb9SGleb Smirnoff 		;
31923b3a8eb9SGleb Smirnoff 
31933b3a8eb9SGleb Smirnoff blockspec	: /* empty */		{
31943b3a8eb9SGleb Smirnoff 			$$.b2 = blockpolicy;
31953b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
31963b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
31973b3a8eb9SGleb Smirnoff 		}
31983b3a8eb9SGleb Smirnoff 		| DROP			{
31993b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_DROP;
32003b3a8eb9SGleb Smirnoff 			$$.w = 0;
32013b3a8eb9SGleb Smirnoff 			$$.w2 = 0;
32023b3a8eb9SGleb Smirnoff 		}
32033b3a8eb9SGleb Smirnoff 		| RETURNRST		{
32043b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNRST;
32053b3a8eb9SGleb Smirnoff 			$$.w = 0;
32063b3a8eb9SGleb Smirnoff 			$$.w2 = 0;
32073b3a8eb9SGleb Smirnoff 		}
32083b3a8eb9SGleb Smirnoff 		| RETURNRST '(' TTL NUMBER ')'	{
32093b3a8eb9SGleb Smirnoff 			if ($4 < 0 || $4 > 255) {
32103b3a8eb9SGleb Smirnoff 				yyerror("illegal ttl value %d", $4);
32113b3a8eb9SGleb Smirnoff 				YYERROR;
32123b3a8eb9SGleb Smirnoff 			}
32133b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNRST;
32143b3a8eb9SGleb Smirnoff 			$$.w = $4;
32153b3a8eb9SGleb Smirnoff 			$$.w2 = 0;
32163b3a8eb9SGleb Smirnoff 		}
32173b3a8eb9SGleb Smirnoff 		| RETURNICMP		{
32183b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
32193b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
32203b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
32213b3a8eb9SGleb Smirnoff 		}
32223b3a8eb9SGleb Smirnoff 		| RETURNICMP6		{
32233b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
32243b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
32253b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
32263b3a8eb9SGleb Smirnoff 		}
32273b3a8eb9SGleb Smirnoff 		| RETURNICMP '(' reticmpspec ')'	{
32283b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
32293b3a8eb9SGleb Smirnoff 			$$.w = $3;
32303b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmpdefault;
32313b3a8eb9SGleb Smirnoff 		}
32323b3a8eb9SGleb Smirnoff 		| RETURNICMP6 '(' reticmp6spec ')'	{
32333b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
32343b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
32353b3a8eb9SGleb Smirnoff 			$$.w2 = $3;
32363b3a8eb9SGleb Smirnoff 		}
32373b3a8eb9SGleb Smirnoff 		| RETURNICMP '(' reticmpspec comma reticmp6spec ')' {
32383b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURNICMP;
32393b3a8eb9SGleb Smirnoff 			$$.w = $3;
32403b3a8eb9SGleb Smirnoff 			$$.w2 = $5;
32413b3a8eb9SGleb Smirnoff 		}
32423b3a8eb9SGleb Smirnoff 		| RETURN {
32433b3a8eb9SGleb Smirnoff 			$$.b2 = PFRULE_RETURN;
32443b3a8eb9SGleb Smirnoff 			$$.w = returnicmpdefault;
32453b3a8eb9SGleb Smirnoff 			$$.w2 = returnicmp6default;
32463b3a8eb9SGleb Smirnoff 		}
32473b3a8eb9SGleb Smirnoff 		;
32483b3a8eb9SGleb Smirnoff 
32493b3a8eb9SGleb Smirnoff reticmpspec	: STRING			{
32503b3a8eb9SGleb Smirnoff 			if (!($$ = parseicmpspec($1, AF_INET))) {
32513b3a8eb9SGleb Smirnoff 				free($1);
32523b3a8eb9SGleb Smirnoff 				YYERROR;
32533b3a8eb9SGleb Smirnoff 			}
32543b3a8eb9SGleb Smirnoff 			free($1);
32553b3a8eb9SGleb Smirnoff 		}
32563b3a8eb9SGleb Smirnoff 		| NUMBER			{
32573b3a8eb9SGleb Smirnoff 			u_int8_t		icmptype;
32583b3a8eb9SGleb Smirnoff 
32593b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
32603b3a8eb9SGleb Smirnoff 				yyerror("invalid icmp code %lu", $1);
32613b3a8eb9SGleb Smirnoff 				YYERROR;
32623b3a8eb9SGleb Smirnoff 			}
32633b3a8eb9SGleb Smirnoff 			icmptype = returnicmpdefault >> 8;
32643b3a8eb9SGleb Smirnoff 			$$ = (icmptype << 8 | $1);
32653b3a8eb9SGleb Smirnoff 		}
32663b3a8eb9SGleb Smirnoff 		;
32673b3a8eb9SGleb Smirnoff 
32683b3a8eb9SGleb Smirnoff reticmp6spec	: STRING			{
32693b3a8eb9SGleb Smirnoff 			if (!($$ = parseicmpspec($1, AF_INET6))) {
32703b3a8eb9SGleb Smirnoff 				free($1);
32713b3a8eb9SGleb Smirnoff 				YYERROR;
32723b3a8eb9SGleb Smirnoff 			}
32733b3a8eb9SGleb Smirnoff 			free($1);
32743b3a8eb9SGleb Smirnoff 		}
32753b3a8eb9SGleb Smirnoff 		| NUMBER			{
32763b3a8eb9SGleb Smirnoff 			u_int8_t		icmptype;
32773b3a8eb9SGleb Smirnoff 
32783b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
32793b3a8eb9SGleb Smirnoff 				yyerror("invalid icmp code %lu", $1);
32803b3a8eb9SGleb Smirnoff 				YYERROR;
32813b3a8eb9SGleb Smirnoff 			}
32823b3a8eb9SGleb Smirnoff 			icmptype = returnicmp6default >> 8;
32833b3a8eb9SGleb Smirnoff 			$$ = (icmptype << 8 | $1);
32843b3a8eb9SGleb Smirnoff 		}
32853b3a8eb9SGleb Smirnoff 		;
32863b3a8eb9SGleb Smirnoff 
32873b3a8eb9SGleb Smirnoff dir		: /* empty */			{ $$ = PF_INOUT; }
32883b3a8eb9SGleb Smirnoff 		| IN				{ $$ = PF_IN; }
32893b3a8eb9SGleb Smirnoff 		| OUT				{ $$ = PF_OUT; }
32903b3a8eb9SGleb Smirnoff 		;
32913b3a8eb9SGleb Smirnoff 
32923b3a8eb9SGleb Smirnoff quick		: /* empty */			{ $$.quick = 0; }
32933b3a8eb9SGleb Smirnoff 		| QUICK				{ $$.quick = 1; }
32943b3a8eb9SGleb Smirnoff 		;
32953b3a8eb9SGleb Smirnoff 
32963b3a8eb9SGleb Smirnoff logquick	: /* empty */	{ $$.log = 0; $$.quick = 0; $$.logif = 0; }
32973b3a8eb9SGleb Smirnoff 		| log		{ $$ = $1; $$.quick = 0; }
32983b3a8eb9SGleb Smirnoff 		| QUICK		{ $$.quick = 1; $$.log = 0; $$.logif = 0; }
32993b3a8eb9SGleb Smirnoff 		| log QUICK	{ $$ = $1; $$.quick = 1; }
33003b3a8eb9SGleb Smirnoff 		| QUICK log	{ $$ = $2; $$.quick = 1; }
33013b3a8eb9SGleb Smirnoff 		;
33023b3a8eb9SGleb Smirnoff 
33033b3a8eb9SGleb Smirnoff log		: LOG			{ $$.log = PF_LOG; $$.logif = 0; }
33043b3a8eb9SGleb Smirnoff 		| LOG '(' logopts ')'	{
33053b3a8eb9SGleb Smirnoff 			$$.log = PF_LOG | $3.log;
33063b3a8eb9SGleb Smirnoff 			$$.logif = $3.logif;
33073b3a8eb9SGleb Smirnoff 		}
33083b3a8eb9SGleb Smirnoff 		;
33093b3a8eb9SGleb Smirnoff 
33103b3a8eb9SGleb Smirnoff logopts		: logopt			{ $$ = $1; }
33113b3a8eb9SGleb Smirnoff 		| logopts comma logopt		{
33123b3a8eb9SGleb Smirnoff 			$$.log = $1.log | $3.log;
33133b3a8eb9SGleb Smirnoff 			$$.logif = $3.logif;
33143b3a8eb9SGleb Smirnoff 			if ($$.logif == 0)
33153b3a8eb9SGleb Smirnoff 				$$.logif = $1.logif;
33163b3a8eb9SGleb Smirnoff 		}
33173b3a8eb9SGleb Smirnoff 		;
33183b3a8eb9SGleb Smirnoff 
33193b3a8eb9SGleb Smirnoff logopt		: ALL		{ $$.log = PF_LOG_ALL; $$.logif = 0; }
3320f3ab00c2SKristof Provost 		| MATCHES		{ $$.log = PF_LOG_MATCHES; $$.logif = 0; }
33213b3a8eb9SGleb Smirnoff 		| USER		{ $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
33223b3a8eb9SGleb Smirnoff 		| GROUP		{ $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
33233b3a8eb9SGleb Smirnoff 		| TO string	{
33243b3a8eb9SGleb Smirnoff 			const char	*errstr;
33253b3a8eb9SGleb Smirnoff 			u_int		 i;
33263b3a8eb9SGleb Smirnoff 
33273b3a8eb9SGleb Smirnoff 			$$.log = 0;
33283b3a8eb9SGleb Smirnoff 			if (strncmp($2, "pflog", 5)) {
33293b3a8eb9SGleb Smirnoff 				yyerror("%s: should be a pflog interface", $2);
33303b3a8eb9SGleb Smirnoff 				free($2);
33313b3a8eb9SGleb Smirnoff 				YYERROR;
33323b3a8eb9SGleb Smirnoff 			}
33333b3a8eb9SGleb Smirnoff 			i = strtonum($2 + 5, 0, 255, &errstr);
33343b3a8eb9SGleb Smirnoff 			if (errstr) {
33353b3a8eb9SGleb Smirnoff 				yyerror("%s: %s", $2, errstr);
33363b3a8eb9SGleb Smirnoff 				free($2);
33373b3a8eb9SGleb Smirnoff 				YYERROR;
33383b3a8eb9SGleb Smirnoff 			}
33393b3a8eb9SGleb Smirnoff 			free($2);
33403b3a8eb9SGleb Smirnoff 			$$.logif = i;
33413b3a8eb9SGleb Smirnoff 		}
33423b3a8eb9SGleb Smirnoff 		;
33433b3a8eb9SGleb Smirnoff 
33443b3a8eb9SGleb Smirnoff interface	: /* empty */			{ $$ = NULL; }
33453b3a8eb9SGleb Smirnoff 		| ON if_item_not		{ $$ = $2; }
33463b3a8eb9SGleb Smirnoff 		| ON '{' optnl if_list '}'	{ $$ = $4; }
33473b3a8eb9SGleb Smirnoff 		;
33483b3a8eb9SGleb Smirnoff 
33493b3a8eb9SGleb Smirnoff if_list		: if_item_not optnl		{ $$ = $1; }
33503b3a8eb9SGleb Smirnoff 		| if_list comma if_item_not optnl	{
33513b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
33523b3a8eb9SGleb Smirnoff 			$1->tail = $3;
33533b3a8eb9SGleb Smirnoff 			$$ = $1;
33543b3a8eb9SGleb Smirnoff 		}
33553b3a8eb9SGleb Smirnoff 		;
33563b3a8eb9SGleb Smirnoff 
33573b3a8eb9SGleb Smirnoff if_item_not	: not if_item			{ $$ = $2; $$->not = $1; }
33583b3a8eb9SGleb Smirnoff 		;
33593b3a8eb9SGleb Smirnoff 
33603b3a8eb9SGleb Smirnoff if_item		: STRING			{
33613b3a8eb9SGleb Smirnoff 			struct node_host	*n;
33623b3a8eb9SGleb Smirnoff 
33633b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_if));
33643b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
33653b3a8eb9SGleb Smirnoff 				err(1, "if_item: calloc");
33663b3a8eb9SGleb Smirnoff 			if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
33673b3a8eb9SGleb Smirnoff 			    sizeof($$->ifname)) {
33683b3a8eb9SGleb Smirnoff 				free($1);
33693b3a8eb9SGleb Smirnoff 				free($$);
33703b3a8eb9SGleb Smirnoff 				yyerror("interface name too long");
33713b3a8eb9SGleb Smirnoff 				YYERROR;
33723b3a8eb9SGleb Smirnoff 			}
33733b3a8eb9SGleb Smirnoff 
33743b3a8eb9SGleb Smirnoff 			if ((n = ifa_exists($1)) != NULL)
33753b3a8eb9SGleb Smirnoff 				$$->ifa_flags = n->ifa_flags;
33763b3a8eb9SGleb Smirnoff 
33773b3a8eb9SGleb Smirnoff 			free($1);
33783b3a8eb9SGleb Smirnoff 			$$->not = 0;
33793b3a8eb9SGleb Smirnoff 			$$->next = NULL;
33803b3a8eb9SGleb Smirnoff 			$$->tail = $$;
33813b3a8eb9SGleb Smirnoff 		}
33823b3a8eb9SGleb Smirnoff 		;
33833b3a8eb9SGleb Smirnoff 
33843b3a8eb9SGleb Smirnoff af		: /* empty */			{ $$ = 0; }
33853b3a8eb9SGleb Smirnoff 		| INET				{ $$ = AF_INET; }
33863b3a8eb9SGleb Smirnoff 		| INET6				{ $$ = AF_INET6; }
33873b3a8eb9SGleb Smirnoff 		;
33883b3a8eb9SGleb Smirnoff 
33892b29ceb8SKristof Provost etherproto	: /* empty */				{ $$ = NULL; }
33902b29ceb8SKristof Provost 		| PROTO etherproto_item			{ $$ = $2; }
33912b29ceb8SKristof Provost 		| PROTO '{' optnl etherproto_list '}'	{ $$ = $4; }
33922b29ceb8SKristof Provost 		;
33932b29ceb8SKristof Provost 
33942b29ceb8SKristof Provost etherproto_list	: etherproto_item optnl			{ $$ = $1; }
33952b29ceb8SKristof Provost 		| etherproto_list comma etherproto_item optnl	{
33962b29ceb8SKristof Provost 			$1->tail->next = $3;
33972b29ceb8SKristof Provost 			$1->tail = $3;
33982b29ceb8SKristof Provost 			$$ = $1;
33992b29ceb8SKristof Provost 		}
34002b29ceb8SKristof Provost 		;
34012b29ceb8SKristof Provost 
34022b29ceb8SKristof Provost etherproto_item	: etherprotoval		{
34032b29ceb8SKristof Provost 			u_int16_t	pr;
34042b29ceb8SKristof Provost 
34052b29ceb8SKristof Provost 			pr = (u_int16_t)$1;
34062b29ceb8SKristof Provost 			if (pr == 0) {
34072b29ceb8SKristof Provost 				yyerror("proto 0 cannot be used");
34082b29ceb8SKristof Provost 				YYERROR;
34092b29ceb8SKristof Provost 			}
34102b29ceb8SKristof Provost 			$$ = calloc(1, sizeof(struct node_proto));
34112b29ceb8SKristof Provost 			if ($$ == NULL)
34122b29ceb8SKristof Provost 				err(1, "proto_item: calloc");
34132b29ceb8SKristof Provost 			$$->proto = pr;
34142b29ceb8SKristof Provost 			$$->next = NULL;
34152b29ceb8SKristof Provost 			$$->tail = $$;
34162b29ceb8SKristof Provost 		}
34172b29ceb8SKristof Provost 		;
34182b29ceb8SKristof Provost 
34192b29ceb8SKristof Provost etherprotoval	: NUMBER			{
34202b29ceb8SKristof Provost 			if ($1 < 0 || $1 > 65565) {
34212b29ceb8SKristof Provost 				yyerror("protocol outside range");
34222b29ceb8SKristof Provost 				YYERROR;
34232b29ceb8SKristof Provost 			}
34242b29ceb8SKristof Provost 		}
34252b29ceb8SKristof Provost 		| STRING
34262b29ceb8SKristof Provost 		{
34272b29ceb8SKristof Provost 			if (!strncmp($1, "0x", 2)) {
34282b29ceb8SKristof Provost 				if (sscanf($1, "0x%4x", &$$) != 1) {
34292b29ceb8SKristof Provost 					free($1);
34302b29ceb8SKristof Provost 					yyerror("invalid EtherType hex");
34312b29ceb8SKristof Provost 					YYERROR;
34322b29ceb8SKristof Provost 				}
34332b29ceb8SKristof Provost 			} else {
34342b29ceb8SKristof Provost 				yyerror("Symbolic EtherType not yet supported");
34352b29ceb8SKristof Provost 			}
34362b29ceb8SKristof Provost 		}
34372b29ceb8SKristof Provost 		;
34382b29ceb8SKristof Provost 
34393b3a8eb9SGleb Smirnoff proto		: /* empty */				{ $$ = NULL; }
34403b3a8eb9SGleb Smirnoff 		| PROTO proto_item			{ $$ = $2; }
34413b3a8eb9SGleb Smirnoff 		| PROTO '{' optnl proto_list '}'	{ $$ = $4; }
34423b3a8eb9SGleb Smirnoff 		;
34433b3a8eb9SGleb Smirnoff 
34443b3a8eb9SGleb Smirnoff proto_list	: proto_item optnl		{ $$ = $1; }
34453b3a8eb9SGleb Smirnoff 		| proto_list comma proto_item optnl	{
34463b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
34473b3a8eb9SGleb Smirnoff 			$1->tail = $3;
34483b3a8eb9SGleb Smirnoff 			$$ = $1;
34493b3a8eb9SGleb Smirnoff 		}
34503b3a8eb9SGleb Smirnoff 		;
34513b3a8eb9SGleb Smirnoff 
34523b3a8eb9SGleb Smirnoff proto_item	: protoval			{
34533b3a8eb9SGleb Smirnoff 			u_int8_t	pr;
34543b3a8eb9SGleb Smirnoff 
34553b3a8eb9SGleb Smirnoff 			pr = (u_int8_t)$1;
34563b3a8eb9SGleb Smirnoff 			if (pr == 0) {
34573b3a8eb9SGleb Smirnoff 				yyerror("proto 0 cannot be used");
34583b3a8eb9SGleb Smirnoff 				YYERROR;
34593b3a8eb9SGleb Smirnoff 			}
34603b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_proto));
34613b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
34623b3a8eb9SGleb Smirnoff 				err(1, "proto_item: calloc");
34633b3a8eb9SGleb Smirnoff 			$$->proto = pr;
34643b3a8eb9SGleb Smirnoff 			$$->next = NULL;
34653b3a8eb9SGleb Smirnoff 			$$->tail = $$;
34663b3a8eb9SGleb Smirnoff 		}
34673b3a8eb9SGleb Smirnoff 		;
34683b3a8eb9SGleb Smirnoff 
34693b3a8eb9SGleb Smirnoff protoval	: STRING			{
34703b3a8eb9SGleb Smirnoff 			struct protoent	*p;
34713b3a8eb9SGleb Smirnoff 
34723b3a8eb9SGleb Smirnoff 			p = getprotobyname($1);
34733b3a8eb9SGleb Smirnoff 			if (p == NULL) {
34743b3a8eb9SGleb Smirnoff 				yyerror("unknown protocol %s", $1);
34753b3a8eb9SGleb Smirnoff 				free($1);
34763b3a8eb9SGleb Smirnoff 				YYERROR;
34773b3a8eb9SGleb Smirnoff 			}
34783b3a8eb9SGleb Smirnoff 			$$ = p->p_proto;
34793b3a8eb9SGleb Smirnoff 			free($1);
34803b3a8eb9SGleb Smirnoff 		}
34813b3a8eb9SGleb Smirnoff 		| NUMBER			{
34823b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
34833b3a8eb9SGleb Smirnoff 				yyerror("protocol outside range");
34843b3a8eb9SGleb Smirnoff 				YYERROR;
34853b3a8eb9SGleb Smirnoff 			}
34863b3a8eb9SGleb Smirnoff 		}
34873b3a8eb9SGleb Smirnoff 		;
34883b3a8eb9SGleb Smirnoff 
34898a42005dSKristof Provost l3fromto	: /* empty */			{
34908a42005dSKristof Provost 			bzero(&$$, sizeof($$));
34918a42005dSKristof Provost 		}
34928a42005dSKristof Provost 		| L3 fromto			{
34933468cd95SKristof Provost 			if ($2.src.host != NULL &&
3494812839e5SKristof Provost 			    $2.src.host->addr.type != PF_ADDR_ADDRMASK &&
3495812839e5SKristof Provost 			    $2.src.host->addr.type != PF_ADDR_TABLE) {
3496812839e5SKristof Provost 				yyerror("from must be an address or table");
34973468cd95SKristof Provost 				YYERROR;
34983468cd95SKristof Provost 			}
34993468cd95SKristof Provost 			if ($2.dst.host != NULL &&
3500812839e5SKristof Provost 			    $2.dst.host->addr.type != PF_ADDR_ADDRMASK &&
3501812839e5SKristof Provost 			    $2.dst.host->addr.type != PF_ADDR_TABLE) {
3502812839e5SKristof Provost 				yyerror("to must be an address or table");
35033468cd95SKristof Provost 				YYERROR;
35043468cd95SKristof Provost 			}
35058a42005dSKristof Provost 			$$ = $2;
35068a42005dSKristof Provost 		}
35078a42005dSKristof Provost 		;
35082b29ceb8SKristof Provost etherfromto	: ALL				{
350987a89d6eSKristof Provost 			$$.src = NULL;
351087a89d6eSKristof Provost 			$$.dst = NULL;
35112b29ceb8SKristof Provost 		}
35122b29ceb8SKristof Provost 		| etherfrom etherto		{
351387a89d6eSKristof Provost 			$$.src = $1.mac;
351487a89d6eSKristof Provost 			$$.dst = $2.mac;
35152b29ceb8SKristof Provost 		}
35162b29ceb8SKristof Provost 		;
35172b29ceb8SKristof Provost 
35182b29ceb8SKristof Provost etherfrom	: /* emtpy */			{
35192b29ceb8SKristof Provost 			bzero(&$$, sizeof($$));
35202b29ceb8SKristof Provost 		}
352187a89d6eSKristof Provost 		| FROM macspec			{
352287a89d6eSKristof Provost 			$$.mac = $2;
35232b29ceb8SKristof Provost 		}
35242b29ceb8SKristof Provost 		;
35252b29ceb8SKristof Provost 
35262b29ceb8SKristof Provost etherto		: /* empty */			{
35272b29ceb8SKristof Provost 			bzero(&$$, sizeof($$));
35282b29ceb8SKristof Provost 		}
352987a89d6eSKristof Provost 		| TO macspec			{
353087a89d6eSKristof Provost 			$$.mac = $2;
35312b29ceb8SKristof Provost 		}
35322b29ceb8SKristof Provost 		;
35332b29ceb8SKristof Provost 
3534b590f17aSKristof Provost mac		: string '/' NUMBER		{
3535b590f17aSKristof Provost 			$$ = node_mac_from_string_masklen($1, $3);
35362b29ceb8SKristof Provost 			free($1);
3537b590f17aSKristof Provost 			if ($$ == NULL)
35382b29ceb8SKristof Provost 				YYERROR;
35392b29ceb8SKristof Provost 		}
3540b590f17aSKristof Provost 		| string			{
3541b590f17aSKristof Provost 			if (strchr($1, '&')) {
3542b590f17aSKristof Provost 				/* mac&mask */
3543b590f17aSKristof Provost 				char *mac = strtok($1, "&");
3544b590f17aSKristof Provost 				char *mask = strtok(NULL, "&");
3545b590f17aSKristof Provost 				$$ = node_mac_from_string_mask(mac, mask);
3546b590f17aSKristof Provost 			} else {
3547b590f17aSKristof Provost 				$$ = node_mac_from_string($1);
3548b590f17aSKristof Provost 			}
354987a89d6eSKristof Provost 			free($1);
3550b590f17aSKristof Provost 			if ($$ == NULL)
3551b590f17aSKristof Provost 				YYERROR;
3552b590f17aSKristof Provost 
355387a89d6eSKristof Provost 		}
355487a89d6eSKristof Provost xmac		: not mac {
355587a89d6eSKristof Provost 			struct node_mac	*n;
355687a89d6eSKristof Provost 
355787a89d6eSKristof Provost 			for (n = $2; n != NULL; n = n->next)
355887a89d6eSKristof Provost 				n->neg = $1;
355987a89d6eSKristof Provost 			$$ = $2;
35602b29ceb8SKristof Provost 		}
35612b29ceb8SKristof Provost 		;
356287a89d6eSKristof Provost macspec		: xmac {
356387a89d6eSKristof Provost 			$$ = $1;
356487a89d6eSKristof Provost 		}
356587a89d6eSKristof Provost 		| '{' optnl mac_list '}'
356687a89d6eSKristof Provost 		{
356787a89d6eSKristof Provost 			$$ = $3;
356887a89d6eSKristof Provost 		}
356987a89d6eSKristof Provost 		;
357087a89d6eSKristof Provost mac_list	: xmac optnl {
357187a89d6eSKristof Provost 			$$ = $1;
357287a89d6eSKristof Provost 		}
357387a89d6eSKristof Provost 		| mac_list comma xmac {
357487a89d6eSKristof Provost 			if ($3 == NULL)
357587a89d6eSKristof Provost 				$$ = $1;
357687a89d6eSKristof Provost 			else if ($1 == NULL)
357787a89d6eSKristof Provost 				$$ = $3;
357887a89d6eSKristof Provost 			else {
357987a89d6eSKristof Provost 				$1->tail->next = $3;
358087a89d6eSKristof Provost 				$1->tail = $3->tail;
358187a89d6eSKristof Provost 				$$ = $1;
358287a89d6eSKristof Provost 			}
358387a89d6eSKristof Provost 		}
35842b29ceb8SKristof Provost 
35853b3a8eb9SGleb Smirnoff fromto		: ALL				{
35863b3a8eb9SGleb Smirnoff 			$$.src.host = NULL;
35873b3a8eb9SGleb Smirnoff 			$$.src.port = NULL;
35883b3a8eb9SGleb Smirnoff 			$$.dst.host = NULL;
35893b3a8eb9SGleb Smirnoff 			$$.dst.port = NULL;
35903b3a8eb9SGleb Smirnoff 			$$.src_os = NULL;
35913b3a8eb9SGleb Smirnoff 		}
35923b3a8eb9SGleb Smirnoff 		| from os to			{
35933b3a8eb9SGleb Smirnoff 			$$.src = $1;
35943b3a8eb9SGleb Smirnoff 			$$.src_os = $2;
35953b3a8eb9SGleb Smirnoff 			$$.dst = $3;
35963b3a8eb9SGleb Smirnoff 		}
35973b3a8eb9SGleb Smirnoff 		;
35983b3a8eb9SGleb Smirnoff 
35993b3a8eb9SGleb Smirnoff os		: /* empty */			{ $$ = NULL; }
36003b3a8eb9SGleb Smirnoff 		| OS xos			{ $$ = $2; }
36013b3a8eb9SGleb Smirnoff 		| OS '{' optnl os_list '}'	{ $$ = $4; }
36023b3a8eb9SGleb Smirnoff 		;
36033b3a8eb9SGleb Smirnoff 
36043b3a8eb9SGleb Smirnoff xos		: STRING {
36053b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_os));
36063b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36073b3a8eb9SGleb Smirnoff 				err(1, "os: calloc");
36083b3a8eb9SGleb Smirnoff 			$$->os = $1;
36093b3a8eb9SGleb Smirnoff 			$$->tail = $$;
36103b3a8eb9SGleb Smirnoff 		}
36113b3a8eb9SGleb Smirnoff 		;
36123b3a8eb9SGleb Smirnoff 
36133b3a8eb9SGleb Smirnoff os_list		: xos optnl 			{ $$ = $1; }
36143b3a8eb9SGleb Smirnoff 		| os_list comma xos optnl	{
36153b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
36163b3a8eb9SGleb Smirnoff 			$1->tail = $3;
36173b3a8eb9SGleb Smirnoff 			$$ = $1;
36183b3a8eb9SGleb Smirnoff 		}
36193b3a8eb9SGleb Smirnoff 		;
36203b3a8eb9SGleb Smirnoff 
36213b3a8eb9SGleb Smirnoff from		: /* empty */			{
36223b3a8eb9SGleb Smirnoff 			$$.host = NULL;
36233b3a8eb9SGleb Smirnoff 			$$.port = NULL;
36243b3a8eb9SGleb Smirnoff 		}
36253b3a8eb9SGleb Smirnoff 		| FROM ipportspec		{
36263b3a8eb9SGleb Smirnoff 			$$ = $2;
36273b3a8eb9SGleb Smirnoff 		}
36283b3a8eb9SGleb Smirnoff 		;
36293b3a8eb9SGleb Smirnoff 
36303b3a8eb9SGleb Smirnoff to		: /* empty */			{
36313b3a8eb9SGleb Smirnoff 			$$.host = NULL;
36323b3a8eb9SGleb Smirnoff 			$$.port = NULL;
36333b3a8eb9SGleb Smirnoff 		}
36343b3a8eb9SGleb Smirnoff 		| TO ipportspec		{
36353b3a8eb9SGleb Smirnoff 			if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
36363b3a8eb9SGleb Smirnoff 			    "not permitted in a destination address"))
36373b3a8eb9SGleb Smirnoff 				YYERROR;
36383b3a8eb9SGleb Smirnoff 			$$ = $2;
36393b3a8eb9SGleb Smirnoff 		}
36403b3a8eb9SGleb Smirnoff 		;
36413b3a8eb9SGleb Smirnoff 
36423b3a8eb9SGleb Smirnoff ipportspec	: ipspec			{
36433b3a8eb9SGleb Smirnoff 			$$.host = $1;
36443b3a8eb9SGleb Smirnoff 			$$.port = NULL;
36453b3a8eb9SGleb Smirnoff 		}
36463b3a8eb9SGleb Smirnoff 		| ipspec PORT portspec		{
36473b3a8eb9SGleb Smirnoff 			$$.host = $1;
36483b3a8eb9SGleb Smirnoff 			$$.port = $3;
36493b3a8eb9SGleb Smirnoff 		}
36503b3a8eb9SGleb Smirnoff 		| PORT portspec			{
36513b3a8eb9SGleb Smirnoff 			$$.host = NULL;
36523b3a8eb9SGleb Smirnoff 			$$.port = $2;
36533b3a8eb9SGleb Smirnoff 		}
36543b3a8eb9SGleb Smirnoff 		;
36553b3a8eb9SGleb Smirnoff 
36563b3a8eb9SGleb Smirnoff optnl		: '\n' optnl
36573b3a8eb9SGleb Smirnoff 		|
36583b3a8eb9SGleb Smirnoff 		;
36593b3a8eb9SGleb Smirnoff 
36603b3a8eb9SGleb Smirnoff ipspec		: ANY				{ $$ = NULL; }
36613b3a8eb9SGleb Smirnoff 		| xhost				{ $$ = $1; }
36623b3a8eb9SGleb Smirnoff 		| '{' optnl host_list '}'	{ $$ = $3; }
36633b3a8eb9SGleb Smirnoff 		;
36643b3a8eb9SGleb Smirnoff 
36653b3a8eb9SGleb Smirnoff toipspec	: TO ipspec			{ $$ = $2; }
36663b3a8eb9SGleb Smirnoff 		| /* empty */			{ $$ = NULL; }
36673b3a8eb9SGleb Smirnoff 		;
36683b3a8eb9SGleb Smirnoff 
36693b3a8eb9SGleb Smirnoff host_list	: ipspec optnl			{ $$ = $1; }
36703b3a8eb9SGleb Smirnoff 		| host_list comma ipspec optnl	{
3671637d81c5SKristof Provost 			if ($1 == NULL) {
3672637d81c5SKristof Provost 				freehostlist($3);
36733b3a8eb9SGleb Smirnoff 				$$ = $1;
3674637d81c5SKristof Provost 			} else if ($3 == NULL) {
3675637d81c5SKristof Provost 				freehostlist($1);
36763b3a8eb9SGleb Smirnoff 				$$ = $3;
3677637d81c5SKristof Provost 			} else {
36783b3a8eb9SGleb Smirnoff 				$1->tail->next = $3;
36793b3a8eb9SGleb Smirnoff 				$1->tail = $3->tail;
36803b3a8eb9SGleb Smirnoff 				$$ = $1;
36813b3a8eb9SGleb Smirnoff 			}
36823b3a8eb9SGleb Smirnoff 		}
36833b3a8eb9SGleb Smirnoff 		;
36843b3a8eb9SGleb Smirnoff 
36853b3a8eb9SGleb Smirnoff xhost		: not host			{
36863b3a8eb9SGleb Smirnoff 			struct node_host	*n;
36873b3a8eb9SGleb Smirnoff 
36883b3a8eb9SGleb Smirnoff 			for (n = $2; n != NULL; n = n->next)
36893b3a8eb9SGleb Smirnoff 				n->not = $1;
36903b3a8eb9SGleb Smirnoff 			$$ = $2;
36913b3a8eb9SGleb Smirnoff 		}
36923b3a8eb9SGleb Smirnoff 		| not NOROUTE			{
36933b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
36943b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
36953b3a8eb9SGleb Smirnoff 				err(1, "xhost: calloc");
36963b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_NOROUTE;
36973b3a8eb9SGleb Smirnoff 			$$->next = NULL;
36983b3a8eb9SGleb Smirnoff 			$$->not = $1;
36993b3a8eb9SGleb Smirnoff 			$$->tail = $$;
37003b3a8eb9SGleb Smirnoff 		}
37013b3a8eb9SGleb Smirnoff 		| not URPFFAILED		{
37023b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
37033b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
37043b3a8eb9SGleb Smirnoff 				err(1, "xhost: calloc");
37053b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_URPFFAILED;
37063b3a8eb9SGleb Smirnoff 			$$->next = NULL;
37073b3a8eb9SGleb Smirnoff 			$$->not = $1;
37083b3a8eb9SGleb Smirnoff 			$$->tail = $$;
37093b3a8eb9SGleb Smirnoff 		}
37103b3a8eb9SGleb Smirnoff 		;
37113b3a8eb9SGleb Smirnoff 
37123b3a8eb9SGleb Smirnoff host		: STRING			{
37133b3a8eb9SGleb Smirnoff 			if (($$ = host($1)) == NULL)	{
37143b3a8eb9SGleb Smirnoff 				/* error. "any" is handled elsewhere */
37153b3a8eb9SGleb Smirnoff 				free($1);
37163b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
37173b3a8eb9SGleb Smirnoff 				YYERROR;
37183b3a8eb9SGleb Smirnoff 			}
37193b3a8eb9SGleb Smirnoff 			free($1);
37203b3a8eb9SGleb Smirnoff 
37213b3a8eb9SGleb Smirnoff 		}
37223b3a8eb9SGleb Smirnoff 		| STRING '-' STRING		{
37233b3a8eb9SGleb Smirnoff 			struct node_host *b, *e;
37243b3a8eb9SGleb Smirnoff 
37253b3a8eb9SGleb Smirnoff 			if ((b = host($1)) == NULL || (e = host($3)) == NULL) {
37263b3a8eb9SGleb Smirnoff 				free($1);
37273b3a8eb9SGleb Smirnoff 				free($3);
37283b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
37293b3a8eb9SGleb Smirnoff 				YYERROR;
37303b3a8eb9SGleb Smirnoff 			}
37313b3a8eb9SGleb Smirnoff 			if (b->af != e->af ||
37323b3a8eb9SGleb Smirnoff 			    b->addr.type != PF_ADDR_ADDRMASK ||
37333b3a8eb9SGleb Smirnoff 			    e->addr.type != PF_ADDR_ADDRMASK ||
37343b3a8eb9SGleb Smirnoff 			    unmask(&b->addr.v.a.mask, b->af) !=
37353b3a8eb9SGleb Smirnoff 			    (b->af == AF_INET ? 32 : 128) ||
37363b3a8eb9SGleb Smirnoff 			    unmask(&e->addr.v.a.mask, e->af) !=
37373b3a8eb9SGleb Smirnoff 			    (e->af == AF_INET ? 32 : 128) ||
37383b3a8eb9SGleb Smirnoff 			    b->next != NULL || b->not ||
37393b3a8eb9SGleb Smirnoff 			    e->next != NULL || e->not) {
37403b3a8eb9SGleb Smirnoff 				free(b);
37413b3a8eb9SGleb Smirnoff 				free(e);
37423b3a8eb9SGleb Smirnoff 				free($1);
37433b3a8eb9SGleb Smirnoff 				free($3);
37443b3a8eb9SGleb Smirnoff 				yyerror("invalid address range");
37453b3a8eb9SGleb Smirnoff 				YYERROR;
37463b3a8eb9SGleb Smirnoff 			}
37473b3a8eb9SGleb Smirnoff 			memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
37483b3a8eb9SGleb Smirnoff 			    sizeof(b->addr.v.a.mask));
37493b3a8eb9SGleb Smirnoff 			b->addr.type = PF_ADDR_RANGE;
37503b3a8eb9SGleb Smirnoff 			$$ = b;
37513b3a8eb9SGleb Smirnoff 			free(e);
37523b3a8eb9SGleb Smirnoff 			free($1);
37533b3a8eb9SGleb Smirnoff 			free($3);
37543b3a8eb9SGleb Smirnoff 		}
37553b3a8eb9SGleb Smirnoff 		| STRING '/' NUMBER		{
37563b3a8eb9SGleb Smirnoff 			char	*buf;
37573b3a8eb9SGleb Smirnoff 
37583b3a8eb9SGleb Smirnoff 			if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1)
37593b3a8eb9SGleb Smirnoff 				err(1, "host: asprintf");
37603b3a8eb9SGleb Smirnoff 			free($1);
37613b3a8eb9SGleb Smirnoff 			if (($$ = host(buf)) == NULL)	{
37623b3a8eb9SGleb Smirnoff 				/* error. "any" is handled elsewhere */
37633b3a8eb9SGleb Smirnoff 				free(buf);
37643b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
37653b3a8eb9SGleb Smirnoff 				YYERROR;
37663b3a8eb9SGleb Smirnoff 			}
37673b3a8eb9SGleb Smirnoff 			free(buf);
37683b3a8eb9SGleb Smirnoff 		}
37693b3a8eb9SGleb Smirnoff 		| NUMBER '/' NUMBER		{
37703b3a8eb9SGleb Smirnoff 			char	*buf;
37713b3a8eb9SGleb Smirnoff 
37723b3a8eb9SGleb Smirnoff 			/* ie. for 10/8 parsing */
37733b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
37743b3a8eb9SGleb Smirnoff 			if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1)
37753b3a8eb9SGleb Smirnoff #else
37763b3a8eb9SGleb Smirnoff 			if (asprintf(&buf, "%lld/%lld", $1, $3) == -1)
37773b3a8eb9SGleb Smirnoff #endif
37783b3a8eb9SGleb Smirnoff 				err(1, "host: asprintf");
37793b3a8eb9SGleb Smirnoff 			if (($$ = host(buf)) == NULL)	{
37803b3a8eb9SGleb Smirnoff 				/* error. "any" is handled elsewhere */
37813b3a8eb9SGleb Smirnoff 				free(buf);
37823b3a8eb9SGleb Smirnoff 				yyerror("could not parse host specification");
37833b3a8eb9SGleb Smirnoff 				YYERROR;
37843b3a8eb9SGleb Smirnoff 			}
37853b3a8eb9SGleb Smirnoff 			free(buf);
37863b3a8eb9SGleb Smirnoff 		}
37873b3a8eb9SGleb Smirnoff 		| dynaddr
37883b3a8eb9SGleb Smirnoff 		| dynaddr '/' NUMBER		{
37893b3a8eb9SGleb Smirnoff 			struct node_host	*n;
37903b3a8eb9SGleb Smirnoff 
37913b3a8eb9SGleb Smirnoff 			if ($3 < 0 || $3 > 128) {
37923b3a8eb9SGleb Smirnoff 				yyerror("bit number too big");
37933b3a8eb9SGleb Smirnoff 				YYERROR;
37943b3a8eb9SGleb Smirnoff 			}
37953b3a8eb9SGleb Smirnoff 			$$ = $1;
37963b3a8eb9SGleb Smirnoff 			for (n = $1; n != NULL; n = n->next)
37973b3a8eb9SGleb Smirnoff 				set_ipmask(n, $3);
37983b3a8eb9SGleb Smirnoff 		}
37993b3a8eb9SGleb Smirnoff 		| '<' STRING '>'	{
38003b3a8eb9SGleb Smirnoff 			if (strlen($2) >= PF_TABLE_NAME_SIZE) {
38013b3a8eb9SGleb Smirnoff 				yyerror("table name '%s' too long", $2);
38023b3a8eb9SGleb Smirnoff 				free($2);
38033b3a8eb9SGleb Smirnoff 				YYERROR;
38043b3a8eb9SGleb Smirnoff 			}
38053b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
38063b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
38073b3a8eb9SGleb Smirnoff 				err(1, "host: calloc");
38083b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_TABLE;
38093b3a8eb9SGleb Smirnoff 			if (strlcpy($$->addr.v.tblname, $2,
38103b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.tblname)) >=
38113b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.tblname))
38123b3a8eb9SGleb Smirnoff 				errx(1, "host: strlcpy");
38133b3a8eb9SGleb Smirnoff 			free($2);
38143b3a8eb9SGleb Smirnoff 			$$->next = NULL;
38153b3a8eb9SGleb Smirnoff 			$$->tail = $$;
38163b3a8eb9SGleb Smirnoff 		}
38173b3a8eb9SGleb Smirnoff 		;
38183b3a8eb9SGleb Smirnoff 
38193b3a8eb9SGleb Smirnoff number		: NUMBER
38203b3a8eb9SGleb Smirnoff 		| STRING		{
38213b3a8eb9SGleb Smirnoff 			u_long	ulval;
38223b3a8eb9SGleb Smirnoff 
38233b3a8eb9SGleb Smirnoff 			if (atoul($1, &ulval) == -1) {
38243b3a8eb9SGleb Smirnoff 				yyerror("%s is not a number", $1);
38253b3a8eb9SGleb Smirnoff 				free($1);
38263b3a8eb9SGleb Smirnoff 				YYERROR;
38273b3a8eb9SGleb Smirnoff 			} else
38283b3a8eb9SGleb Smirnoff 				$$ = ulval;
38293b3a8eb9SGleb Smirnoff 			free($1);
38303b3a8eb9SGleb Smirnoff 		}
38313b3a8eb9SGleb Smirnoff 		;
38323b3a8eb9SGleb Smirnoff 
38333b3a8eb9SGleb Smirnoff dynaddr		: '(' STRING ')'		{
38343b3a8eb9SGleb Smirnoff 			int	 flags = 0;
38353b3a8eb9SGleb Smirnoff 			char	*p, *op;
38363b3a8eb9SGleb Smirnoff 
38373b3a8eb9SGleb Smirnoff 			op = $2;
38383b3a8eb9SGleb Smirnoff 			if (!isalpha(op[0])) {
38393b3a8eb9SGleb Smirnoff 				yyerror("invalid interface name '%s'", op);
38403b3a8eb9SGleb Smirnoff 				free(op);
38413b3a8eb9SGleb Smirnoff 				YYERROR;
38423b3a8eb9SGleb Smirnoff 			}
38433b3a8eb9SGleb Smirnoff 			while ((p = strrchr($2, ':')) != NULL) {
38443b3a8eb9SGleb Smirnoff 				if (!strcmp(p+1, "network"))
38453b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_NETWORK;
38463b3a8eb9SGleb Smirnoff 				else if (!strcmp(p+1, "broadcast"))
38473b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_BROADCAST;
38483b3a8eb9SGleb Smirnoff 				else if (!strcmp(p+1, "peer"))
38493b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_PEER;
38503b3a8eb9SGleb Smirnoff 				else if (!strcmp(p+1, "0"))
38513b3a8eb9SGleb Smirnoff 					flags |= PFI_AFLAG_NOALIAS;
38523b3a8eb9SGleb Smirnoff 				else {
38533b3a8eb9SGleb Smirnoff 					yyerror("interface %s has bad modifier",
38543b3a8eb9SGleb Smirnoff 					    $2);
38553b3a8eb9SGleb Smirnoff 					free(op);
38563b3a8eb9SGleb Smirnoff 					YYERROR;
38573b3a8eb9SGleb Smirnoff 				}
38583b3a8eb9SGleb Smirnoff 				*p = '\0';
38593b3a8eb9SGleb Smirnoff 			}
38603b3a8eb9SGleb Smirnoff 			if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
38613b3a8eb9SGleb Smirnoff 				free(op);
38623b3a8eb9SGleb Smirnoff 				yyerror("illegal combination of "
38633b3a8eb9SGleb Smirnoff 				    "interface modifiers");
38643b3a8eb9SGleb Smirnoff 				YYERROR;
38653b3a8eb9SGleb Smirnoff 			}
38663b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
38673b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
38683b3a8eb9SGleb Smirnoff 				err(1, "address: calloc");
38693b3a8eb9SGleb Smirnoff 			$$->af = 0;
38703b3a8eb9SGleb Smirnoff 			set_ipmask($$, 128);
38713b3a8eb9SGleb Smirnoff 			$$->addr.type = PF_ADDR_DYNIFTL;
38723b3a8eb9SGleb Smirnoff 			$$->addr.iflags = flags;
38733b3a8eb9SGleb Smirnoff 			if (strlcpy($$->addr.v.ifname, $2,
38743b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.ifname)) >=
38753b3a8eb9SGleb Smirnoff 			    sizeof($$->addr.v.ifname)) {
38763b3a8eb9SGleb Smirnoff 				free(op);
38773b3a8eb9SGleb Smirnoff 				free($$);
38783b3a8eb9SGleb Smirnoff 				yyerror("interface name too long");
38793b3a8eb9SGleb Smirnoff 				YYERROR;
38803b3a8eb9SGleb Smirnoff 			}
38813b3a8eb9SGleb Smirnoff 			free(op);
38823b3a8eb9SGleb Smirnoff 			$$->next = NULL;
38833b3a8eb9SGleb Smirnoff 			$$->tail = $$;
38843b3a8eb9SGleb Smirnoff 		}
38853b3a8eb9SGleb Smirnoff 		;
38863b3a8eb9SGleb Smirnoff 
38873b3a8eb9SGleb Smirnoff portspec	: port_item			{ $$ = $1; }
38883b3a8eb9SGleb Smirnoff 		| '{' optnl port_list '}'	{ $$ = $3; }
38893b3a8eb9SGleb Smirnoff 		;
38903b3a8eb9SGleb Smirnoff 
38913b3a8eb9SGleb Smirnoff port_list	: port_item optnl		{ $$ = $1; }
38923b3a8eb9SGleb Smirnoff 		| port_list comma port_item optnl	{
38933b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
38943b3a8eb9SGleb Smirnoff 			$1->tail = $3;
38953b3a8eb9SGleb Smirnoff 			$$ = $1;
38963b3a8eb9SGleb Smirnoff 		}
38973b3a8eb9SGleb Smirnoff 		;
38983b3a8eb9SGleb Smirnoff 
38993b3a8eb9SGleb Smirnoff port_item	: portrange			{
39003b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_port));
39013b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
39023b3a8eb9SGleb Smirnoff 				err(1, "port_item: calloc");
39033b3a8eb9SGleb Smirnoff 			$$->port[0] = $1.a;
39043b3a8eb9SGleb Smirnoff 			$$->port[1] = $1.b;
39053b3a8eb9SGleb Smirnoff 			if ($1.t)
39063b3a8eb9SGleb Smirnoff 				$$->op = PF_OP_RRG;
39073b3a8eb9SGleb Smirnoff 			else
39083b3a8eb9SGleb Smirnoff 				$$->op = PF_OP_EQ;
39093b3a8eb9SGleb Smirnoff 			$$->next = NULL;
39103b3a8eb9SGleb Smirnoff 			$$->tail = $$;
39113b3a8eb9SGleb Smirnoff 		}
39123b3a8eb9SGleb Smirnoff 		| unaryop portrange	{
39133b3a8eb9SGleb Smirnoff 			if ($2.t) {
39143b3a8eb9SGleb Smirnoff 				yyerror("':' cannot be used with an other "
39153b3a8eb9SGleb Smirnoff 				    "port operator");
39163b3a8eb9SGleb Smirnoff 				YYERROR;
39173b3a8eb9SGleb Smirnoff 			}
39183b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_port));
39193b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
39203b3a8eb9SGleb Smirnoff 				err(1, "port_item: calloc");
39213b3a8eb9SGleb Smirnoff 			$$->port[0] = $2.a;
39223b3a8eb9SGleb Smirnoff 			$$->port[1] = $2.b;
39233b3a8eb9SGleb Smirnoff 			$$->op = $1;
39243b3a8eb9SGleb Smirnoff 			$$->next = NULL;
39253b3a8eb9SGleb Smirnoff 			$$->tail = $$;
39263b3a8eb9SGleb Smirnoff 		}
39273b3a8eb9SGleb Smirnoff 		| portrange PORTBINARY portrange	{
39283b3a8eb9SGleb Smirnoff 			if ($1.t || $3.t) {
39293b3a8eb9SGleb Smirnoff 				yyerror("':' cannot be used with an other "
39303b3a8eb9SGleb Smirnoff 				    "port operator");
39313b3a8eb9SGleb Smirnoff 				YYERROR;
39323b3a8eb9SGleb Smirnoff 			}
39333b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_port));
39343b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
39353b3a8eb9SGleb Smirnoff 				err(1, "port_item: calloc");
39363b3a8eb9SGleb Smirnoff 			$$->port[0] = $1.a;
39373b3a8eb9SGleb Smirnoff 			$$->port[1] = $3.a;
39383b3a8eb9SGleb Smirnoff 			$$->op = $2;
39393b3a8eb9SGleb Smirnoff 			$$->next = NULL;
39403b3a8eb9SGleb Smirnoff 			$$->tail = $$;
39413b3a8eb9SGleb Smirnoff 		}
39423b3a8eb9SGleb Smirnoff 		;
39433b3a8eb9SGleb Smirnoff 
39443b3a8eb9SGleb Smirnoff portplain	: numberstring			{
39453b3a8eb9SGleb Smirnoff 			if (parseport($1, &$$, 0) == -1) {
39463b3a8eb9SGleb Smirnoff 				free($1);
39473b3a8eb9SGleb Smirnoff 				YYERROR;
39483b3a8eb9SGleb Smirnoff 			}
39493b3a8eb9SGleb Smirnoff 			free($1);
39503b3a8eb9SGleb Smirnoff 		}
39513b3a8eb9SGleb Smirnoff 		;
39523b3a8eb9SGleb Smirnoff 
39533b3a8eb9SGleb Smirnoff portrange	: numberstring			{
39543b3a8eb9SGleb Smirnoff 			if (parseport($1, &$$, PPORT_RANGE) == -1) {
39553b3a8eb9SGleb Smirnoff 				free($1);
39563b3a8eb9SGleb Smirnoff 				YYERROR;
39573b3a8eb9SGleb Smirnoff 			}
39583b3a8eb9SGleb Smirnoff 			free($1);
39593b3a8eb9SGleb Smirnoff 		}
39603b3a8eb9SGleb Smirnoff 		;
39613b3a8eb9SGleb Smirnoff 
39623b3a8eb9SGleb Smirnoff uids		: uid_item			{ $$ = $1; }
39633b3a8eb9SGleb Smirnoff 		| '{' optnl uid_list '}'	{ $$ = $3; }
39643b3a8eb9SGleb Smirnoff 		;
39653b3a8eb9SGleb Smirnoff 
39663b3a8eb9SGleb Smirnoff uid_list	: uid_item optnl		{ $$ = $1; }
39673b3a8eb9SGleb Smirnoff 		| uid_list comma uid_item optnl	{
39683b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
39693b3a8eb9SGleb Smirnoff 			$1->tail = $3;
39703b3a8eb9SGleb Smirnoff 			$$ = $1;
39713b3a8eb9SGleb Smirnoff 		}
39723b3a8eb9SGleb Smirnoff 		;
39733b3a8eb9SGleb Smirnoff 
39743b3a8eb9SGleb Smirnoff uid_item	: uid				{
39753b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_uid));
39763b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
39773b3a8eb9SGleb Smirnoff 				err(1, "uid_item: calloc");
39783b3a8eb9SGleb Smirnoff 			$$->uid[0] = $1;
39793b3a8eb9SGleb Smirnoff 			$$->uid[1] = $1;
39803b3a8eb9SGleb Smirnoff 			$$->op = PF_OP_EQ;
39813b3a8eb9SGleb Smirnoff 			$$->next = NULL;
39823b3a8eb9SGleb Smirnoff 			$$->tail = $$;
39833b3a8eb9SGleb Smirnoff 		}
39843b3a8eb9SGleb Smirnoff 		| unaryop uid			{
39853b3a8eb9SGleb Smirnoff 			if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
39863b3a8eb9SGleb Smirnoff 				yyerror("user unknown requires operator = or "
39873b3a8eb9SGleb Smirnoff 				    "!=");
39883b3a8eb9SGleb Smirnoff 				YYERROR;
39893b3a8eb9SGleb Smirnoff 			}
39903b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_uid));
39913b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
39923b3a8eb9SGleb Smirnoff 				err(1, "uid_item: calloc");
39933b3a8eb9SGleb Smirnoff 			$$->uid[0] = $2;
39943b3a8eb9SGleb Smirnoff 			$$->uid[1] = $2;
39953b3a8eb9SGleb Smirnoff 			$$->op = $1;
39963b3a8eb9SGleb Smirnoff 			$$->next = NULL;
39973b3a8eb9SGleb Smirnoff 			$$->tail = $$;
39983b3a8eb9SGleb Smirnoff 		}
39993b3a8eb9SGleb Smirnoff 		| uid PORTBINARY uid		{
40003b3a8eb9SGleb Smirnoff 			if ($1 == UID_MAX || $3 == UID_MAX) {
40013b3a8eb9SGleb Smirnoff 				yyerror("user unknown requires operator = or "
40023b3a8eb9SGleb Smirnoff 				    "!=");
40033b3a8eb9SGleb Smirnoff 				YYERROR;
40043b3a8eb9SGleb Smirnoff 			}
40053b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_uid));
40063b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
40073b3a8eb9SGleb Smirnoff 				err(1, "uid_item: calloc");
40083b3a8eb9SGleb Smirnoff 			$$->uid[0] = $1;
40093b3a8eb9SGleb Smirnoff 			$$->uid[1] = $3;
40103b3a8eb9SGleb Smirnoff 			$$->op = $2;
40113b3a8eb9SGleb Smirnoff 			$$->next = NULL;
40123b3a8eb9SGleb Smirnoff 			$$->tail = $$;
40133b3a8eb9SGleb Smirnoff 		}
40143b3a8eb9SGleb Smirnoff 		;
40153b3a8eb9SGleb Smirnoff 
40163b3a8eb9SGleb Smirnoff uid		: STRING			{
40173b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "unknown"))
40183b3a8eb9SGleb Smirnoff 				$$ = UID_MAX;
40193b3a8eb9SGleb Smirnoff 			else {
40203b3a8eb9SGleb Smirnoff 				struct passwd	*pw;
40213b3a8eb9SGleb Smirnoff 
40223b3a8eb9SGleb Smirnoff 				if ((pw = getpwnam($1)) == NULL) {
40233b3a8eb9SGleb Smirnoff 					yyerror("unknown user %s", $1);
40243b3a8eb9SGleb Smirnoff 					free($1);
40253b3a8eb9SGleb Smirnoff 					YYERROR;
40263b3a8eb9SGleb Smirnoff 				}
40273b3a8eb9SGleb Smirnoff 				$$ = pw->pw_uid;
40283b3a8eb9SGleb Smirnoff 			}
40293b3a8eb9SGleb Smirnoff 			free($1);
40303b3a8eb9SGleb Smirnoff 		}
40313b3a8eb9SGleb Smirnoff 		| NUMBER			{
40323b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 >= UID_MAX) {
40333b3a8eb9SGleb Smirnoff 				yyerror("illegal uid value %lu", $1);
40343b3a8eb9SGleb Smirnoff 				YYERROR;
40353b3a8eb9SGleb Smirnoff 			}
40363b3a8eb9SGleb Smirnoff 			$$ = $1;
40373b3a8eb9SGleb Smirnoff 		}
40383b3a8eb9SGleb Smirnoff 		;
40393b3a8eb9SGleb Smirnoff 
40403b3a8eb9SGleb Smirnoff gids		: gid_item			{ $$ = $1; }
40413b3a8eb9SGleb Smirnoff 		| '{' optnl gid_list '}'	{ $$ = $3; }
40423b3a8eb9SGleb Smirnoff 		;
40433b3a8eb9SGleb Smirnoff 
40443b3a8eb9SGleb Smirnoff gid_list	: gid_item optnl		{ $$ = $1; }
40453b3a8eb9SGleb Smirnoff 		| gid_list comma gid_item optnl	{
40463b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
40473b3a8eb9SGleb Smirnoff 			$1->tail = $3;
40483b3a8eb9SGleb Smirnoff 			$$ = $1;
40493b3a8eb9SGleb Smirnoff 		}
40503b3a8eb9SGleb Smirnoff 		;
40513b3a8eb9SGleb Smirnoff 
40523b3a8eb9SGleb Smirnoff gid_item	: gid				{
40533b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_gid));
40543b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
40553b3a8eb9SGleb Smirnoff 				err(1, "gid_item: calloc");
40563b3a8eb9SGleb Smirnoff 			$$->gid[0] = $1;
40573b3a8eb9SGleb Smirnoff 			$$->gid[1] = $1;
40583b3a8eb9SGleb Smirnoff 			$$->op = PF_OP_EQ;
40593b3a8eb9SGleb Smirnoff 			$$->next = NULL;
40603b3a8eb9SGleb Smirnoff 			$$->tail = $$;
40613b3a8eb9SGleb Smirnoff 		}
40623b3a8eb9SGleb Smirnoff 		| unaryop gid			{
40633b3a8eb9SGleb Smirnoff 			if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
40643b3a8eb9SGleb Smirnoff 				yyerror("group unknown requires operator = or "
40653b3a8eb9SGleb Smirnoff 				    "!=");
40663b3a8eb9SGleb Smirnoff 				YYERROR;
40673b3a8eb9SGleb Smirnoff 			}
40683b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_gid));
40693b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
40703b3a8eb9SGleb Smirnoff 				err(1, "gid_item: calloc");
40713b3a8eb9SGleb Smirnoff 			$$->gid[0] = $2;
40723b3a8eb9SGleb Smirnoff 			$$->gid[1] = $2;
40733b3a8eb9SGleb Smirnoff 			$$->op = $1;
40743b3a8eb9SGleb Smirnoff 			$$->next = NULL;
40753b3a8eb9SGleb Smirnoff 			$$->tail = $$;
40763b3a8eb9SGleb Smirnoff 		}
40773b3a8eb9SGleb Smirnoff 		| gid PORTBINARY gid		{
40783b3a8eb9SGleb Smirnoff 			if ($1 == GID_MAX || $3 == GID_MAX) {
40793b3a8eb9SGleb Smirnoff 				yyerror("group unknown requires operator = or "
40803b3a8eb9SGleb Smirnoff 				    "!=");
40813b3a8eb9SGleb Smirnoff 				YYERROR;
40823b3a8eb9SGleb Smirnoff 			}
40833b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_gid));
40843b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
40853b3a8eb9SGleb Smirnoff 				err(1, "gid_item: calloc");
40863b3a8eb9SGleb Smirnoff 			$$->gid[0] = $1;
40873b3a8eb9SGleb Smirnoff 			$$->gid[1] = $3;
40883b3a8eb9SGleb Smirnoff 			$$->op = $2;
40893b3a8eb9SGleb Smirnoff 			$$->next = NULL;
40903b3a8eb9SGleb Smirnoff 			$$->tail = $$;
40913b3a8eb9SGleb Smirnoff 		}
40923b3a8eb9SGleb Smirnoff 		;
40933b3a8eb9SGleb Smirnoff 
40943b3a8eb9SGleb Smirnoff gid		: STRING			{
40953b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "unknown"))
40963b3a8eb9SGleb Smirnoff 				$$ = GID_MAX;
40973b3a8eb9SGleb Smirnoff 			else {
40983b3a8eb9SGleb Smirnoff 				struct group	*grp;
40993b3a8eb9SGleb Smirnoff 
41003b3a8eb9SGleb Smirnoff 				if ((grp = getgrnam($1)) == NULL) {
41013b3a8eb9SGleb Smirnoff 					yyerror("unknown group %s", $1);
41023b3a8eb9SGleb Smirnoff 					free($1);
41033b3a8eb9SGleb Smirnoff 					YYERROR;
41043b3a8eb9SGleb Smirnoff 				}
41053b3a8eb9SGleb Smirnoff 				$$ = grp->gr_gid;
41063b3a8eb9SGleb Smirnoff 			}
41073b3a8eb9SGleb Smirnoff 			free($1);
41083b3a8eb9SGleb Smirnoff 		}
41093b3a8eb9SGleb Smirnoff 		| NUMBER			{
41103b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 >= GID_MAX) {
41113b3a8eb9SGleb Smirnoff 				yyerror("illegal gid value %lu", $1);
41123b3a8eb9SGleb Smirnoff 				YYERROR;
41133b3a8eb9SGleb Smirnoff 			}
41143b3a8eb9SGleb Smirnoff 			$$ = $1;
41153b3a8eb9SGleb Smirnoff 		}
41163b3a8eb9SGleb Smirnoff 		;
41173b3a8eb9SGleb Smirnoff 
41183b3a8eb9SGleb Smirnoff flag		: STRING			{
41193b3a8eb9SGleb Smirnoff 			int	f;
41203b3a8eb9SGleb Smirnoff 
41213b3a8eb9SGleb Smirnoff 			if ((f = parse_flags($1)) < 0) {
41223b3a8eb9SGleb Smirnoff 				yyerror("bad flags %s", $1);
41233b3a8eb9SGleb Smirnoff 				free($1);
41243b3a8eb9SGleb Smirnoff 				YYERROR;
41253b3a8eb9SGleb Smirnoff 			}
41263b3a8eb9SGleb Smirnoff 			free($1);
41273b3a8eb9SGleb Smirnoff 			$$.b1 = f;
41283b3a8eb9SGleb Smirnoff 		}
41293b3a8eb9SGleb Smirnoff 		;
41303b3a8eb9SGleb Smirnoff 
41313b3a8eb9SGleb Smirnoff flags		: FLAGS flag '/' flag	{ $$.b1 = $2.b1; $$.b2 = $4.b1; }
41323b3a8eb9SGleb Smirnoff 		| FLAGS '/' flag	{ $$.b1 = 0; $$.b2 = $3.b1; }
41333b3a8eb9SGleb Smirnoff 		| FLAGS ANY		{ $$.b1 = 0; $$.b2 = 0; }
41343b3a8eb9SGleb Smirnoff 		;
41353b3a8eb9SGleb Smirnoff 
41363b3a8eb9SGleb Smirnoff icmpspec	: ICMPTYPE icmp_item			{ $$ = $2; }
41373b3a8eb9SGleb Smirnoff 		| ICMPTYPE '{' optnl icmp_list '}'	{ $$ = $4; }
41383b3a8eb9SGleb Smirnoff 		| ICMP6TYPE icmp6_item			{ $$ = $2; }
41393b3a8eb9SGleb Smirnoff 		| ICMP6TYPE '{' optnl icmp6_list '}'	{ $$ = $4; }
41403b3a8eb9SGleb Smirnoff 		;
41413b3a8eb9SGleb Smirnoff 
41423b3a8eb9SGleb Smirnoff icmp_list	: icmp_item optnl		{ $$ = $1; }
41433b3a8eb9SGleb Smirnoff 		| icmp_list comma icmp_item optnl {
41443b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
41453b3a8eb9SGleb Smirnoff 			$1->tail = $3;
41463b3a8eb9SGleb Smirnoff 			$$ = $1;
41473b3a8eb9SGleb Smirnoff 		}
41483b3a8eb9SGleb Smirnoff 		;
41493b3a8eb9SGleb Smirnoff 
41503b3a8eb9SGleb Smirnoff icmp6_list	: icmp6_item optnl		{ $$ = $1; }
41513b3a8eb9SGleb Smirnoff 		| icmp6_list comma icmp6_item optnl {
41523b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
41533b3a8eb9SGleb Smirnoff 			$1->tail = $3;
41543b3a8eb9SGleb Smirnoff 			$$ = $1;
41553b3a8eb9SGleb Smirnoff 		}
41563b3a8eb9SGleb Smirnoff 		;
41573b3a8eb9SGleb Smirnoff 
41583b3a8eb9SGleb Smirnoff icmp_item	: icmptype		{
41593b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
41603b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
41613b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
41623b3a8eb9SGleb Smirnoff 			$$->type = $1;
41633b3a8eb9SGleb Smirnoff 			$$->code = 0;
41643b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMP;
41653b3a8eb9SGleb Smirnoff 			$$->next = NULL;
41663b3a8eb9SGleb Smirnoff 			$$->tail = $$;
41673b3a8eb9SGleb Smirnoff 		}
41683b3a8eb9SGleb Smirnoff 		| icmptype CODE STRING	{
41693b3a8eb9SGleb Smirnoff 			const struct icmpcodeent	*p;
41703b3a8eb9SGleb Smirnoff 
41713b3a8eb9SGleb Smirnoff 			if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) {
41723b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp-code %s", $3);
41733b3a8eb9SGleb Smirnoff 				free($3);
41743b3a8eb9SGleb Smirnoff 				YYERROR;
41753b3a8eb9SGleb Smirnoff 			}
41763b3a8eb9SGleb Smirnoff 
41773b3a8eb9SGleb Smirnoff 			free($3);
41783b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
41793b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
41803b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
41813b3a8eb9SGleb Smirnoff 			$$->type = $1;
41823b3a8eb9SGleb Smirnoff 			$$->code = p->code + 1;
41833b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMP;
41843b3a8eb9SGleb Smirnoff 			$$->next = NULL;
41853b3a8eb9SGleb Smirnoff 			$$->tail = $$;
41863b3a8eb9SGleb Smirnoff 		}
41873b3a8eb9SGleb Smirnoff 		| icmptype CODE NUMBER	{
41883b3a8eb9SGleb Smirnoff 			if ($3 < 0 || $3 > 255) {
41893b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp-code %lu", $3);
41903b3a8eb9SGleb Smirnoff 				YYERROR;
41913b3a8eb9SGleb Smirnoff 			}
41923b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
41933b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
41943b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
41953b3a8eb9SGleb Smirnoff 			$$->type = $1;
41963b3a8eb9SGleb Smirnoff 			$$->code = $3 + 1;
41973b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMP;
41983b3a8eb9SGleb Smirnoff 			$$->next = NULL;
41993b3a8eb9SGleb Smirnoff 			$$->tail = $$;
42003b3a8eb9SGleb Smirnoff 		}
42013b3a8eb9SGleb Smirnoff 		;
42023b3a8eb9SGleb Smirnoff 
42033b3a8eb9SGleb Smirnoff icmp6_item	: icmp6type		{
42043b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
42053b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
42063b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
42073b3a8eb9SGleb Smirnoff 			$$->type = $1;
42083b3a8eb9SGleb Smirnoff 			$$->code = 0;
42093b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMPV6;
42103b3a8eb9SGleb Smirnoff 			$$->next = NULL;
42113b3a8eb9SGleb Smirnoff 			$$->tail = $$;
42123b3a8eb9SGleb Smirnoff 		}
42133b3a8eb9SGleb Smirnoff 		| icmp6type CODE STRING	{
42143b3a8eb9SGleb Smirnoff 			const struct icmpcodeent	*p;
42153b3a8eb9SGleb Smirnoff 
42163b3a8eb9SGleb Smirnoff 			if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) {
42173b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp6-code %s", $3);
42183b3a8eb9SGleb Smirnoff 				free($3);
42193b3a8eb9SGleb Smirnoff 				YYERROR;
42203b3a8eb9SGleb Smirnoff 			}
42213b3a8eb9SGleb Smirnoff 			free($3);
42223b3a8eb9SGleb Smirnoff 
42233b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
42243b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
42253b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
42263b3a8eb9SGleb Smirnoff 			$$->type = $1;
42273b3a8eb9SGleb Smirnoff 			$$->code = p->code + 1;
42283b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMPV6;
42293b3a8eb9SGleb Smirnoff 			$$->next = NULL;
42303b3a8eb9SGleb Smirnoff 			$$->tail = $$;
42313b3a8eb9SGleb Smirnoff 		}
42323b3a8eb9SGleb Smirnoff 		| icmp6type CODE NUMBER	{
42333b3a8eb9SGleb Smirnoff 			if ($3 < 0 || $3 > 255) {
42343b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp-code %lu", $3);
42353b3a8eb9SGleb Smirnoff 				YYERROR;
42363b3a8eb9SGleb Smirnoff 			}
42373b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_icmp));
42383b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
42393b3a8eb9SGleb Smirnoff 				err(1, "icmp_item: calloc");
42403b3a8eb9SGleb Smirnoff 			$$->type = $1;
42413b3a8eb9SGleb Smirnoff 			$$->code = $3 + 1;
42423b3a8eb9SGleb Smirnoff 			$$->proto = IPPROTO_ICMPV6;
42433b3a8eb9SGleb Smirnoff 			$$->next = NULL;
42443b3a8eb9SGleb Smirnoff 			$$->tail = $$;
42453b3a8eb9SGleb Smirnoff 		}
42463b3a8eb9SGleb Smirnoff 		;
42473b3a8eb9SGleb Smirnoff 
42483b3a8eb9SGleb Smirnoff icmptype	: STRING			{
42493b3a8eb9SGleb Smirnoff 			const struct icmptypeent	*p;
42503b3a8eb9SGleb Smirnoff 
42513b3a8eb9SGleb Smirnoff 			if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
42523b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp-type %s", $1);
42533b3a8eb9SGleb Smirnoff 				free($1);
42543b3a8eb9SGleb Smirnoff 				YYERROR;
42553b3a8eb9SGleb Smirnoff 			}
42563b3a8eb9SGleb Smirnoff 			$$ = p->type + 1;
42573b3a8eb9SGleb Smirnoff 			free($1);
42583b3a8eb9SGleb Smirnoff 		}
42593b3a8eb9SGleb Smirnoff 		| NUMBER			{
42603b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
42613b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp-type %lu", $1);
42623b3a8eb9SGleb Smirnoff 				YYERROR;
42633b3a8eb9SGleb Smirnoff 			}
42643b3a8eb9SGleb Smirnoff 			$$ = $1 + 1;
42653b3a8eb9SGleb Smirnoff 		}
42663b3a8eb9SGleb Smirnoff 		;
42673b3a8eb9SGleb Smirnoff 
42683b3a8eb9SGleb Smirnoff icmp6type	: STRING			{
42693b3a8eb9SGleb Smirnoff 			const struct icmptypeent	*p;
42703b3a8eb9SGleb Smirnoff 
42713b3a8eb9SGleb Smirnoff 			if ((p = geticmptypebyname($1, AF_INET6)) ==
42723b3a8eb9SGleb Smirnoff 			    NULL) {
42733b3a8eb9SGleb Smirnoff 				yyerror("unknown icmp6-type %s", $1);
42743b3a8eb9SGleb Smirnoff 				free($1);
42753b3a8eb9SGleb Smirnoff 				YYERROR;
42763b3a8eb9SGleb Smirnoff 			}
42773b3a8eb9SGleb Smirnoff 			$$ = p->type + 1;
42783b3a8eb9SGleb Smirnoff 			free($1);
42793b3a8eb9SGleb Smirnoff 		}
42803b3a8eb9SGleb Smirnoff 		| NUMBER			{
42813b3a8eb9SGleb Smirnoff 			if ($1 < 0 || $1 > 255) {
42823b3a8eb9SGleb Smirnoff 				yyerror("illegal icmp6-type %lu", $1);
42833b3a8eb9SGleb Smirnoff 				YYERROR;
42843b3a8eb9SGleb Smirnoff 			}
42853b3a8eb9SGleb Smirnoff 			$$ = $1 + 1;
42863b3a8eb9SGleb Smirnoff 		}
42873b3a8eb9SGleb Smirnoff 		;
42883b3a8eb9SGleb Smirnoff 
42893b3a8eb9SGleb Smirnoff tos	: STRING			{
42901f495578SKristof Provost 			int val;
42911f495578SKristof Provost 			char *end;
42921f495578SKristof Provost 
42931f495578SKristof Provost 			if (map_tos($1, &val))
42941f495578SKristof Provost 				$$ = val;
42951f495578SKristof Provost 			else if ($1[0] == '0' && $1[1] == 'x') {
42961f495578SKristof Provost 				errno = 0;
42971f495578SKristof Provost 				$$ = strtoul($1, &end, 16);
42981f495578SKristof Provost 				if (errno || *end != '\0')
42991f495578SKristof Provost 					$$ = 256;
43001f495578SKristof Provost 			} else
43010cd7a91aSKristof Provost 				$$ = 256;		/* flag bad argument */
43020cd7a91aSKristof Provost 			if ($$ < 0 || $$ > 255) {
43033b3a8eb9SGleb Smirnoff 				yyerror("illegal tos value %s", $1);
43043b3a8eb9SGleb Smirnoff 				free($1);
43053b3a8eb9SGleb Smirnoff 				YYERROR;
43063b3a8eb9SGleb Smirnoff 			}
43073b3a8eb9SGleb Smirnoff 			free($1);
43083b3a8eb9SGleb Smirnoff 		}
43093b3a8eb9SGleb Smirnoff 		| NUMBER			{
43103b3a8eb9SGleb Smirnoff 			$$ = $1;
43110cd7a91aSKristof Provost 			if ($$ < 0 || $$ > 255) {
43126562157dSKristof Provost 				yyerror("illegal tos value %lu", $1);
43133b3a8eb9SGleb Smirnoff 				YYERROR;
43143b3a8eb9SGleb Smirnoff 			}
43153b3a8eb9SGleb Smirnoff 		}
43163b3a8eb9SGleb Smirnoff 		;
43173b3a8eb9SGleb Smirnoff 
43183b3a8eb9SGleb Smirnoff sourcetrack	: SOURCETRACK		{ $$ = PF_SRCTRACK; }
43193b3a8eb9SGleb Smirnoff 		| SOURCETRACK GLOBAL	{ $$ = PF_SRCTRACK_GLOBAL; }
43203b3a8eb9SGleb Smirnoff 		| SOURCETRACK RULE	{ $$ = PF_SRCTRACK_RULE; }
43213b3a8eb9SGleb Smirnoff 		;
43223b3a8eb9SGleb Smirnoff 
43233b3a8eb9SGleb Smirnoff statelock	: IFBOUND {
43243b3a8eb9SGleb Smirnoff 			$$ = PFRULE_IFBOUND;
43253b3a8eb9SGleb Smirnoff 		}
43263b3a8eb9SGleb Smirnoff 		| FLOATING {
43273b3a8eb9SGleb Smirnoff 			$$ = 0;
43283b3a8eb9SGleb Smirnoff 		}
43293b3a8eb9SGleb Smirnoff 		;
43303b3a8eb9SGleb Smirnoff 
43313b3a8eb9SGleb Smirnoff keep		: NO STATE			{
43323b3a8eb9SGleb Smirnoff 			$$.action = 0;
43333b3a8eb9SGleb Smirnoff 			$$.options = NULL;
43343b3a8eb9SGleb Smirnoff 		}
43353b3a8eb9SGleb Smirnoff 		| KEEP STATE state_opt_spec	{
43363b3a8eb9SGleb Smirnoff 			$$.action = PF_STATE_NORMAL;
43373b3a8eb9SGleb Smirnoff 			$$.options = $3;
43383b3a8eb9SGleb Smirnoff 		}
43393b3a8eb9SGleb Smirnoff 		| MODULATE STATE state_opt_spec {
43403b3a8eb9SGleb Smirnoff 			$$.action = PF_STATE_MODULATE;
43413b3a8eb9SGleb Smirnoff 			$$.options = $3;
43423b3a8eb9SGleb Smirnoff 		}
43433b3a8eb9SGleb Smirnoff 		| SYNPROXY STATE state_opt_spec {
43443b3a8eb9SGleb Smirnoff 			$$.action = PF_STATE_SYNPROXY;
43453b3a8eb9SGleb Smirnoff 			$$.options = $3;
43463b3a8eb9SGleb Smirnoff 		}
43473b3a8eb9SGleb Smirnoff 		;
43483b3a8eb9SGleb Smirnoff 
43493b3a8eb9SGleb Smirnoff flush		: /* empty */			{ $$ = 0; }
43503b3a8eb9SGleb Smirnoff 		| FLUSH				{ $$ = PF_FLUSH; }
43513b3a8eb9SGleb Smirnoff 		| FLUSH GLOBAL			{
43523b3a8eb9SGleb Smirnoff 			$$ = PF_FLUSH | PF_FLUSH_GLOBAL;
43533b3a8eb9SGleb Smirnoff 		}
43543b3a8eb9SGleb Smirnoff 		;
43553b3a8eb9SGleb Smirnoff 
43563b3a8eb9SGleb Smirnoff state_opt_spec	: '(' state_opt_list ')'	{ $$ = $2; }
43573b3a8eb9SGleb Smirnoff 		| /* empty */			{ $$ = NULL; }
43583b3a8eb9SGleb Smirnoff 		;
43593b3a8eb9SGleb Smirnoff 
43603b3a8eb9SGleb Smirnoff state_opt_list	: state_opt_item		{ $$ = $1; }
43613b3a8eb9SGleb Smirnoff 		| state_opt_list comma state_opt_item {
43623b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
43633b3a8eb9SGleb Smirnoff 			$1->tail = $3;
43643b3a8eb9SGleb Smirnoff 			$$ = $1;
43653b3a8eb9SGleb Smirnoff 		}
43663b3a8eb9SGleb Smirnoff 		;
43673b3a8eb9SGleb Smirnoff 
43683b3a8eb9SGleb Smirnoff state_opt_item	: MAXIMUM NUMBER		{
43693b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
43703b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
43713b3a8eb9SGleb Smirnoff 				YYERROR;
43723b3a8eb9SGleb Smirnoff 			}
43733b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
43743b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
43753b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
43763b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX;
43773b3a8eb9SGleb Smirnoff 			$$->data.max_states = $2;
43783b3a8eb9SGleb Smirnoff 			$$->next = NULL;
43793b3a8eb9SGleb Smirnoff 			$$->tail = $$;
43803b3a8eb9SGleb Smirnoff 		}
43813b3a8eb9SGleb Smirnoff 		| NOSYNC				{
43823b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
43833b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
43843b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
43853b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_NOSYNC;
43863b3a8eb9SGleb Smirnoff 			$$->next = NULL;
43873b3a8eb9SGleb Smirnoff 			$$->tail = $$;
43883b3a8eb9SGleb Smirnoff 		}
43893b3a8eb9SGleb Smirnoff 		| MAXSRCSTATES NUMBER			{
43903b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
43913b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
43923b3a8eb9SGleb Smirnoff 				YYERROR;
43933b3a8eb9SGleb Smirnoff 			}
43943b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
43953b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
43963b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
43973b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_STATES;
43983b3a8eb9SGleb Smirnoff 			$$->data.max_src_states = $2;
43993b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44003b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44013b3a8eb9SGleb Smirnoff 		}
44023b3a8eb9SGleb Smirnoff 		| MAXSRCCONN NUMBER			{
44033b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
44043b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
44053b3a8eb9SGleb Smirnoff 				YYERROR;
44063b3a8eb9SGleb Smirnoff 			}
44073b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
44083b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
44093b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
44103b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_CONN;
44113b3a8eb9SGleb Smirnoff 			$$->data.max_src_conn = $2;
44123b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44133b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44143b3a8eb9SGleb Smirnoff 		}
44153b3a8eb9SGleb Smirnoff 		| MAXSRCCONNRATE NUMBER '/' NUMBER	{
44163b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX ||
44173b3a8eb9SGleb Smirnoff 			    $4 < 0 || $4 > UINT_MAX) {
44183b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
44193b3a8eb9SGleb Smirnoff 				YYERROR;
44203b3a8eb9SGleb Smirnoff 			}
44213b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
44223b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
44233b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
44243b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
44253b3a8eb9SGleb Smirnoff 			$$->data.max_src_conn_rate.limit = $2;
44263b3a8eb9SGleb Smirnoff 			$$->data.max_src_conn_rate.seconds = $4;
44273b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44283b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44293b3a8eb9SGleb Smirnoff 		}
44303b3a8eb9SGleb Smirnoff 		| OVERLOAD '<' STRING '>' flush		{
44313b3a8eb9SGleb Smirnoff 			if (strlen($3) >= PF_TABLE_NAME_SIZE) {
44323b3a8eb9SGleb Smirnoff 				yyerror("table name '%s' too long", $3);
44333b3a8eb9SGleb Smirnoff 				free($3);
44343b3a8eb9SGleb Smirnoff 				YYERROR;
44353b3a8eb9SGleb Smirnoff 			}
44363b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
44373b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
44383b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
44393b3a8eb9SGleb Smirnoff 			if (strlcpy($$->data.overload.tblname, $3,
44403b3a8eb9SGleb Smirnoff 			    PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
44413b3a8eb9SGleb Smirnoff 				errx(1, "state_opt_item: strlcpy");
44423b3a8eb9SGleb Smirnoff 			free($3);
44433b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_OVERLOAD;
44443b3a8eb9SGleb Smirnoff 			$$->data.overload.flush = $5;
44453b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44463b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44473b3a8eb9SGleb Smirnoff 		}
44483b3a8eb9SGleb Smirnoff 		| MAXSRCNODES NUMBER			{
44493b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
44503b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
44513b3a8eb9SGleb Smirnoff 				YYERROR;
44523b3a8eb9SGleb Smirnoff 			}
44533b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
44543b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
44553b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
44563b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_MAX_SRC_NODES;
44573b3a8eb9SGleb Smirnoff 			$$->data.max_src_nodes = $2;
44583b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44593b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44603b3a8eb9SGleb Smirnoff 		}
44613b3a8eb9SGleb Smirnoff 		| sourcetrack {
44623b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
44633b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
44643b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
44653b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_SRCTRACK;
44663b3a8eb9SGleb Smirnoff 			$$->data.src_track = $1;
44673b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44683b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44693b3a8eb9SGleb Smirnoff 		}
44703b3a8eb9SGleb Smirnoff 		| statelock {
44713b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
44723b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
44733b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
44743b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_STATELOCK;
44753b3a8eb9SGleb Smirnoff 			$$->data.statelock = $1;
44763b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44773b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44783b3a8eb9SGleb Smirnoff 		}
44793b3a8eb9SGleb Smirnoff 		| SLOPPY {
44803b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
44813b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
44823b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
44833b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_SLOPPY;
44843b3a8eb9SGleb Smirnoff 			$$->next = NULL;
44853b3a8eb9SGleb Smirnoff 			$$->tail = $$;
44863b3a8eb9SGleb Smirnoff 		}
4487baf9b6d0SKristof Provost 		| PFLOW {
4488baf9b6d0SKristof Provost 			$$ = calloc(1, sizeof(struct node_state_opt));
4489baf9b6d0SKristof Provost 			if ($$ == NULL)
4490baf9b6d0SKristof Provost 				err(1, "state_opt_item: calloc");
4491baf9b6d0SKristof Provost 			$$->type = PF_STATE_OPT_PFLOW;
4492baf9b6d0SKristof Provost 			$$->next = NULL;
4493baf9b6d0SKristof Provost 			$$->tail = $$;
4494baf9b6d0SKristof Provost 		}
4495e4f2733dSKristof Provost 		| ALLOW_RELATED {
4496e4f2733dSKristof Provost 			$$ = calloc(1, sizeof(struct node_state_opt));
4497e4f2733dSKristof Provost 			if ($$ == NULL)
4498e4f2733dSKristof Provost 				err(1, "state_opt_item: calloc");
4499e4f2733dSKristof Provost 			$$->type = PF_STATE_OPT_ALLOW_RELATED;
4500e4f2733dSKristof Provost 			$$->next = NULL;
4501e4f2733dSKristof Provost 			$$->tail = $$;
4502e4f2733dSKristof Provost 		}
45033b3a8eb9SGleb Smirnoff 		| STRING NUMBER			{
45043b3a8eb9SGleb Smirnoff 			int	i;
45053b3a8eb9SGleb Smirnoff 
45063b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
45073b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
45083b3a8eb9SGleb Smirnoff 				YYERROR;
45093b3a8eb9SGleb Smirnoff 			}
45103b3a8eb9SGleb Smirnoff 			for (i = 0; pf_timeouts[i].name &&
45113b3a8eb9SGleb Smirnoff 			    strcmp(pf_timeouts[i].name, $1); ++i)
45123b3a8eb9SGleb Smirnoff 				;	/* nothing */
45133b3a8eb9SGleb Smirnoff 			if (!pf_timeouts[i].name) {
45143b3a8eb9SGleb Smirnoff 				yyerror("illegal timeout name %s", $1);
45153b3a8eb9SGleb Smirnoff 				free($1);
45163b3a8eb9SGleb Smirnoff 				YYERROR;
45173b3a8eb9SGleb Smirnoff 			}
45183b3a8eb9SGleb Smirnoff 			if (strchr(pf_timeouts[i].name, '.') == NULL) {
45193b3a8eb9SGleb Smirnoff 				yyerror("illegal state timeout %s", $1);
45203b3a8eb9SGleb Smirnoff 				free($1);
45213b3a8eb9SGleb Smirnoff 				YYERROR;
45223b3a8eb9SGleb Smirnoff 			}
45233b3a8eb9SGleb Smirnoff 			free($1);
45243b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_state_opt));
45253b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
45263b3a8eb9SGleb Smirnoff 				err(1, "state_opt_item: calloc");
45273b3a8eb9SGleb Smirnoff 			$$->type = PF_STATE_OPT_TIMEOUT;
45283b3a8eb9SGleb Smirnoff 			$$->data.timeout.number = pf_timeouts[i].timeout;
45293b3a8eb9SGleb Smirnoff 			$$->data.timeout.seconds = $2;
45303b3a8eb9SGleb Smirnoff 			$$->next = NULL;
45313b3a8eb9SGleb Smirnoff 			$$->tail = $$;
45323b3a8eb9SGleb Smirnoff 		}
45333b3a8eb9SGleb Smirnoff 		;
45343b3a8eb9SGleb Smirnoff 
45353b3a8eb9SGleb Smirnoff label		: LABEL STRING			{
45363b3a8eb9SGleb Smirnoff 			$$ = $2;
45373b3a8eb9SGleb Smirnoff 		}
45383b3a8eb9SGleb Smirnoff 		;
45393b3a8eb9SGleb Smirnoff 
45402b29ceb8SKristof Provost etherqname	: QUEUE STRING				{
45412b29ceb8SKristof Provost 			$$.qname = $2;
45422b29ceb8SKristof Provost 		}
45432b29ceb8SKristof Provost 		| QUEUE '(' STRING ')'			{
45442b29ceb8SKristof Provost 			$$.qname = $3;
45452b29ceb8SKristof Provost 		}
45462b29ceb8SKristof Provost 		;
45472b29ceb8SKristof Provost 
45483b3a8eb9SGleb Smirnoff qname		: QUEUE STRING				{
45493b3a8eb9SGleb Smirnoff 			$$.qname = $2;
45503b3a8eb9SGleb Smirnoff 			$$.pqname = NULL;
45513b3a8eb9SGleb Smirnoff 		}
45523b3a8eb9SGleb Smirnoff 		| QUEUE '(' STRING ')'			{
45533b3a8eb9SGleb Smirnoff 			$$.qname = $3;
45543b3a8eb9SGleb Smirnoff 			$$.pqname = NULL;
45553b3a8eb9SGleb Smirnoff 		}
45563b3a8eb9SGleb Smirnoff 		| QUEUE '(' STRING comma STRING ')'	{
45573b3a8eb9SGleb Smirnoff 			$$.qname = $3;
45583b3a8eb9SGleb Smirnoff 			$$.pqname = $5;
45593b3a8eb9SGleb Smirnoff 		}
45603b3a8eb9SGleb Smirnoff 		;
45613b3a8eb9SGleb Smirnoff 
45623b3a8eb9SGleb Smirnoff no		: /* empty */			{ $$ = 0; }
45633b3a8eb9SGleb Smirnoff 		| NO				{ $$ = 1; }
45643b3a8eb9SGleb Smirnoff 		;
45653b3a8eb9SGleb Smirnoff 
45663b3a8eb9SGleb Smirnoff portstar	: numberstring			{
45673b3a8eb9SGleb Smirnoff 			if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) {
45683b3a8eb9SGleb Smirnoff 				free($1);
45693b3a8eb9SGleb Smirnoff 				YYERROR;
45703b3a8eb9SGleb Smirnoff 			}
45713b3a8eb9SGleb Smirnoff 			free($1);
45723b3a8eb9SGleb Smirnoff 		}
45733b3a8eb9SGleb Smirnoff 		;
45743b3a8eb9SGleb Smirnoff 
45753b3a8eb9SGleb Smirnoff redirspec	: host				{ $$ = $1; }
45763b3a8eb9SGleb Smirnoff 		| '{' optnl redir_host_list '}'	{ $$ = $3; }
45773b3a8eb9SGleb Smirnoff 		;
45783b3a8eb9SGleb Smirnoff 
45793b3a8eb9SGleb Smirnoff redir_host_list	: host optnl			{ $$ = $1; }
45803b3a8eb9SGleb Smirnoff 		| redir_host_list comma host optnl {
45813b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
45823b3a8eb9SGleb Smirnoff 			$1->tail = $3->tail;
45833b3a8eb9SGleb Smirnoff 			$$ = $1;
45843b3a8eb9SGleb Smirnoff 		}
45853b3a8eb9SGleb Smirnoff 		;
45863b3a8eb9SGleb Smirnoff 
45873b3a8eb9SGleb Smirnoff redirpool	: /* empty */			{ $$ = NULL; }
45883b3a8eb9SGleb Smirnoff 		| ARROW redirspec		{
45893b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
45903b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
45913b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
45923b3a8eb9SGleb Smirnoff 			$$->host = $2;
45933b3a8eb9SGleb Smirnoff 			$$->rport.a = $$->rport.b = $$->rport.t = 0;
45943b3a8eb9SGleb Smirnoff 		}
45953b3a8eb9SGleb Smirnoff 		| ARROW redirspec PORT portstar	{
45963b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
45973b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
45983b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
45993b3a8eb9SGleb Smirnoff 			$$->host = $2;
46003b3a8eb9SGleb Smirnoff 			$$->rport = $4;
46013b3a8eb9SGleb Smirnoff 		}
46023b3a8eb9SGleb Smirnoff 		;
46033b3a8eb9SGleb Smirnoff 
46043b3a8eb9SGleb Smirnoff hashkey		: /* empty */
46053b3a8eb9SGleb Smirnoff 		{
46063b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct pf_poolhashkey));
46073b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
46083b3a8eb9SGleb Smirnoff 				err(1, "hashkey: calloc");
46093b3a8eb9SGleb Smirnoff 			$$->key32[0] = arc4random();
46103b3a8eb9SGleb Smirnoff 			$$->key32[1] = arc4random();
46113b3a8eb9SGleb Smirnoff 			$$->key32[2] = arc4random();
46123b3a8eb9SGleb Smirnoff 			$$->key32[3] = arc4random();
46133b3a8eb9SGleb Smirnoff 		}
46143b3a8eb9SGleb Smirnoff 		| string
46153b3a8eb9SGleb Smirnoff 		{
46163b3a8eb9SGleb Smirnoff 			if (!strncmp($1, "0x", 2)) {
46173b3a8eb9SGleb Smirnoff 				if (strlen($1) != 34) {
46183b3a8eb9SGleb Smirnoff 					free($1);
46193b3a8eb9SGleb Smirnoff 					yyerror("hex key must be 128 bits "
46203b3a8eb9SGleb Smirnoff 						"(32 hex digits) long");
46213b3a8eb9SGleb Smirnoff 					YYERROR;
46223b3a8eb9SGleb Smirnoff 				}
46233b3a8eb9SGleb Smirnoff 				$$ = calloc(1, sizeof(struct pf_poolhashkey));
46243b3a8eb9SGleb Smirnoff 				if ($$ == NULL)
46253b3a8eb9SGleb Smirnoff 					err(1, "hashkey: calloc");
46263b3a8eb9SGleb Smirnoff 
46273b3a8eb9SGleb Smirnoff 				if (sscanf($1, "0x%8x%8x%8x%8x",
46283b3a8eb9SGleb Smirnoff 				    &$$->key32[0], &$$->key32[1],
46293b3a8eb9SGleb Smirnoff 				    &$$->key32[2], &$$->key32[3]) != 4) {
46303b3a8eb9SGleb Smirnoff 					free($$);
46313b3a8eb9SGleb Smirnoff 					free($1);
46323b3a8eb9SGleb Smirnoff 					yyerror("invalid hex key");
46333b3a8eb9SGleb Smirnoff 					YYERROR;
46343b3a8eb9SGleb Smirnoff 				}
46353b3a8eb9SGleb Smirnoff 			} else {
46363b3a8eb9SGleb Smirnoff 				MD5_CTX	context;
46373b3a8eb9SGleb Smirnoff 
46383b3a8eb9SGleb Smirnoff 				$$ = calloc(1, sizeof(struct pf_poolhashkey));
46393b3a8eb9SGleb Smirnoff 				if ($$ == NULL)
46403b3a8eb9SGleb Smirnoff 					err(1, "hashkey: calloc");
46413b3a8eb9SGleb Smirnoff 				MD5Init(&context);
46423b3a8eb9SGleb Smirnoff 				MD5Update(&context, (unsigned char *)$1,
46433b3a8eb9SGleb Smirnoff 				    strlen($1));
46443b3a8eb9SGleb Smirnoff 				MD5Final((unsigned char *)$$, &context);
46453b3a8eb9SGleb Smirnoff 				HTONL($$->key32[0]);
46463b3a8eb9SGleb Smirnoff 				HTONL($$->key32[1]);
46473b3a8eb9SGleb Smirnoff 				HTONL($$->key32[2]);
46483b3a8eb9SGleb Smirnoff 				HTONL($$->key32[3]);
46493b3a8eb9SGleb Smirnoff 			}
46503b3a8eb9SGleb Smirnoff 			free($1);
46513b3a8eb9SGleb Smirnoff 		}
46523b3a8eb9SGleb Smirnoff 		;
46533b3a8eb9SGleb Smirnoff 
46543b3a8eb9SGleb Smirnoff pool_opts	:	{ bzero(&pool_opts, sizeof pool_opts); }
46553b3a8eb9SGleb Smirnoff 		    pool_opts_l
46563b3a8eb9SGleb Smirnoff 			{ $$ = pool_opts; }
46573b3a8eb9SGleb Smirnoff 		| /* empty */	{
46583b3a8eb9SGleb Smirnoff 			bzero(&pool_opts, sizeof pool_opts);
46593b3a8eb9SGleb Smirnoff 			$$ = pool_opts;
46603b3a8eb9SGleb Smirnoff 		}
46613b3a8eb9SGleb Smirnoff 		;
46623b3a8eb9SGleb Smirnoff 
46633b3a8eb9SGleb Smirnoff pool_opts_l	: pool_opts_l pool_opt
46643b3a8eb9SGleb Smirnoff 		| pool_opt
46653b3a8eb9SGleb Smirnoff 		;
46663b3a8eb9SGleb Smirnoff 
46673b3a8eb9SGleb Smirnoff pool_opt	: BITMASK	{
46683b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
46693b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
46703b3a8eb9SGleb Smirnoff 				YYERROR;
46713b3a8eb9SGleb Smirnoff 			}
46723b3a8eb9SGleb Smirnoff 			pool_opts.type =  PF_POOL_BITMASK;
46733b3a8eb9SGleb Smirnoff 		}
46743b3a8eb9SGleb Smirnoff 		| RANDOM	{
46753b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
46763b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
46773b3a8eb9SGleb Smirnoff 				YYERROR;
46783b3a8eb9SGleb Smirnoff 			}
46793b3a8eb9SGleb Smirnoff 			pool_opts.type = PF_POOL_RANDOM;
46803b3a8eb9SGleb Smirnoff 		}
46813b3a8eb9SGleb Smirnoff 		| SOURCEHASH hashkey {
46823b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
46833b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
46843b3a8eb9SGleb Smirnoff 				YYERROR;
46853b3a8eb9SGleb Smirnoff 			}
46863b3a8eb9SGleb Smirnoff 			pool_opts.type = PF_POOL_SRCHASH;
46873b3a8eb9SGleb Smirnoff 			pool_opts.key = $2;
46883b3a8eb9SGleb Smirnoff 		}
46893b3a8eb9SGleb Smirnoff 		| ROUNDROBIN	{
46903b3a8eb9SGleb Smirnoff 			if (pool_opts.type) {
46913b3a8eb9SGleb Smirnoff 				yyerror("pool type cannot be redefined");
46923b3a8eb9SGleb Smirnoff 				YYERROR;
46933b3a8eb9SGleb Smirnoff 			}
46943b3a8eb9SGleb Smirnoff 			pool_opts.type = PF_POOL_ROUNDROBIN;
46953b3a8eb9SGleb Smirnoff 		}
46963b3a8eb9SGleb Smirnoff 		| STATICPORT	{
46973b3a8eb9SGleb Smirnoff 			if (pool_opts.staticport) {
46983b3a8eb9SGleb Smirnoff 				yyerror("static-port cannot be redefined");
46993b3a8eb9SGleb Smirnoff 				YYERROR;
47003b3a8eb9SGleb Smirnoff 			}
47013b3a8eb9SGleb Smirnoff 			pool_opts.staticport = 1;
47023b3a8eb9SGleb Smirnoff 		}
47033b3a8eb9SGleb Smirnoff 		| STICKYADDRESS	{
47041e73fbd8SFranco Fichtner 			if (pool_opts.marker & POM_STICKYADDRESS) {
47053b3a8eb9SGleb Smirnoff 				yyerror("sticky-address cannot be redefined");
47063b3a8eb9SGleb Smirnoff 				YYERROR;
47073b3a8eb9SGleb Smirnoff 			}
47083b3a8eb9SGleb Smirnoff 			pool_opts.marker |= POM_STICKYADDRESS;
47093b3a8eb9SGleb Smirnoff 			pool_opts.opts |= PF_POOL_STICKYADDR;
47103b3a8eb9SGleb Smirnoff 		}
4711390dc369STom Jones 		| ENDPI {
4712390dc369STom Jones 			if (pool_opts.marker & POM_ENDPI) {
4713390dc369STom Jones 				yyerror("endpoint-independent cannot be redefined");
4714390dc369STom Jones 				YYERROR;
4715390dc369STom Jones 			}
4716390dc369STom Jones 			pool_opts.marker |= POM_ENDPI;
4717390dc369STom Jones 			pool_opts.opts |= PF_POOL_ENDPI;
4718390dc369STom Jones 		}
47192aa21096SKurosawa Takahiro 		| MAPEPORTSET number '/' number '/' number {
47202aa21096SKurosawa Takahiro 			if (pool_opts.mape.offset) {
47212aa21096SKurosawa Takahiro 				yyerror("map-e-portset cannot be redefined");
47222aa21096SKurosawa Takahiro 				YYERROR;
47232aa21096SKurosawa Takahiro 			}
47242aa21096SKurosawa Takahiro 			if (pool_opts.type) {
47252aa21096SKurosawa Takahiro 				yyerror("map-e-portset cannot be used with "
47262aa21096SKurosawa Takahiro 					"address pools");
47272aa21096SKurosawa Takahiro 				YYERROR;
47282aa21096SKurosawa Takahiro 			}
47292aa21096SKurosawa Takahiro 			if ($2 <= 0 || $2 >= 16) {
47302aa21096SKurosawa Takahiro 				yyerror("MAP-E PSID offset must be 1-15");
47312aa21096SKurosawa Takahiro 				YYERROR;
47322aa21096SKurosawa Takahiro 			}
47332aa21096SKurosawa Takahiro 			if ($4 < 0 || $4 >= 16 || $2 + $4 > 16) {
47342aa21096SKurosawa Takahiro 				yyerror("Invalid MAP-E PSID length");
47352aa21096SKurosawa Takahiro 				YYERROR;
47362aa21096SKurosawa Takahiro 			} else if ($4 == 0) {
47372aa21096SKurosawa Takahiro 				yyerror("PSID Length = 0: this means"
47382aa21096SKurosawa Takahiro 				    " you do not need MAP-E");
47392aa21096SKurosawa Takahiro 				YYERROR;
47402aa21096SKurosawa Takahiro 			}
47412aa21096SKurosawa Takahiro 			if ($6 < 0 || $6 > 65535) {
47422aa21096SKurosawa Takahiro 				yyerror("Invalid MAP-E PSID");
47432aa21096SKurosawa Takahiro 				YYERROR;
47442aa21096SKurosawa Takahiro 			}
47452aa21096SKurosawa Takahiro 			pool_opts.mape.offset = $2;
47462aa21096SKurosawa Takahiro 			pool_opts.mape.psidlen = $4;
47472aa21096SKurosawa Takahiro 			pool_opts.mape.psid = $6;
47482aa21096SKurosawa Takahiro 		}
47493b3a8eb9SGleb Smirnoff 		;
47503b3a8eb9SGleb Smirnoff 
47513b3a8eb9SGleb Smirnoff redirection	: /* empty */			{ $$ = NULL; }
47523b3a8eb9SGleb Smirnoff 		| ARROW host			{
47533b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
47543b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
47553b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
47563b3a8eb9SGleb Smirnoff 			$$->host = $2;
47573b3a8eb9SGleb Smirnoff 			$$->rport.a = $$->rport.b = $$->rport.t = 0;
47583b3a8eb9SGleb Smirnoff 		}
47593b3a8eb9SGleb Smirnoff 		| ARROW host PORT portstar	{
47603b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct redirection));
47613b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
47623b3a8eb9SGleb Smirnoff 				err(1, "redirection: calloc");
47633b3a8eb9SGleb Smirnoff 			$$->host = $2;
47643b3a8eb9SGleb Smirnoff 			$$->rport = $4;
47653b3a8eb9SGleb Smirnoff 		}
47663b3a8eb9SGleb Smirnoff 		;
47673b3a8eb9SGleb Smirnoff 
47683b3a8eb9SGleb Smirnoff natpasslog	: /* empty */	{ $$.b1 = $$.b2 = 0; $$.w2 = 0; }
47693b3a8eb9SGleb Smirnoff 		| PASS		{ $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
47703b3a8eb9SGleb Smirnoff 		| PASS log	{ $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
47713b3a8eb9SGleb Smirnoff 		| log		{ $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
47723b3a8eb9SGleb Smirnoff 		;
47733b3a8eb9SGleb Smirnoff 
47743b3a8eb9SGleb Smirnoff nataction	: no NAT natpasslog {
47753b3a8eb9SGleb Smirnoff 			if ($1 && $3.b1) {
47763b3a8eb9SGleb Smirnoff 				yyerror("\"pass\" not valid with \"no\"");
47773b3a8eb9SGleb Smirnoff 				YYERROR;
47783b3a8eb9SGleb Smirnoff 			}
47793b3a8eb9SGleb Smirnoff 			if ($1)
47803b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NONAT;
47813b3a8eb9SGleb Smirnoff 			else
47823b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NAT;
47833b3a8eb9SGleb Smirnoff 			$$.b2 = $3.b1;
47843b3a8eb9SGleb Smirnoff 			$$.w = $3.b2;
47853b3a8eb9SGleb Smirnoff 			$$.w2 = $3.w2;
47863b3a8eb9SGleb Smirnoff 		}
47873b3a8eb9SGleb Smirnoff 		| no RDR natpasslog {
47883b3a8eb9SGleb Smirnoff 			if ($1 && $3.b1) {
47893b3a8eb9SGleb Smirnoff 				yyerror("\"pass\" not valid with \"no\"");
47903b3a8eb9SGleb Smirnoff 				YYERROR;
47913b3a8eb9SGleb Smirnoff 			}
47923b3a8eb9SGleb Smirnoff 			if ($1)
47933b3a8eb9SGleb Smirnoff 				$$.b1 = PF_NORDR;
47943b3a8eb9SGleb Smirnoff 			else
47953b3a8eb9SGleb Smirnoff 				$$.b1 = PF_RDR;
47963b3a8eb9SGleb Smirnoff 			$$.b2 = $3.b1;
47973b3a8eb9SGleb Smirnoff 			$$.w = $3.b2;
47983b3a8eb9SGleb Smirnoff 			$$.w2 = $3.w2;
47993b3a8eb9SGleb Smirnoff 		}
48003b3a8eb9SGleb Smirnoff 		;
48013b3a8eb9SGleb Smirnoff 
48023b3a8eb9SGleb Smirnoff natrule		: nataction interface af proto fromto tag tagged rtable
48033b3a8eb9SGleb Smirnoff 		    redirpool pool_opts
48043b3a8eb9SGleb Smirnoff 		{
4805e9eb0941SKristof Provost 			struct pfctl_rule	r;
4806fc6e5069SKristof Provost 			struct node_state_opt	*o;
48073b3a8eb9SGleb Smirnoff 
48083b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT))
48093b3a8eb9SGleb Smirnoff 				YYERROR;
48103b3a8eb9SGleb Smirnoff 
48113b3a8eb9SGleb Smirnoff 			memset(&r, 0, sizeof(r));
48123b3a8eb9SGleb Smirnoff 
48133b3a8eb9SGleb Smirnoff 			r.action = $1.b1;
48143b3a8eb9SGleb Smirnoff 			r.natpass = $1.b2;
48153b3a8eb9SGleb Smirnoff 			r.log = $1.w;
48163b3a8eb9SGleb Smirnoff 			r.logif = $1.w2;
48173b3a8eb9SGleb Smirnoff 			r.af = $3;
48183b3a8eb9SGleb Smirnoff 
48193b3a8eb9SGleb Smirnoff 			if (!r.af) {
48203b3a8eb9SGleb Smirnoff 				if ($5.src.host && $5.src.host->af &&
48213b3a8eb9SGleb Smirnoff 				    !$5.src.host->ifindex)
48223b3a8eb9SGleb Smirnoff 					r.af = $5.src.host->af;
48233b3a8eb9SGleb Smirnoff 				else if ($5.dst.host && $5.dst.host->af &&
48243b3a8eb9SGleb Smirnoff 				    !$5.dst.host->ifindex)
48253b3a8eb9SGleb Smirnoff 					r.af = $5.dst.host->af;
48263b3a8eb9SGleb Smirnoff 			}
48273b3a8eb9SGleb Smirnoff 
48283b3a8eb9SGleb Smirnoff 			if ($6 != NULL)
48293b3a8eb9SGleb Smirnoff 				if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
48303b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) {
48313b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
48323b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
48333b3a8eb9SGleb Smirnoff 					YYERROR;
48343b3a8eb9SGleb Smirnoff 				}
48353b3a8eb9SGleb Smirnoff 
48363b3a8eb9SGleb Smirnoff 			if ($7.name)
48373b3a8eb9SGleb Smirnoff 				if (strlcpy(r.match_tagname, $7.name,
48383b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
48393b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
48403b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
48413b3a8eb9SGleb Smirnoff 					YYERROR;
48423b3a8eb9SGleb Smirnoff 				}
48433b3a8eb9SGleb Smirnoff 			r.match_tag_not = $7.neg;
48443b3a8eb9SGleb Smirnoff 			r.rtableid = $8;
48453b3a8eb9SGleb Smirnoff 
48463b3a8eb9SGleb Smirnoff 			if (r.action == PF_NONAT || r.action == PF_NORDR) {
48473b3a8eb9SGleb Smirnoff 				if ($9 != NULL) {
48483b3a8eb9SGleb Smirnoff 					yyerror("translation rule with 'no' "
48493b3a8eb9SGleb Smirnoff 					    "does not need '->'");
48503b3a8eb9SGleb Smirnoff 					YYERROR;
48513b3a8eb9SGleb Smirnoff 				}
48523b3a8eb9SGleb Smirnoff 			} else {
48533b3a8eb9SGleb Smirnoff 				if ($9 == NULL || $9->host == NULL) {
48543b3a8eb9SGleb Smirnoff 					yyerror("translation rule requires '-> "
48553b3a8eb9SGleb Smirnoff 					    "address'");
48563b3a8eb9SGleb Smirnoff 					YYERROR;
48573b3a8eb9SGleb Smirnoff 				}
48583b3a8eb9SGleb Smirnoff 				if (!r.af && ! $9->host->ifindex)
48593b3a8eb9SGleb Smirnoff 					r.af = $9->host->af;
48603b3a8eb9SGleb Smirnoff 
48613b3a8eb9SGleb Smirnoff 				remove_invalid_hosts(&$9->host, &r.af);
48623b3a8eb9SGleb Smirnoff 				if (invalid_redirect($9->host, r.af))
48633b3a8eb9SGleb Smirnoff 					YYERROR;
48647ce98cf2SKristof Provost 				if ($9->host->addr.type == PF_ADDR_DYNIFTL) {
48657ce98cf2SKristof Provost 					if (($9->host = gen_dynnode($9->host, r.af)) == NULL)
48667ce98cf2SKristof Provost 						err(1, "calloc");
48677ce98cf2SKristof Provost 				}
48683b3a8eb9SGleb Smirnoff 				if (check_netmask($9->host, r.af))
48693b3a8eb9SGleb Smirnoff 					YYERROR;
48703b3a8eb9SGleb Smirnoff 
4871096efeb6SKristof Provost 				r.rdr.proxy_port[0] = ntohs($9->rport.a);
48723b3a8eb9SGleb Smirnoff 
48733b3a8eb9SGleb Smirnoff 				switch (r.action) {
48743b3a8eb9SGleb Smirnoff 				case PF_RDR:
48753b3a8eb9SGleb Smirnoff 					if (!$9->rport.b && $9->rport.t &&
48763b3a8eb9SGleb Smirnoff 					    $5.dst.port != NULL) {
4877096efeb6SKristof Provost 						r.rdr.proxy_port[1] =
48783b3a8eb9SGleb Smirnoff 						    ntohs($9->rport.a) +
48793b3a8eb9SGleb Smirnoff 						    (ntohs(
48803b3a8eb9SGleb Smirnoff 						    $5.dst.port->port[1]) -
48813b3a8eb9SGleb Smirnoff 						    ntohs(
48823b3a8eb9SGleb Smirnoff 						    $5.dst.port->port[0]));
48833b3a8eb9SGleb Smirnoff 					} else
4884096efeb6SKristof Provost 						r.rdr.proxy_port[1] =
48853b3a8eb9SGleb Smirnoff 						    ntohs($9->rport.b);
48863b3a8eb9SGleb Smirnoff 					break;
48873b3a8eb9SGleb Smirnoff 				case PF_NAT:
4888096efeb6SKristof Provost 					r.rdr.proxy_port[1] =
48893b3a8eb9SGleb Smirnoff 					    ntohs($9->rport.b);
4890096efeb6SKristof Provost 					if (!r.rdr.proxy_port[0] &&
4891096efeb6SKristof Provost 					    !r.rdr.proxy_port[1]) {
4892096efeb6SKristof Provost 						r.rdr.proxy_port[0] =
48933b3a8eb9SGleb Smirnoff 						    PF_NAT_PROXY_PORT_LOW;
4894096efeb6SKristof Provost 						r.rdr.proxy_port[1] =
48953b3a8eb9SGleb Smirnoff 						    PF_NAT_PROXY_PORT_HIGH;
4896096efeb6SKristof Provost 					} else if (!r.rdr.proxy_port[1])
4897096efeb6SKristof Provost 						r.rdr.proxy_port[1] =
4898096efeb6SKristof Provost 						    r.rdr.proxy_port[0];
48993b3a8eb9SGleb Smirnoff 					break;
49003b3a8eb9SGleb Smirnoff 				default:
49013b3a8eb9SGleb Smirnoff 					break;
49023b3a8eb9SGleb Smirnoff 				}
49033b3a8eb9SGleb Smirnoff 
4904096efeb6SKristof Provost 				r.rdr.opts = $10.type;
4905096efeb6SKristof Provost 				if ((r.rdr.opts & PF_POOL_TYPEMASK) ==
49063b3a8eb9SGleb Smirnoff 				    PF_POOL_NONE && ($9->host->next != NULL ||
49073b3a8eb9SGleb Smirnoff 				    $9->host->addr.type == PF_ADDR_TABLE ||
49083b3a8eb9SGleb Smirnoff 				    DYNIF_MULTIADDR($9->host->addr)))
4909096efeb6SKristof Provost 					r.rdr.opts = PF_POOL_ROUNDROBIN;
4910096efeb6SKristof Provost 				if ((r.rdr.opts & PF_POOL_TYPEMASK) !=
49113b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
49123b3a8eb9SGleb Smirnoff 				    disallow_table($9->host, "tables are only "
49133b3a8eb9SGleb Smirnoff 				    "supported in round-robin redirection "
49143b3a8eb9SGleb Smirnoff 				    "pools"))
49153b3a8eb9SGleb Smirnoff 					YYERROR;
4916096efeb6SKristof Provost 				if ((r.rdr.opts & PF_POOL_TYPEMASK) !=
49173b3a8eb9SGleb Smirnoff 				    PF_POOL_ROUNDROBIN &&
49183b3a8eb9SGleb Smirnoff 				    disallow_alias($9->host, "interface (%s) "
49193b3a8eb9SGleb Smirnoff 				    "is only supported in round-robin "
49203b3a8eb9SGleb Smirnoff 				    "redirection pools"))
49213b3a8eb9SGleb Smirnoff 					YYERROR;
49223b3a8eb9SGleb Smirnoff 				if ($9->host->next != NULL) {
4923096efeb6SKristof Provost 					if ((r.rdr.opts & PF_POOL_TYPEMASK) !=
49243b3a8eb9SGleb Smirnoff 					    PF_POOL_ROUNDROBIN) {
49253b3a8eb9SGleb Smirnoff 						yyerror("only round-robin "
49263b3a8eb9SGleb Smirnoff 						    "valid for multiple "
49273b3a8eb9SGleb Smirnoff 						    "redirection addresses");
49283b3a8eb9SGleb Smirnoff 						YYERROR;
49293b3a8eb9SGleb Smirnoff 					}
49303b3a8eb9SGleb Smirnoff 				}
49313b3a8eb9SGleb Smirnoff 			}
49323b3a8eb9SGleb Smirnoff 
49333b3a8eb9SGleb Smirnoff 			if ($10.key != NULL)
4934096efeb6SKristof Provost 				memcpy(&r.rdr.key, $10.key,
49353b3a8eb9SGleb Smirnoff 				    sizeof(struct pf_poolhashkey));
49363b3a8eb9SGleb Smirnoff 
49373b3a8eb9SGleb Smirnoff 			 if ($10.opts)
4938096efeb6SKristof Provost 				r.rdr.opts |= $10.opts;
49393b3a8eb9SGleb Smirnoff 
49403b3a8eb9SGleb Smirnoff 			if ($10.staticport) {
49413b3a8eb9SGleb Smirnoff 				if (r.action != PF_NAT) {
49423b3a8eb9SGleb Smirnoff 					yyerror("the 'static-port' option is "
49433b3a8eb9SGleb Smirnoff 					    "only valid with nat rules");
49443b3a8eb9SGleb Smirnoff 					YYERROR;
49453b3a8eb9SGleb Smirnoff 				}
4946096efeb6SKristof Provost 				if (r.rdr.proxy_port[0] !=
49473b3a8eb9SGleb Smirnoff 				    PF_NAT_PROXY_PORT_LOW &&
4948096efeb6SKristof Provost 				    r.rdr.proxy_port[1] !=
49493b3a8eb9SGleb Smirnoff 				    PF_NAT_PROXY_PORT_HIGH) {
49503b3a8eb9SGleb Smirnoff 					yyerror("the 'static-port' option can't"
49513b3a8eb9SGleb Smirnoff 					    " be used when specifying a port"
49523b3a8eb9SGleb Smirnoff 					    " range");
49533b3a8eb9SGleb Smirnoff 					YYERROR;
49543b3a8eb9SGleb Smirnoff 				}
4955096efeb6SKristof Provost 				r.rdr.proxy_port[0] = 0;
4956096efeb6SKristof Provost 				r.rdr.proxy_port[1] = 0;
49573b3a8eb9SGleb Smirnoff 			}
49583b3a8eb9SGleb Smirnoff 
49592aa21096SKurosawa Takahiro 			if ($10.mape.offset) {
49602aa21096SKurosawa Takahiro 				if (r.action != PF_NAT) {
49612aa21096SKurosawa Takahiro 					yyerror("the 'map-e-portset' option is"
49622aa21096SKurosawa Takahiro 					    " only valid with nat rules");
49632aa21096SKurosawa Takahiro 					YYERROR;
49642aa21096SKurosawa Takahiro 				}
49652aa21096SKurosawa Takahiro 				if ($10.staticport) {
49662aa21096SKurosawa Takahiro 					yyerror("the 'map-e-portset' option"
49672aa21096SKurosawa Takahiro 					    " can't be used 'static-port'");
49682aa21096SKurosawa Takahiro 					YYERROR;
49692aa21096SKurosawa Takahiro 				}
4970096efeb6SKristof Provost 				if (r.rdr.proxy_port[0] !=
49712aa21096SKurosawa Takahiro 				    PF_NAT_PROXY_PORT_LOW &&
4972096efeb6SKristof Provost 				    r.rdr.proxy_port[1] !=
49732aa21096SKurosawa Takahiro 				    PF_NAT_PROXY_PORT_HIGH) {
49742aa21096SKurosawa Takahiro 					yyerror("the 'map-e-portset' option"
49752aa21096SKurosawa Takahiro 					    " can't be used when specifying"
49762aa21096SKurosawa Takahiro 					    " a port range");
49772aa21096SKurosawa Takahiro 					YYERROR;
49782aa21096SKurosawa Takahiro 				}
4979096efeb6SKristof Provost 				r.rdr.mape = $10.mape;
49802aa21096SKurosawa Takahiro 			}
49812aa21096SKurosawa Takahiro 
4982fc6e5069SKristof Provost 			o = keep_state_defaults;
4983fc6e5069SKristof Provost 			while (o) {
4984fc6e5069SKristof Provost 				switch (o->type) {
4985fc6e5069SKristof Provost 				case PF_STATE_OPT_PFLOW:
4986fc6e5069SKristof Provost 					if (r.rule_flag & PFRULE_PFLOW) {
4987fc6e5069SKristof Provost 						yyerror("state pflow option: "
4988fc6e5069SKristof Provost 						    "multiple definitions");
4989fc6e5069SKristof Provost 						YYERROR;
4990fc6e5069SKristof Provost 					}
4991fc6e5069SKristof Provost 					r.rule_flag |= PFRULE_PFLOW;
4992fc6e5069SKristof Provost 					break;
4993fc6e5069SKristof Provost 				}
4994fc6e5069SKristof Provost 				o = o->next;
4995fc6e5069SKristof Provost 			}
4996fc6e5069SKristof Provost 
49970972294eSKristof Provost 			expand_rule(&r, $2, NULL, NULL, NULL,
49980972294eSKristof Provost 			    $9 == NULL ? NULL : $9->host, NULL, NULL, $4,
49990972294eSKristof Provost 			    $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
50002339ead6SKristof Provost 			    $5.dst.port, 0, 0, 0, 0, "");
50013b3a8eb9SGleb Smirnoff 			free($9);
50023b3a8eb9SGleb Smirnoff 		}
50033b3a8eb9SGleb Smirnoff 		;
50043b3a8eb9SGleb Smirnoff 
50051e93588bSLuiz Otavio O Souza binatrule	: no BINAT natpasslog interface af proto FROM ipspec toipspec tag
50063b3a8eb9SGleb Smirnoff 		    tagged rtable redirection
50073b3a8eb9SGleb Smirnoff 		{
5008e9eb0941SKristof Provost 			struct pfctl_rule	binat;
50093b3a8eb9SGleb Smirnoff 			struct pf_pooladdr	*pa;
50103b3a8eb9SGleb Smirnoff 
50113b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_NAT))
50123b3a8eb9SGleb Smirnoff 				YYERROR;
50133b3a8eb9SGleb Smirnoff 			if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
50143b3a8eb9SGleb Smirnoff 			    "permitted as a binat destination"))
50153b3a8eb9SGleb Smirnoff 				YYERROR;
50163b3a8eb9SGleb Smirnoff 
50173b3a8eb9SGleb Smirnoff 			memset(&binat, 0, sizeof(binat));
50183b3a8eb9SGleb Smirnoff 
50193b3a8eb9SGleb Smirnoff 			if ($1 && $3.b1) {
50203b3a8eb9SGleb Smirnoff 				yyerror("\"pass\" not valid with \"no\"");
50213b3a8eb9SGleb Smirnoff 				YYERROR;
50223b3a8eb9SGleb Smirnoff 			}
50233b3a8eb9SGleb Smirnoff 			if ($1)
50243b3a8eb9SGleb Smirnoff 				binat.action = PF_NOBINAT;
50253b3a8eb9SGleb Smirnoff 			else
50263b3a8eb9SGleb Smirnoff 				binat.action = PF_BINAT;
50273b3a8eb9SGleb Smirnoff 			binat.natpass = $3.b1;
50283b3a8eb9SGleb Smirnoff 			binat.log = $3.b2;
50293b3a8eb9SGleb Smirnoff 			binat.logif = $3.w2;
50303b3a8eb9SGleb Smirnoff 			binat.af = $5;
50313b3a8eb9SGleb Smirnoff 			if (!binat.af && $8 != NULL && $8->af)
50323b3a8eb9SGleb Smirnoff 				binat.af = $8->af;
50333b3a8eb9SGleb Smirnoff 			if (!binat.af && $9 != NULL && $9->af)
50343b3a8eb9SGleb Smirnoff 				binat.af = $9->af;
50353b3a8eb9SGleb Smirnoff 
50363b3a8eb9SGleb Smirnoff 			if (!binat.af && $13 != NULL && $13->host)
50373b3a8eb9SGleb Smirnoff 				binat.af = $13->host->af;
50383b3a8eb9SGleb Smirnoff 			if (!binat.af) {
50393b3a8eb9SGleb Smirnoff 				yyerror("address family (inet/inet6) "
50403b3a8eb9SGleb Smirnoff 				    "undefined");
50413b3a8eb9SGleb Smirnoff 				YYERROR;
50423b3a8eb9SGleb Smirnoff 			}
50433b3a8eb9SGleb Smirnoff 
50443b3a8eb9SGleb Smirnoff 			if ($4 != NULL) {
50453b3a8eb9SGleb Smirnoff 				memcpy(binat.ifname, $4->ifname,
50463b3a8eb9SGleb Smirnoff 				    sizeof(binat.ifname));
50473b3a8eb9SGleb Smirnoff 				binat.ifnot = $4->not;
50483b3a8eb9SGleb Smirnoff 				free($4);
50493b3a8eb9SGleb Smirnoff 			}
50503b3a8eb9SGleb Smirnoff 
50513b3a8eb9SGleb Smirnoff 			if ($10 != NULL)
50523b3a8eb9SGleb Smirnoff 				if (strlcpy(binat.tagname, $10,
50533b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
50543b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
50553b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
50563b3a8eb9SGleb Smirnoff 					YYERROR;
50573b3a8eb9SGleb Smirnoff 				}
50583b3a8eb9SGleb Smirnoff 			if ($11.name)
50593b3a8eb9SGleb Smirnoff 				if (strlcpy(binat.match_tagname, $11.name,
50603b3a8eb9SGleb Smirnoff 				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
50613b3a8eb9SGleb Smirnoff 					yyerror("tag too long, max %u chars",
50623b3a8eb9SGleb Smirnoff 					    PF_TAG_NAME_SIZE - 1);
50633b3a8eb9SGleb Smirnoff 					YYERROR;
50643b3a8eb9SGleb Smirnoff 				}
50653b3a8eb9SGleb Smirnoff 			binat.match_tag_not = $11.neg;
50663b3a8eb9SGleb Smirnoff 			binat.rtableid = $12;
50673b3a8eb9SGleb Smirnoff 
50683b3a8eb9SGleb Smirnoff 			if ($6 != NULL) {
50693b3a8eb9SGleb Smirnoff 				binat.proto = $6->proto;
50703b3a8eb9SGleb Smirnoff 				free($6);
50713b3a8eb9SGleb Smirnoff 			}
50723b3a8eb9SGleb Smirnoff 
50733b3a8eb9SGleb Smirnoff 			if ($8 != NULL && disallow_table($8, "invalid use of "
50743b3a8eb9SGleb Smirnoff 			    "table <%s> as the source address of a binat rule"))
50753b3a8eb9SGleb Smirnoff 				YYERROR;
50763b3a8eb9SGleb Smirnoff 			if ($8 != NULL && disallow_alias($8, "invalid use of "
50773b3a8eb9SGleb Smirnoff 			    "interface (%s) as the source address of a binat "
50783b3a8eb9SGleb Smirnoff 			    "rule"))
50793b3a8eb9SGleb Smirnoff 				YYERROR;
50803b3a8eb9SGleb Smirnoff 			if ($13 != NULL && $13->host != NULL && disallow_table(
50813b3a8eb9SGleb Smirnoff 			    $13->host, "invalid use of table <%s> as the "
50823b3a8eb9SGleb Smirnoff 			    "redirect address of a binat rule"))
50833b3a8eb9SGleb Smirnoff 				YYERROR;
50843b3a8eb9SGleb Smirnoff 			if ($13 != NULL && $13->host != NULL && disallow_alias(
50853b3a8eb9SGleb Smirnoff 			    $13->host, "invalid use of interface (%s) as the "
50863b3a8eb9SGleb Smirnoff 			    "redirect address of a binat rule"))
50873b3a8eb9SGleb Smirnoff 				YYERROR;
50883b3a8eb9SGleb Smirnoff 
50893b3a8eb9SGleb Smirnoff 			if ($8 != NULL) {
50903b3a8eb9SGleb Smirnoff 				if ($8->next) {
50913b3a8eb9SGleb Smirnoff 					yyerror("multiple binat ip addresses");
50923b3a8eb9SGleb Smirnoff 					YYERROR;
50933b3a8eb9SGleb Smirnoff 				}
50943b3a8eb9SGleb Smirnoff 				if ($8->addr.type == PF_ADDR_DYNIFTL)
50953b3a8eb9SGleb Smirnoff 					$8->af = binat.af;
50963b3a8eb9SGleb Smirnoff 				if ($8->af != binat.af) {
50973b3a8eb9SGleb Smirnoff 					yyerror("binat ip versions must match");
50983b3a8eb9SGleb Smirnoff 					YYERROR;
50993b3a8eb9SGleb Smirnoff 				}
51007ce98cf2SKristof Provost 				if ($8->addr.type == PF_ADDR_DYNIFTL) {
51017ce98cf2SKristof Provost 					if (($8 = gen_dynnode($8, binat.af)) == NULL)
51027ce98cf2SKristof Provost 						err(1, "calloc");
51037ce98cf2SKristof Provost 				}
51043b3a8eb9SGleb Smirnoff 				if (check_netmask($8, binat.af))
51053b3a8eb9SGleb Smirnoff 					YYERROR;
51063b3a8eb9SGleb Smirnoff 				memcpy(&binat.src.addr, &$8->addr,
51073b3a8eb9SGleb Smirnoff 				    sizeof(binat.src.addr));
51083b3a8eb9SGleb Smirnoff 				free($8);
51093b3a8eb9SGleb Smirnoff 			}
51103b3a8eb9SGleb Smirnoff 			if ($9 != NULL) {
51113b3a8eb9SGleb Smirnoff 				if ($9->next) {
51123b3a8eb9SGleb Smirnoff 					yyerror("multiple binat ip addresses");
51133b3a8eb9SGleb Smirnoff 					YYERROR;
51143b3a8eb9SGleb Smirnoff 				}
51153b3a8eb9SGleb Smirnoff 				if ($9->af != binat.af && $9->af) {
51163b3a8eb9SGleb Smirnoff 					yyerror("binat ip versions must match");
51173b3a8eb9SGleb Smirnoff 					YYERROR;
51183b3a8eb9SGleb Smirnoff 				}
51197ce98cf2SKristof Provost 				if ($9->addr.type == PF_ADDR_DYNIFTL) {
51207ce98cf2SKristof Provost 					if (($9 = gen_dynnode($9, binat.af)) == NULL)
51217ce98cf2SKristof Provost 						err(1, "calloc");
51227ce98cf2SKristof Provost 				}
51233b3a8eb9SGleb Smirnoff 				if (check_netmask($9, binat.af))
51243b3a8eb9SGleb Smirnoff 					YYERROR;
51253b3a8eb9SGleb Smirnoff 				memcpy(&binat.dst.addr, &$9->addr,
51263b3a8eb9SGleb Smirnoff 				    sizeof(binat.dst.addr));
51273b3a8eb9SGleb Smirnoff 				binat.dst.neg = $9->not;
51283b3a8eb9SGleb Smirnoff 				free($9);
51293b3a8eb9SGleb Smirnoff 			}
51303b3a8eb9SGleb Smirnoff 
51313b3a8eb9SGleb Smirnoff 			if (binat.action == PF_NOBINAT) {
51323b3a8eb9SGleb Smirnoff 				if ($13 != NULL) {
51333b3a8eb9SGleb Smirnoff 					yyerror("'no binat' rule does not need"
51343b3a8eb9SGleb Smirnoff 					    " '->'");
51353b3a8eb9SGleb Smirnoff 					YYERROR;
51363b3a8eb9SGleb Smirnoff 				}
51373b3a8eb9SGleb Smirnoff 			} else {
51383b3a8eb9SGleb Smirnoff 				if ($13 == NULL || $13->host == NULL) {
51393b3a8eb9SGleb Smirnoff 					yyerror("'binat' rule requires"
51403b3a8eb9SGleb Smirnoff 					    " '-> address'");
51413b3a8eb9SGleb Smirnoff 					YYERROR;
51423b3a8eb9SGleb Smirnoff 				}
51433b3a8eb9SGleb Smirnoff 
51443b3a8eb9SGleb Smirnoff 				remove_invalid_hosts(&$13->host, &binat.af);
51453b3a8eb9SGleb Smirnoff 				if (invalid_redirect($13->host, binat.af))
51463b3a8eb9SGleb Smirnoff 					YYERROR;
51473b3a8eb9SGleb Smirnoff 				if ($13->host->next != NULL) {
51483b3a8eb9SGleb Smirnoff 					yyerror("binat rule must redirect to "
51493b3a8eb9SGleb Smirnoff 					    "a single address");
51503b3a8eb9SGleb Smirnoff 					YYERROR;
51513b3a8eb9SGleb Smirnoff 				}
51527ce98cf2SKristof Provost 				if ($13->host->addr.type == PF_ADDR_DYNIFTL) {
51537ce98cf2SKristof Provost 					if (($13->host = gen_dynnode($13->host, binat.af)) == NULL)
51547ce98cf2SKristof Provost 						err(1, "calloc");
51557ce98cf2SKristof Provost 				}
51563b3a8eb9SGleb Smirnoff 				if (check_netmask($13->host, binat.af))
51573b3a8eb9SGleb Smirnoff 					YYERROR;
51583b3a8eb9SGleb Smirnoff 
51593b3a8eb9SGleb Smirnoff 				if (!PF_AZERO(&binat.src.addr.v.a.mask,
51603b3a8eb9SGleb Smirnoff 				    binat.af) &&
51613b3a8eb9SGleb Smirnoff 				    !PF_AEQ(&binat.src.addr.v.a.mask,
51623b3a8eb9SGleb Smirnoff 				    &$13->host->addr.v.a.mask, binat.af)) {
51633b3a8eb9SGleb Smirnoff 					yyerror("'binat' source mask and "
51643b3a8eb9SGleb Smirnoff 					    "redirect mask must be the same");
51653b3a8eb9SGleb Smirnoff 					YYERROR;
51663b3a8eb9SGleb Smirnoff 				}
51673b3a8eb9SGleb Smirnoff 
5168096efeb6SKristof Provost 				TAILQ_INIT(&binat.rdr.list);
51695cb08fddSKristof Provost 				TAILQ_INIT(&binat.nat.list);
51703b3a8eb9SGleb Smirnoff 				pa = calloc(1, sizeof(struct pf_pooladdr));
51713b3a8eb9SGleb Smirnoff 				if (pa == NULL)
51723b3a8eb9SGleb Smirnoff 					err(1, "binat: calloc");
51733b3a8eb9SGleb Smirnoff 				pa->addr = $13->host->addr;
51743b3a8eb9SGleb Smirnoff 				pa->ifname[0] = 0;
5175096efeb6SKristof Provost 				TAILQ_INSERT_TAIL(&binat.rdr.list,
51763b3a8eb9SGleb Smirnoff 				    pa, entries);
51773b3a8eb9SGleb Smirnoff 
51783b3a8eb9SGleb Smirnoff 				free($13);
51793b3a8eb9SGleb Smirnoff 			}
51803b3a8eb9SGleb Smirnoff 
51810d71f9f3SKristof Provost 			pfctl_append_rule(pf, &binat, "");
51823b3a8eb9SGleb Smirnoff 		}
51833b3a8eb9SGleb Smirnoff 		;
51843b3a8eb9SGleb Smirnoff 
51853b3a8eb9SGleb Smirnoff tag		: /* empty */		{ $$ = NULL; }
51863b3a8eb9SGleb Smirnoff 		| TAG STRING		{ $$ = $2; }
51873b3a8eb9SGleb Smirnoff 		;
51883b3a8eb9SGleb Smirnoff 
51893b3a8eb9SGleb Smirnoff tagged		: /* empty */		{ $$.neg = 0; $$.name = NULL; }
51903b3a8eb9SGleb Smirnoff 		| not TAGGED string	{ $$.neg = $1; $$.name = $3; }
51913b3a8eb9SGleb Smirnoff 		;
51923b3a8eb9SGleb Smirnoff 
51933b3a8eb9SGleb Smirnoff rtable		: /* empty */		{ $$ = -1; }
51943b3a8eb9SGleb Smirnoff 		| RTABLE NUMBER		{
51953b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > rt_tableid_max()) {
51963b3a8eb9SGleb Smirnoff 				yyerror("invalid rtable id");
51973b3a8eb9SGleb Smirnoff 				YYERROR;
51983b3a8eb9SGleb Smirnoff 			}
51993b3a8eb9SGleb Smirnoff 			$$ = $2;
52003b3a8eb9SGleb Smirnoff 		}
52013b3a8eb9SGleb Smirnoff 		;
52023b3a8eb9SGleb Smirnoff 
52033b3a8eb9SGleb Smirnoff route_host	: STRING			{
52043b3a8eb9SGleb Smirnoff 			$$ = calloc(1, sizeof(struct node_host));
52053b3a8eb9SGleb Smirnoff 			if ($$ == NULL)
52063b3a8eb9SGleb Smirnoff 				err(1, "route_host: calloc");
5207e68de669SKristof Provost 			if (strlen($1) >= IFNAMSIZ) {
5208e68de669SKristof Provost 				yyerror("interface name too long");
5209e68de669SKristof Provost 				YYERROR;
5210e68de669SKristof Provost 			}
5211a2a90d6eSKristof Provost 			$$->ifname = strdup($1);
52123b3a8eb9SGleb Smirnoff 			set_ipmask($$, 128);
52133b3a8eb9SGleb Smirnoff 			$$->next = NULL;
52143b3a8eb9SGleb Smirnoff 			$$->tail = $$;
52153b3a8eb9SGleb Smirnoff 		}
52163b3a8eb9SGleb Smirnoff 		| '(' STRING host ')'		{
521758c8430aSKristof Provost 			struct node_host *n;
521858c8430aSKristof Provost 
52193b3a8eb9SGleb Smirnoff 			$$ = $3;
5220e68de669SKristof Provost 			for (n = $3; n != NULL; n = n->next) {
5221e68de669SKristof Provost 				if (strlen($2) >= IFNAMSIZ) {
5222e68de669SKristof Provost 					yyerror("interface name too long");
5223e68de669SKristof Provost 					YYERROR;
5224e68de669SKristof Provost 				}
5225a2a90d6eSKristof Provost 				n->ifname = strdup($2);
52263b3a8eb9SGleb Smirnoff 			}
5227e68de669SKristof Provost 		}
52283b3a8eb9SGleb Smirnoff 		;
52293b3a8eb9SGleb Smirnoff 
52303b3a8eb9SGleb Smirnoff route_host_list	: route_host optnl			{ $$ = $1; }
52313b3a8eb9SGleb Smirnoff 		| route_host_list comma route_host optnl {
52323b3a8eb9SGleb Smirnoff 			if ($1->af == 0)
52333b3a8eb9SGleb Smirnoff 				$1->af = $3->af;
52343b3a8eb9SGleb Smirnoff 			if ($1->af != $3->af) {
52353b3a8eb9SGleb Smirnoff 				yyerror("all pool addresses must be in the "
52363b3a8eb9SGleb Smirnoff 				    "same address family");
52373b3a8eb9SGleb Smirnoff 				YYERROR;
52383b3a8eb9SGleb Smirnoff 			}
52393b3a8eb9SGleb Smirnoff 			$1->tail->next = $3;
52403b3a8eb9SGleb Smirnoff 			$1->tail = $3->tail;
52413b3a8eb9SGleb Smirnoff 			$$ = $1;
52423b3a8eb9SGleb Smirnoff 		}
52433b3a8eb9SGleb Smirnoff 		;
52443b3a8eb9SGleb Smirnoff 
52453b3a8eb9SGleb Smirnoff routespec	: route_host			{ $$ = $1; }
52463b3a8eb9SGleb Smirnoff 		| '{' optnl route_host_list '}'	{ $$ = $3; }
52473b3a8eb9SGleb Smirnoff 		;
52483b3a8eb9SGleb Smirnoff 
52493b3a8eb9SGleb Smirnoff route		: /* empty */			{
52503b3a8eb9SGleb Smirnoff 			$$.host = NULL;
52513b3a8eb9SGleb Smirnoff 			$$.rt = 0;
52523b3a8eb9SGleb Smirnoff 			$$.pool_opts = 0;
52533b3a8eb9SGleb Smirnoff 		}
52543b3a8eb9SGleb Smirnoff 		| FASTROUTE {
5255813196a1SKristof Provost 			/* backwards-compat */
52563b3a8eb9SGleb Smirnoff 			$$.host = NULL;
5257813196a1SKristof Provost 			$$.rt = 0;
52583b3a8eb9SGleb Smirnoff 			$$.pool_opts = 0;
52593b3a8eb9SGleb Smirnoff 		}
52603b3a8eb9SGleb Smirnoff 		| ROUTETO routespec pool_opts {
52613b3a8eb9SGleb Smirnoff 			$$.host = $2;
52623b3a8eb9SGleb Smirnoff 			$$.rt = PF_ROUTETO;
52633b3a8eb9SGleb Smirnoff 			$$.pool_opts = $3.type | $3.opts;
52643b3a8eb9SGleb Smirnoff 			if ($3.key != NULL)
52653b3a8eb9SGleb Smirnoff 				$$.key = $3.key;
52663b3a8eb9SGleb Smirnoff 		}
52673b3a8eb9SGleb Smirnoff 		| REPLYTO routespec pool_opts {
52683b3a8eb9SGleb Smirnoff 			$$.host = $2;
52693b3a8eb9SGleb Smirnoff 			$$.rt = PF_REPLYTO;
52703b3a8eb9SGleb Smirnoff 			$$.pool_opts = $3.type | $3.opts;
52713b3a8eb9SGleb Smirnoff 			if ($3.key != NULL)
52723b3a8eb9SGleb Smirnoff 				$$.key = $3.key;
52733b3a8eb9SGleb Smirnoff 		}
52743b3a8eb9SGleb Smirnoff 		| DUPTO routespec pool_opts {
52753b3a8eb9SGleb Smirnoff 			$$.host = $2;
52763b3a8eb9SGleb Smirnoff 			$$.rt = PF_DUPTO;
52773b3a8eb9SGleb Smirnoff 			$$.pool_opts = $3.type | $3.opts;
52783b3a8eb9SGleb Smirnoff 			if ($3.key != NULL)
52793b3a8eb9SGleb Smirnoff 				$$.key = $3.key;
52803b3a8eb9SGleb Smirnoff 		}
52813b3a8eb9SGleb Smirnoff 		;
52823b3a8eb9SGleb Smirnoff 
52833b3a8eb9SGleb Smirnoff timeout_spec	: STRING NUMBER
52843b3a8eb9SGleb Smirnoff 		{
52853b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
52863b3a8eb9SGleb Smirnoff 				free($1);
52873b3a8eb9SGleb Smirnoff 				YYERROR;
52883b3a8eb9SGleb Smirnoff 			}
52893b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
52903b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
52913b3a8eb9SGleb Smirnoff 				YYERROR;
52923b3a8eb9SGleb Smirnoff 			}
529330bad751SKristof Provost 			if (pfctl_apply_timeout(pf, $1, $2, 0) != 0) {
52943b3a8eb9SGleb Smirnoff 				yyerror("unknown timeout %s", $1);
52953b3a8eb9SGleb Smirnoff 				free($1);
52963b3a8eb9SGleb Smirnoff 				YYERROR;
52973b3a8eb9SGleb Smirnoff 			}
52983b3a8eb9SGleb Smirnoff 			free($1);
52993b3a8eb9SGleb Smirnoff 		}
53007f8af000SLuiz Otavio O Souza 		| INTERVAL NUMBER		{
53017f8af000SLuiz Otavio O Souza 			if (check_rulestate(PFCTL_STATE_OPTION))
53027f8af000SLuiz Otavio O Souza 				YYERROR;
53037f8af000SLuiz Otavio O Souza 			if ($2 < 0 || $2 > UINT_MAX) {
53047f8af000SLuiz Otavio O Souza 				yyerror("only positive values permitted");
53057f8af000SLuiz Otavio O Souza 				YYERROR;
53067f8af000SLuiz Otavio O Souza 			}
530730bad751SKristof Provost 			if (pfctl_apply_timeout(pf, "interval", $2, 0) != 0)
53087f8af000SLuiz Otavio O Souza 				YYERROR;
53097f8af000SLuiz Otavio O Souza 		}
53103b3a8eb9SGleb Smirnoff 		;
53113b3a8eb9SGleb Smirnoff 
53123b3a8eb9SGleb Smirnoff timeout_list	: timeout_list comma timeout_spec optnl
53133b3a8eb9SGleb Smirnoff 		| timeout_spec optnl
53143b3a8eb9SGleb Smirnoff 		;
53153b3a8eb9SGleb Smirnoff 
53163b3a8eb9SGleb Smirnoff limit_spec	: STRING NUMBER
53173b3a8eb9SGleb Smirnoff 		{
53183b3a8eb9SGleb Smirnoff 			if (check_rulestate(PFCTL_STATE_OPTION)) {
53193b3a8eb9SGleb Smirnoff 				free($1);
53203b3a8eb9SGleb Smirnoff 				YYERROR;
53213b3a8eb9SGleb Smirnoff 			}
53223b3a8eb9SGleb Smirnoff 			if ($2 < 0 || $2 > UINT_MAX) {
53233b3a8eb9SGleb Smirnoff 				yyerror("only positive values permitted");
53243b3a8eb9SGleb Smirnoff 				YYERROR;
53253b3a8eb9SGleb Smirnoff 			}
5326d9ab8999SKristof Provost 			if (pfctl_apply_limit(pf, $1, $2) != 0) {
53273b3a8eb9SGleb Smirnoff 				yyerror("unable to set limit %s %u", $1, $2);
53283b3a8eb9SGleb Smirnoff 				free($1);
53293b3a8eb9SGleb Smirnoff 				YYERROR;
53303b3a8eb9SGleb Smirnoff 			}
53313b3a8eb9SGleb Smirnoff 			free($1);
53323b3a8eb9SGleb Smirnoff 		}
53333b3a8eb9SGleb Smirnoff 		;
53343b3a8eb9SGleb Smirnoff 
53353b3a8eb9SGleb Smirnoff limit_list	: limit_list comma limit_spec optnl
53363b3a8eb9SGleb Smirnoff 		| limit_spec optnl
53373b3a8eb9SGleb Smirnoff 		;
53383b3a8eb9SGleb Smirnoff 
53393b3a8eb9SGleb Smirnoff comma		: ','
53403b3a8eb9SGleb Smirnoff 		| /* empty */
53413b3a8eb9SGleb Smirnoff 		;
53423b3a8eb9SGleb Smirnoff 
53433b3a8eb9SGleb Smirnoff yesno		: NO			{ $$ = 0; }
53443b3a8eb9SGleb Smirnoff 		| STRING		{
53453b3a8eb9SGleb Smirnoff 			if (!strcmp($1, "yes"))
53463b3a8eb9SGleb Smirnoff 				$$ = 1;
53473b3a8eb9SGleb Smirnoff 			else {
53483b3a8eb9SGleb Smirnoff 				yyerror("invalid value '%s', expected 'yes' "
53493b3a8eb9SGleb Smirnoff 				    "or 'no'", $1);
53503b3a8eb9SGleb Smirnoff 				free($1);
53513b3a8eb9SGleb Smirnoff 				YYERROR;
53523b3a8eb9SGleb Smirnoff 			}
53533b3a8eb9SGleb Smirnoff 			free($1);
53543b3a8eb9SGleb Smirnoff 		}
53553b3a8eb9SGleb Smirnoff 		;
53563b3a8eb9SGleb Smirnoff 
53573b3a8eb9SGleb Smirnoff unaryop		: '='		{ $$ = PF_OP_EQ; }
535880eb861dSKristof Provost 		| NE			{ $$ = PF_OP_NE; }
535980eb861dSKristof Provost 		| LE			{ $$ = PF_OP_LE; }
53603b3a8eb9SGleb Smirnoff 		| '<'		{ $$ = PF_OP_LT; }
536180eb861dSKristof Provost 		| GE		{ $$ = PF_OP_GE; }
53623b3a8eb9SGleb Smirnoff 		| '>'		{ $$ = PF_OP_GT; }
53633b3a8eb9SGleb Smirnoff 		;
53643b3a8eb9SGleb Smirnoff 
53653b3a8eb9SGleb Smirnoff %%
53663b3a8eb9SGleb Smirnoff 
53673b3a8eb9SGleb Smirnoff int
53683b3a8eb9SGleb Smirnoff yyerror(const char *fmt, ...)
53693b3a8eb9SGleb Smirnoff {
53703b3a8eb9SGleb Smirnoff 	va_list		 ap;
53713b3a8eb9SGleb Smirnoff 
53723b3a8eb9SGleb Smirnoff 	file->errors++;
53733b3a8eb9SGleb Smirnoff 	va_start(ap, fmt);
53743b3a8eb9SGleb Smirnoff 	fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
53753b3a8eb9SGleb Smirnoff 	vfprintf(stderr, fmt, ap);
53763b3a8eb9SGleb Smirnoff 	fprintf(stderr, "\n");
53773b3a8eb9SGleb Smirnoff 	va_end(ap);
53783b3a8eb9SGleb Smirnoff 	return (0);
53793b3a8eb9SGleb Smirnoff }
53803b3a8eb9SGleb Smirnoff 
53813b3a8eb9SGleb Smirnoff int
53823b3a8eb9SGleb Smirnoff disallow_table(struct node_host *h, const char *fmt)
53833b3a8eb9SGleb Smirnoff {
53843b3a8eb9SGleb Smirnoff 	for (; h != NULL; h = h->next)
53853b3a8eb9SGleb Smirnoff 		if (h->addr.type == PF_ADDR_TABLE) {
53863b3a8eb9SGleb Smirnoff 			yyerror(fmt, h->addr.v.tblname);
53873b3a8eb9SGleb Smirnoff 			return (1);
53883b3a8eb9SGleb Smirnoff 		}
53893b3a8eb9SGleb Smirnoff 	return (0);
53903b3a8eb9SGleb Smirnoff }
53913b3a8eb9SGleb Smirnoff 
53923b3a8eb9SGleb Smirnoff int
53933b3a8eb9SGleb Smirnoff disallow_urpf_failed(struct node_host *h, const char *fmt)
53943b3a8eb9SGleb Smirnoff {
53953b3a8eb9SGleb Smirnoff 	for (; h != NULL; h = h->next)
53963b3a8eb9SGleb Smirnoff 		if (h->addr.type == PF_ADDR_URPFFAILED) {
53973b3a8eb9SGleb Smirnoff 			yyerror(fmt);
53983b3a8eb9SGleb Smirnoff 			return (1);
53993b3a8eb9SGleb Smirnoff 		}
54003b3a8eb9SGleb Smirnoff 	return (0);
54013b3a8eb9SGleb Smirnoff }
54023b3a8eb9SGleb Smirnoff 
54033b3a8eb9SGleb Smirnoff int
54043b3a8eb9SGleb Smirnoff disallow_alias(struct node_host *h, const char *fmt)
54053b3a8eb9SGleb Smirnoff {
54063b3a8eb9SGleb Smirnoff 	for (; h != NULL; h = h->next)
54073b3a8eb9SGleb Smirnoff 		if (DYNIF_MULTIADDR(h->addr)) {
54083b3a8eb9SGleb Smirnoff 			yyerror(fmt, h->addr.v.tblname);
54093b3a8eb9SGleb Smirnoff 			return (1);
54103b3a8eb9SGleb Smirnoff 		}
54113b3a8eb9SGleb Smirnoff 	return (0);
54123b3a8eb9SGleb Smirnoff }
54133b3a8eb9SGleb Smirnoff 
54143b3a8eb9SGleb Smirnoff int
5415e9eb0941SKristof Provost rule_consistent(struct pfctl_rule *r, int anchor_call)
54163b3a8eb9SGleb Smirnoff {
54173b3a8eb9SGleb Smirnoff 	int	problems = 0;
54183b3a8eb9SGleb Smirnoff 
54193b3a8eb9SGleb Smirnoff 	switch (r->action) {
54203b3a8eb9SGleb Smirnoff 	case PF_PASS:
542139282ef3SKajetan Staszkiewicz 	case PF_MATCH:
54223b3a8eb9SGleb Smirnoff 	case PF_DROP:
54233b3a8eb9SGleb Smirnoff 	case PF_SCRUB:
54243b3a8eb9SGleb Smirnoff 	case PF_NOSCRUB:
54253b3a8eb9SGleb Smirnoff 		problems = filter_consistent(r, anchor_call);
54263b3a8eb9SGleb Smirnoff 		break;
54273b3a8eb9SGleb Smirnoff 	case PF_NAT:
54283b3a8eb9SGleb Smirnoff 	case PF_NONAT:
54293b3a8eb9SGleb Smirnoff 		problems = nat_consistent(r);
54303b3a8eb9SGleb Smirnoff 		break;
54313b3a8eb9SGleb Smirnoff 	case PF_RDR:
54323b3a8eb9SGleb Smirnoff 	case PF_NORDR:
54333b3a8eb9SGleb Smirnoff 		problems = rdr_consistent(r);
54343b3a8eb9SGleb Smirnoff 		break;
54353b3a8eb9SGleb Smirnoff 	case PF_BINAT:
54363b3a8eb9SGleb Smirnoff 	case PF_NOBINAT:
54373b3a8eb9SGleb Smirnoff 	default:
54383b3a8eb9SGleb Smirnoff 		break;
54393b3a8eb9SGleb Smirnoff 	}
54403b3a8eb9SGleb Smirnoff 	return (problems);
54413b3a8eb9SGleb Smirnoff }
54423b3a8eb9SGleb Smirnoff 
54433b3a8eb9SGleb Smirnoff int
5444e9eb0941SKristof Provost filter_consistent(struct pfctl_rule *r, int anchor_call)
54453b3a8eb9SGleb Smirnoff {
54463b3a8eb9SGleb Smirnoff 	int	problems = 0;
54473b3a8eb9SGleb Smirnoff 
54483b3a8eb9SGleb Smirnoff 	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
54490bd4a683SKristof Provost 	    r->proto != IPPROTO_SCTP &&
54503b3a8eb9SGleb Smirnoff 	    (r->src.port_op || r->dst.port_op)) {
54510bd4a683SKristof Provost 		yyerror("port only applies to tcp/udp/sctp");
54523b3a8eb9SGleb Smirnoff 		problems++;
54533b3a8eb9SGleb Smirnoff 	}
54543b3a8eb9SGleb Smirnoff 	if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
54553b3a8eb9SGleb Smirnoff 	    (r->type || r->code)) {
54563b3a8eb9SGleb Smirnoff 		yyerror("icmp-type/code only applies to icmp");
54573b3a8eb9SGleb Smirnoff 		problems++;
54583b3a8eb9SGleb Smirnoff 	}
54593b3a8eb9SGleb Smirnoff 	if (!r->af && (r->type || r->code)) {
54603b3a8eb9SGleb Smirnoff 		yyerror("must indicate address family with icmp-type/code");
54613b3a8eb9SGleb Smirnoff 		problems++;
54623b3a8eb9SGleb Smirnoff 	}
5463899e7976SKristof Provost 	if (r->rule_flag & PFRULE_AFTO && r->af == r->naf) {
5464899e7976SKristof Provost 		yyerror("must indicate different address family with af-to");
5465899e7976SKristof Provost 		problems++;
5466899e7976SKristof Provost 	}
54673b3a8eb9SGleb Smirnoff 	if (r->overload_tblname[0] &&
54683b3a8eb9SGleb Smirnoff 	    r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
54693b3a8eb9SGleb Smirnoff 		yyerror("'overload' requires 'max-src-conn' "
54703b3a8eb9SGleb Smirnoff 		    "or 'max-src-conn-rate'");
54713b3a8eb9SGleb Smirnoff 		problems++;
54723b3a8eb9SGleb Smirnoff 	}
54733b3a8eb9SGleb Smirnoff 	if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
54743b3a8eb9SGleb Smirnoff 	    (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
54753b3a8eb9SGleb Smirnoff 		yyerror("proto %s doesn't match address family %s",
54763b3a8eb9SGleb Smirnoff 		    r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
54773b3a8eb9SGleb Smirnoff 		    r->af == AF_INET ? "inet" : "inet6");
54783b3a8eb9SGleb Smirnoff 		problems++;
54793b3a8eb9SGleb Smirnoff 	}
54803b3a8eb9SGleb Smirnoff 	if (r->allow_opts && r->action != PF_PASS) {
54813b3a8eb9SGleb Smirnoff 		yyerror("allow-opts can only be specified for pass rules");
54823b3a8eb9SGleb Smirnoff 		problems++;
54833b3a8eb9SGleb Smirnoff 	}
54843b3a8eb9SGleb Smirnoff 	if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
54853b3a8eb9SGleb Smirnoff 	    r->dst.port_op || r->flagset || r->type || r->code)) {
54863b3a8eb9SGleb Smirnoff 		yyerror("fragments can be filtered only on IP header fields");
54873b3a8eb9SGleb Smirnoff 		problems++;
54883b3a8eb9SGleb Smirnoff 	}
54893b3a8eb9SGleb Smirnoff 	if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
54903b3a8eb9SGleb Smirnoff 		yyerror("return-rst can only be applied to TCP rules");
54913b3a8eb9SGleb Smirnoff 		problems++;
54923b3a8eb9SGleb Smirnoff 	}
54933b3a8eb9SGleb Smirnoff 	if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
54943b3a8eb9SGleb Smirnoff 		yyerror("max-src-nodes requires 'source-track rule'");
54953b3a8eb9SGleb Smirnoff 		problems++;
54963b3a8eb9SGleb Smirnoff 	}
549739282ef3SKajetan Staszkiewicz 	if (r->action != PF_PASS && r->keep_state) {
549839282ef3SKajetan Staszkiewicz 		yyerror("keep state is great, but only for pass rules");
54993b3a8eb9SGleb Smirnoff 		problems++;
55003b3a8eb9SGleb Smirnoff 	}
55013b3a8eb9SGleb Smirnoff 	if (r->rule_flag & PFRULE_STATESLOPPY &&
55023b3a8eb9SGleb Smirnoff 	    (r->keep_state == PF_STATE_MODULATE ||
55033b3a8eb9SGleb Smirnoff 	    r->keep_state == PF_STATE_SYNPROXY)) {
55043b3a8eb9SGleb Smirnoff 		yyerror("sloppy state matching cannot be used with "
55053b3a8eb9SGleb Smirnoff 		    "synproxy state or modulate state");
55063b3a8eb9SGleb Smirnoff 		problems++;
55073b3a8eb9SGleb Smirnoff 	}
5508ca0e6934SKristof Provost 	if (r->rule_flag & PFRULE_AFTO && r->rt) {
55097a372bdeSKristof Provost 		if (r->rt != PF_ROUTETO && r->rt != PF_REPLYTO) {
55107a372bdeSKristof Provost 			yyerror("dup-to "
5511ca0e6934SKristof Provost 			   "must not be used on af-to rules");
5512ca0e6934SKristof Provost 			problems++;
5513ca0e6934SKristof Provost 		}
5514ca0e6934SKristof Provost 	}
551539282ef3SKajetan Staszkiewicz 	/* match rules rules */
551639282ef3SKajetan Staszkiewicz 	if (r->action == PF_MATCH) {
551739282ef3SKajetan Staszkiewicz 		if (r->divert.port) {
551839282ef3SKajetan Staszkiewicz 			yyerror("divert is not supported on match rules");
551939282ef3SKajetan Staszkiewicz 			problems++;
552039282ef3SKajetan Staszkiewicz 		}
552139282ef3SKajetan Staszkiewicz 		if (r->rt) {
552239282ef3SKajetan Staszkiewicz 			yyerror("route-to, reply-to, dup-to and fastroute "
552339282ef3SKajetan Staszkiewicz 			   "must not be used on match rules");
552439282ef3SKajetan Staszkiewicz 			problems++;
552539282ef3SKajetan Staszkiewicz 		}
5526f88019e8SKristof Provost 		if (r->rule_flag & PFRULE_AFTO) {
5527aa69fdf1SKristof Provost 			yyerror("af-to is not supported on match rules");
5528aa69fdf1SKristof Provost 			problems++;
5529aa69fdf1SKristof Provost 		}
553039282ef3SKajetan Staszkiewicz 	}
5531096efeb6SKristof Provost 	if (r->rdr.opts & PF_POOL_STICKYADDR && !r->keep_state) {
5532788f194fSKajetan Staszkiewicz 		yyerror("'sticky-address' requires 'keep state'");
5533788f194fSKajetan Staszkiewicz 		problems++;
5534788f194fSKajetan Staszkiewicz 	}
55353b3a8eb9SGleb Smirnoff 	return (-problems);
55363b3a8eb9SGleb Smirnoff }
55373b3a8eb9SGleb Smirnoff 
55383b3a8eb9SGleb Smirnoff int
5539e9eb0941SKristof Provost nat_consistent(struct pfctl_rule *r)
55403b3a8eb9SGleb Smirnoff {
55413b3a8eb9SGleb Smirnoff 	return (0);	/* yeah! */
55423b3a8eb9SGleb Smirnoff }
55433b3a8eb9SGleb Smirnoff 
55443b3a8eb9SGleb Smirnoff int
5545e9eb0941SKristof Provost rdr_consistent(struct pfctl_rule *r)
55463b3a8eb9SGleb Smirnoff {
55473b3a8eb9SGleb Smirnoff 	int			 problems = 0;
55483b3a8eb9SGleb Smirnoff 
55490bd4a683SKristof Provost 	if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
55500bd4a683SKristof Provost 	    r->proto != IPPROTO_SCTP) {
55513b3a8eb9SGleb Smirnoff 		if (r->src.port_op) {
55520bd4a683SKristof Provost 			yyerror("src port only applies to tcp/udp/sctp");
55533b3a8eb9SGleb Smirnoff 			problems++;
55543b3a8eb9SGleb Smirnoff 		}
55553b3a8eb9SGleb Smirnoff 		if (r->dst.port_op) {
55560bd4a683SKristof Provost 			yyerror("dst port only applies to tcp/udp/sctp");
55573b3a8eb9SGleb Smirnoff 			problems++;
55583b3a8eb9SGleb Smirnoff 		}
5559096efeb6SKristof Provost 		if (r->rdr.proxy_port[0]) {
5560096efeb6SKristof Provost 			yyerror("rdr port only applies to tcp/udp/sctp");
55613b3a8eb9SGleb Smirnoff 			problems++;
55623b3a8eb9SGleb Smirnoff 		}
55633b3a8eb9SGleb Smirnoff 	}
55643b3a8eb9SGleb Smirnoff 	if (r->dst.port_op &&
55653b3a8eb9SGleb Smirnoff 	    r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
55663b3a8eb9SGleb Smirnoff 		yyerror("invalid port operator for rdr destination port");
55673b3a8eb9SGleb Smirnoff 		problems++;
55683b3a8eb9SGleb Smirnoff 	}
55693b3a8eb9SGleb Smirnoff 	return (-problems);
55703b3a8eb9SGleb Smirnoff }
55713b3a8eb9SGleb Smirnoff 
55723b3a8eb9SGleb Smirnoff int
55733b3a8eb9SGleb Smirnoff process_tabledef(char *name, struct table_opts *opts)
55743b3a8eb9SGleb Smirnoff {
55753b3a8eb9SGleb Smirnoff 	struct pfr_buffer	 ab;
55763b3a8eb9SGleb Smirnoff 	struct node_tinit	*ti;
5577542feeffSKristof Provost 	unsigned long		 maxcount;
5578542feeffSKristof Provost 	size_t			 s = sizeof(maxcount);
55793b3a8eb9SGleb Smirnoff 
55803b3a8eb9SGleb Smirnoff 	bzero(&ab, sizeof(ab));
55813b3a8eb9SGleb Smirnoff 	ab.pfrb_type = PFRB_ADDRS;
55823b3a8eb9SGleb Smirnoff 	SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
55833b3a8eb9SGleb Smirnoff 		if (ti->file)
55843b3a8eb9SGleb Smirnoff 			if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
55853b3a8eb9SGleb Smirnoff 				if (errno)
55863b3a8eb9SGleb Smirnoff 					yyerror("cannot load \"%s\": %s",
55873b3a8eb9SGleb Smirnoff 					    ti->file, strerror(errno));
55883b3a8eb9SGleb Smirnoff 				else
55893b3a8eb9SGleb Smirnoff 					yyerror("file \"%s\" contains bad data",
55903b3a8eb9SGleb Smirnoff 					    ti->file);
55913b3a8eb9SGleb Smirnoff 				goto _error;
55923b3a8eb9SGleb Smirnoff 			}
55933b3a8eb9SGleb Smirnoff 		if (ti->host)
55943b3a8eb9SGleb Smirnoff 			if (append_addr_host(&ab, ti->host, 0, 0)) {
55953b3a8eb9SGleb Smirnoff 				yyerror("cannot create address buffer: %s",
55963b3a8eb9SGleb Smirnoff 				    strerror(errno));
55973b3a8eb9SGleb Smirnoff 				goto _error;
55983b3a8eb9SGleb Smirnoff 			}
55993b3a8eb9SGleb Smirnoff 	}
56003b3a8eb9SGleb Smirnoff 	if (pf->opts & PF_OPT_VERBOSE)
56013b3a8eb9SGleb Smirnoff 		print_tabledef(name, opts->flags, opts->init_addr,
56023b3a8eb9SGleb Smirnoff 		    &opts->init_nodes);
56033b3a8eb9SGleb Smirnoff 	if (!(pf->opts & PF_OPT_NOACTION) &&
56043b3a8eb9SGleb Smirnoff 	    pfctl_define_table(name, opts->flags, opts->init_addr,
56053b3a8eb9SGleb Smirnoff 	    pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
5606542feeffSKristof Provost 
5607542feeffSKristof Provost 		if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s,
5608542feeffSKristof Provost 		    NULL, 0) == -1)
5609542feeffSKristof Provost 			maxcount = 65535;
5610542feeffSKristof Provost 
5611542feeffSKristof Provost 		if (ab.pfrb_size > maxcount)
5612542feeffSKristof Provost 			yyerror("cannot define table %s: too many elements.\n"
5613542feeffSKristof Provost 			    "Consider increasing net.pf.request_maxcount.",
5614542feeffSKristof Provost 			    name);
5615542feeffSKristof Provost 		else
56163b3a8eb9SGleb Smirnoff 			yyerror("cannot define table %s: %s", name,
56173b3a8eb9SGleb Smirnoff 			    pfr_strerror(errno));
5618542feeffSKristof Provost 
56193b3a8eb9SGleb Smirnoff 		goto _error;
56203b3a8eb9SGleb Smirnoff 	}
56213b3a8eb9SGleb Smirnoff 	pf->tdirty = 1;
56223b3a8eb9SGleb Smirnoff 	pfr_buf_clear(&ab);
56233b3a8eb9SGleb Smirnoff 	return (0);
56243b3a8eb9SGleb Smirnoff _error:
56253b3a8eb9SGleb Smirnoff 	pfr_buf_clear(&ab);
56263b3a8eb9SGleb Smirnoff 	return (-1);
56273b3a8eb9SGleb Smirnoff }
56283b3a8eb9SGleb Smirnoff 
56293b3a8eb9SGleb Smirnoff struct keywords {
56303b3a8eb9SGleb Smirnoff 	const char	*k_name;
56313b3a8eb9SGleb Smirnoff 	int		 k_val;
56323b3a8eb9SGleb Smirnoff };
56333b3a8eb9SGleb Smirnoff 
56343b3a8eb9SGleb Smirnoff /* macro gore, but you should've seen the prior indentation nightmare... */
56353b3a8eb9SGleb Smirnoff 
56363b3a8eb9SGleb Smirnoff #define FREE_LIST(T,r) \
56373b3a8eb9SGleb Smirnoff 	do { \
56383b3a8eb9SGleb Smirnoff 		T *p, *node = r; \
56393b3a8eb9SGleb Smirnoff 		while (node != NULL) { \
56403b3a8eb9SGleb Smirnoff 			p = node; \
56413b3a8eb9SGleb Smirnoff 			node = node->next; \
56423b3a8eb9SGleb Smirnoff 			free(p); \
56433b3a8eb9SGleb Smirnoff 		} \
56443b3a8eb9SGleb Smirnoff 	} while (0)
56453b3a8eb9SGleb Smirnoff 
56463b3a8eb9SGleb Smirnoff #define LOOP_THROUGH(T,n,r,C) \
56473b3a8eb9SGleb Smirnoff 	do { \
56483b3a8eb9SGleb Smirnoff 		T *n; \
56493b3a8eb9SGleb Smirnoff 		if (r == NULL) { \
56503b3a8eb9SGleb Smirnoff 			r = calloc(1, sizeof(T)); \
56513b3a8eb9SGleb Smirnoff 			if (r == NULL) \
56523b3a8eb9SGleb Smirnoff 				err(1, "LOOP: calloc"); \
56533b3a8eb9SGleb Smirnoff 			r->next = NULL; \
56543b3a8eb9SGleb Smirnoff 		} \
56553b3a8eb9SGleb Smirnoff 		n = r; \
56563b3a8eb9SGleb Smirnoff 		while (n != NULL) { \
56573b3a8eb9SGleb Smirnoff 			do { \
56583b3a8eb9SGleb Smirnoff 				C; \
56593b3a8eb9SGleb Smirnoff 			} while (0); \
56603b3a8eb9SGleb Smirnoff 			n = n->next; \
56613b3a8eb9SGleb Smirnoff 		} \
56623b3a8eb9SGleb Smirnoff 	} while (0)
56633b3a8eb9SGleb Smirnoff 
56643b3a8eb9SGleb Smirnoff void
56653b3a8eb9SGleb Smirnoff expand_label_str(char *label, size_t len, const char *srch, const char *repl)
56663b3a8eb9SGleb Smirnoff {
56673b3a8eb9SGleb Smirnoff 	char *tmp;
56683b3a8eb9SGleb Smirnoff 	char *p, *q;
56693b3a8eb9SGleb Smirnoff 
56703b3a8eb9SGleb Smirnoff 	if ((tmp = calloc(1, len)) == NULL)
56713b3a8eb9SGleb Smirnoff 		err(1, "expand_label_str: calloc");
56723b3a8eb9SGleb Smirnoff 	p = q = label;
56733b3a8eb9SGleb Smirnoff 	while ((q = strstr(p, srch)) != NULL) {
56743b3a8eb9SGleb Smirnoff 		*q = '\0';
56753b3a8eb9SGleb Smirnoff 		if ((strlcat(tmp, p, len) >= len) ||
56763b3a8eb9SGleb Smirnoff 		    (strlcat(tmp, repl, len) >= len))
56773b3a8eb9SGleb Smirnoff 			errx(1, "expand_label: label too long");
56783b3a8eb9SGleb Smirnoff 		q += strlen(srch);
56793b3a8eb9SGleb Smirnoff 		p = q;
56803b3a8eb9SGleb Smirnoff 	}
56813b3a8eb9SGleb Smirnoff 	if (strlcat(tmp, p, len) >= len)
56823b3a8eb9SGleb Smirnoff 		errx(1, "expand_label: label too long");
56833b3a8eb9SGleb Smirnoff 	strlcpy(label, tmp, len);	/* always fits */
56843b3a8eb9SGleb Smirnoff 	free(tmp);
56853b3a8eb9SGleb Smirnoff }
56863b3a8eb9SGleb Smirnoff 
56873b3a8eb9SGleb Smirnoff void
56883b3a8eb9SGleb Smirnoff expand_label_if(const char *name, char *label, size_t len, const char *ifname)
56893b3a8eb9SGleb Smirnoff {
56903b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
56913b3a8eb9SGleb Smirnoff 		if (!*ifname)
56923b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, "any");
56933b3a8eb9SGleb Smirnoff 		else
56943b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, ifname);
56953b3a8eb9SGleb Smirnoff 	}
56963b3a8eb9SGleb Smirnoff }
56973b3a8eb9SGleb Smirnoff 
56983b3a8eb9SGleb Smirnoff void
56993b3a8eb9SGleb Smirnoff expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
570009c7f238SKristof Provost     struct pf_rule_addr *addr)
57013b3a8eb9SGleb Smirnoff {
57023b3a8eb9SGleb Smirnoff 	char tmp[64], tmp_not[66];
57033b3a8eb9SGleb Smirnoff 
57043b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
570509c7f238SKristof Provost 		switch (addr->addr.type) {
57063b3a8eb9SGleb Smirnoff 		case PF_ADDR_DYNIFTL:
570709c7f238SKristof Provost 			snprintf(tmp, sizeof(tmp), "(%s)", addr->addr.v.ifname);
57083b3a8eb9SGleb Smirnoff 			break;
57093b3a8eb9SGleb Smirnoff 		case PF_ADDR_TABLE:
571009c7f238SKristof Provost 			snprintf(tmp, sizeof(tmp), "<%s>", addr->addr.v.tblname);
57113b3a8eb9SGleb Smirnoff 			break;
57123b3a8eb9SGleb Smirnoff 		case PF_ADDR_NOROUTE:
57133b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "no-route");
57143b3a8eb9SGleb Smirnoff 			break;
57153b3a8eb9SGleb Smirnoff 		case PF_ADDR_URPFFAILED:
57163b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "urpf-failed");
57173b3a8eb9SGleb Smirnoff 			break;
57183b3a8eb9SGleb Smirnoff 		case PF_ADDR_ADDRMASK:
571909c7f238SKristof Provost 			if (!af || (PF_AZERO(&addr->addr.v.a.addr, af) &&
572009c7f238SKristof Provost 			    PF_AZERO(&addr->addr.v.a.mask, af)))
57213b3a8eb9SGleb Smirnoff 				snprintf(tmp, sizeof(tmp), "any");
57223b3a8eb9SGleb Smirnoff 			else {
57233b3a8eb9SGleb Smirnoff 				char	a[48];
57243b3a8eb9SGleb Smirnoff 				int	bits;
57253b3a8eb9SGleb Smirnoff 
572609c7f238SKristof Provost 				if (inet_ntop(af, &addr->addr.v.a.addr, a,
57273b3a8eb9SGleb Smirnoff 				    sizeof(a)) == NULL)
57283b3a8eb9SGleb Smirnoff 					snprintf(tmp, sizeof(tmp), "?");
57293b3a8eb9SGleb Smirnoff 				else {
573009c7f238SKristof Provost 					bits = unmask(&addr->addr.v.a.mask, af);
57313b3a8eb9SGleb Smirnoff 					if ((af == AF_INET && bits < 32) ||
57323b3a8eb9SGleb Smirnoff 					    (af == AF_INET6 && bits < 128))
57333b3a8eb9SGleb Smirnoff 						snprintf(tmp, sizeof(tmp),
57343b3a8eb9SGleb Smirnoff 						    "%s/%d", a, bits);
57353b3a8eb9SGleb Smirnoff 					else
57363b3a8eb9SGleb Smirnoff 						snprintf(tmp, sizeof(tmp),
57373b3a8eb9SGleb Smirnoff 						    "%s", a);
57383b3a8eb9SGleb Smirnoff 				}
57393b3a8eb9SGleb Smirnoff 			}
57403b3a8eb9SGleb Smirnoff 			break;
57413b3a8eb9SGleb Smirnoff 		default:
57423b3a8eb9SGleb Smirnoff 			snprintf(tmp, sizeof(tmp), "?");
57433b3a8eb9SGleb Smirnoff 			break;
57443b3a8eb9SGleb Smirnoff 		}
57453b3a8eb9SGleb Smirnoff 
574609c7f238SKristof Provost 		if (addr->neg) {
57473b3a8eb9SGleb Smirnoff 			snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
57483b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, tmp_not);
57493b3a8eb9SGleb Smirnoff 		} else
57503b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, tmp);
57513b3a8eb9SGleb Smirnoff 	}
57523b3a8eb9SGleb Smirnoff }
57533b3a8eb9SGleb Smirnoff 
57543b3a8eb9SGleb Smirnoff void
57553b3a8eb9SGleb Smirnoff expand_label_port(const char *name, char *label, size_t len,
575609c7f238SKristof Provost     struct pf_rule_addr *addr)
57573b3a8eb9SGleb Smirnoff {
57583b3a8eb9SGleb Smirnoff 	char	 a1[6], a2[6], op[13] = "";
57593b3a8eb9SGleb Smirnoff 
57603b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
576109c7f238SKristof Provost 		snprintf(a1, sizeof(a1), "%u", ntohs(addr->port[0]));
576209c7f238SKristof Provost 		snprintf(a2, sizeof(a2), "%u", ntohs(addr->port[1]));
576309c7f238SKristof Provost 		if (!addr->port_op)
57643b3a8eb9SGleb Smirnoff 			;
576509c7f238SKristof Provost 		else if (addr->port_op == PF_OP_IRG)
57663b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "%s><%s", a1, a2);
576709c7f238SKristof Provost 		else if (addr->port_op == PF_OP_XRG)
57683b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "%s<>%s", a1, a2);
576909c7f238SKristof Provost 		else if (addr->port_op == PF_OP_EQ)
57703b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "%s", a1);
577109c7f238SKristof Provost 		else if (addr->port_op == PF_OP_NE)
57723b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "!=%s", a1);
577309c7f238SKristof Provost 		else if (addr->port_op == PF_OP_LT)
57743b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "<%s", a1);
577509c7f238SKristof Provost 		else if (addr->port_op == PF_OP_LE)
57763b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), "<=%s", a1);
577709c7f238SKristof Provost 		else if (addr->port_op == PF_OP_GT)
57783b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), ">%s", a1);
577909c7f238SKristof Provost 		else if (addr->port_op == PF_OP_GE)
57803b3a8eb9SGleb Smirnoff 			snprintf(op, sizeof(op), ">=%s", a1);
57813b3a8eb9SGleb Smirnoff 		expand_label_str(label, len, name, op);
57823b3a8eb9SGleb Smirnoff 	}
57833b3a8eb9SGleb Smirnoff }
57843b3a8eb9SGleb Smirnoff 
57853b3a8eb9SGleb Smirnoff void
57863b3a8eb9SGleb Smirnoff expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
57873b3a8eb9SGleb Smirnoff {
5788858937beSMateusz Guzik 	const char *protoname;
57893b3a8eb9SGleb Smirnoff 	char n[4];
57903b3a8eb9SGleb Smirnoff 
57913b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
5792858937beSMateusz Guzik 		protoname = pfctl_proto2name(proto);
5793858937beSMateusz Guzik 		if (protoname != NULL)
5794858937beSMateusz Guzik 			expand_label_str(label, len, name, protoname);
57953b3a8eb9SGleb Smirnoff 		else {
57963b3a8eb9SGleb Smirnoff 			snprintf(n, sizeof(n), "%u", proto);
57973b3a8eb9SGleb Smirnoff 			expand_label_str(label, len, name, n);
57983b3a8eb9SGleb Smirnoff 		}
57993b3a8eb9SGleb Smirnoff 	}
58003b3a8eb9SGleb Smirnoff }
58013b3a8eb9SGleb Smirnoff 
58023b3a8eb9SGleb Smirnoff void
580309c7f238SKristof Provost expand_label_nr(const char *name, char *label, size_t len,
580409c7f238SKristof Provost     struct pfctl_rule *r)
58053b3a8eb9SGleb Smirnoff {
58063b3a8eb9SGleb Smirnoff 	char n[11];
58073b3a8eb9SGleb Smirnoff 
58083b3a8eb9SGleb Smirnoff 	if (strstr(label, name) != NULL) {
580909c7f238SKristof Provost 		snprintf(n, sizeof(n), "%u", r->nr);
58103b3a8eb9SGleb Smirnoff 		expand_label_str(label, len, name, n);
58113b3a8eb9SGleb Smirnoff 	}
58123b3a8eb9SGleb Smirnoff }
58133b3a8eb9SGleb Smirnoff 
58143b3a8eb9SGleb Smirnoff void
581509c7f238SKristof Provost expand_label(char *label, size_t len, struct pfctl_rule *r)
58163b3a8eb9SGleb Smirnoff {
581709c7f238SKristof Provost 	expand_label_if("$if", label, len, r->ifname);
581809c7f238SKristof Provost 	expand_label_addr("$srcaddr", label, len, r->af, &r->src);
581909c7f238SKristof Provost 	expand_label_addr("$dstaddr", label, len, r->af, &r->dst);
582009c7f238SKristof Provost 	expand_label_port("$srcport", label, len, &r->src);
582109c7f238SKristof Provost 	expand_label_port("$dstport", label, len, &r->dst);
582209c7f238SKristof Provost 	expand_label_proto("$proto", label, len, r->proto);
582309c7f238SKristof Provost 	expand_label_nr("$nr", label, len, r);
58243b3a8eb9SGleb Smirnoff }
58253b3a8eb9SGleb Smirnoff 
58263b3a8eb9SGleb Smirnoff int
58273b3a8eb9SGleb Smirnoff expand_altq(struct pf_altq *a, struct node_if *interfaces,
58283b3a8eb9SGleb Smirnoff     struct node_queue *nqueues, struct node_queue_bw bwspec,
58293b3a8eb9SGleb Smirnoff     struct node_queue_opt *opts)
58303b3a8eb9SGleb Smirnoff {
58313b3a8eb9SGleb Smirnoff 	struct pf_altq		 pa, pb;
58323b3a8eb9SGleb Smirnoff 	char			 qname[PF_QNAME_SIZE];
58333b3a8eb9SGleb Smirnoff 	struct node_queue	*n;
58343b3a8eb9SGleb Smirnoff 	struct node_queue_bw	 bw;
58353b3a8eb9SGleb Smirnoff 	int			 errs = 0;
58363b3a8eb9SGleb Smirnoff 
58373b3a8eb9SGleb Smirnoff 	if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
58383b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_if, interfaces);
58390a70aaf8SLuiz Otavio O Souza 		if (nqueues)
58403b3a8eb9SGleb Smirnoff 			FREE_LIST(struct node_queue, nqueues);
58413b3a8eb9SGleb Smirnoff 		return (0);
58423b3a8eb9SGleb Smirnoff 	}
58433b3a8eb9SGleb Smirnoff 
58443b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
58453b3a8eb9SGleb Smirnoff 		memcpy(&pa, a, sizeof(struct pf_altq));
58463b3a8eb9SGleb Smirnoff 		if (strlcpy(pa.ifname, interface->ifname,
58473b3a8eb9SGleb Smirnoff 		    sizeof(pa.ifname)) >= sizeof(pa.ifname))
58483b3a8eb9SGleb Smirnoff 			errx(1, "expand_altq: strlcpy");
58493b3a8eb9SGleb Smirnoff 
58503b3a8eb9SGleb Smirnoff 		if (interface->not) {
58513b3a8eb9SGleb Smirnoff 			yyerror("altq on ! <interface> is not supported");
58523b3a8eb9SGleb Smirnoff 			errs++;
58533b3a8eb9SGleb Smirnoff 		} else {
58543b3a8eb9SGleb Smirnoff 			if (eval_pfaltq(pf, &pa, &bwspec, opts))
58553b3a8eb9SGleb Smirnoff 				errs++;
58563b3a8eb9SGleb Smirnoff 			else
58573b3a8eb9SGleb Smirnoff 				if (pfctl_add_altq(pf, &pa))
58583b3a8eb9SGleb Smirnoff 					errs++;
58593b3a8eb9SGleb Smirnoff 
58603b3a8eb9SGleb Smirnoff 			if (pf->opts & PF_OPT_VERBOSE) {
58613b3a8eb9SGleb Smirnoff 				print_altq(&pf->paltq->altq, 0,
58623b3a8eb9SGleb Smirnoff 				    &bwspec, opts);
58633b3a8eb9SGleb Smirnoff 				if (nqueues && nqueues->tail) {
58643b3a8eb9SGleb Smirnoff 					printf("queue { ");
58653b3a8eb9SGleb Smirnoff 					LOOP_THROUGH(struct node_queue, queue,
58663b3a8eb9SGleb Smirnoff 					    nqueues,
58673b3a8eb9SGleb Smirnoff 						printf("%s ",
58683b3a8eb9SGleb Smirnoff 						    queue->queue);
58693b3a8eb9SGleb Smirnoff 					);
58703b3a8eb9SGleb Smirnoff 					printf("}");
58713b3a8eb9SGleb Smirnoff 				}
58723b3a8eb9SGleb Smirnoff 				printf("\n");
58733b3a8eb9SGleb Smirnoff 			}
58743b3a8eb9SGleb Smirnoff 
58753b3a8eb9SGleb Smirnoff 			if (pa.scheduler == ALTQT_CBQ ||
5876dc784287SKristof Provost 			    pa.scheduler == ALTQT_HFSC ||
5877dc784287SKristof Provost 			    pa.scheduler == ALTQT_FAIRQ) {
58783b3a8eb9SGleb Smirnoff 				/* now create a root queue */
58793b3a8eb9SGleb Smirnoff 				memset(&pb, 0, sizeof(struct pf_altq));
58803b3a8eb9SGleb Smirnoff 				if (strlcpy(qname, "root_", sizeof(qname)) >=
58813b3a8eb9SGleb Smirnoff 				    sizeof(qname))
58823b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
58833b3a8eb9SGleb Smirnoff 				if (strlcat(qname, interface->ifname,
58843b3a8eb9SGleb Smirnoff 				    sizeof(qname)) >= sizeof(qname))
58853b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcat");
58863b3a8eb9SGleb Smirnoff 				if (strlcpy(pb.qname, qname,
58873b3a8eb9SGleb Smirnoff 				    sizeof(pb.qname)) >= sizeof(pb.qname))
58883b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
58893b3a8eb9SGleb Smirnoff 				if (strlcpy(pb.ifname, interface->ifname,
58903b3a8eb9SGleb Smirnoff 				    sizeof(pb.ifname)) >= sizeof(pb.ifname))
58913b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
58923b3a8eb9SGleb Smirnoff 				pb.qlimit = pa.qlimit;
58933b3a8eb9SGleb Smirnoff 				pb.scheduler = pa.scheduler;
58943b3a8eb9SGleb Smirnoff 				bw.bw_absolute = pa.ifbandwidth;
58953b3a8eb9SGleb Smirnoff 				bw.bw_percent = 0;
58963b3a8eb9SGleb Smirnoff 				if (eval_pfqueue(pf, &pb, &bw, opts))
58973b3a8eb9SGleb Smirnoff 					errs++;
58983b3a8eb9SGleb Smirnoff 				else
58993b3a8eb9SGleb Smirnoff 					if (pfctl_add_altq(pf, &pb))
59003b3a8eb9SGleb Smirnoff 						errs++;
59013b3a8eb9SGleb Smirnoff 			}
59023b3a8eb9SGleb Smirnoff 
59033b3a8eb9SGleb Smirnoff 			LOOP_THROUGH(struct node_queue, queue, nqueues,
59043b3a8eb9SGleb Smirnoff 				n = calloc(1, sizeof(struct node_queue));
59053b3a8eb9SGleb Smirnoff 				if (n == NULL)
59063b3a8eb9SGleb Smirnoff 					err(1, "expand_altq: calloc");
59073b3a8eb9SGleb Smirnoff 				if (pa.scheduler == ALTQT_CBQ ||
5908dc784287SKristof Provost 				    pa.scheduler == ALTQT_HFSC ||
5909dc784287SKristof Provost 				    pa.scheduler == ALTQT_FAIRQ)
59103b3a8eb9SGleb Smirnoff 					if (strlcpy(n->parent, qname,
59113b3a8eb9SGleb Smirnoff 					    sizeof(n->parent)) >=
59123b3a8eb9SGleb Smirnoff 					    sizeof(n->parent))
59133b3a8eb9SGleb Smirnoff 						errx(1, "expand_altq: strlcpy");
59143b3a8eb9SGleb Smirnoff 				if (strlcpy(n->queue, queue->queue,
59153b3a8eb9SGleb Smirnoff 				    sizeof(n->queue)) >= sizeof(n->queue))
59163b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
59173b3a8eb9SGleb Smirnoff 				if (strlcpy(n->ifname, interface->ifname,
59183b3a8eb9SGleb Smirnoff 				    sizeof(n->ifname)) >= sizeof(n->ifname))
59193b3a8eb9SGleb Smirnoff 					errx(1, "expand_altq: strlcpy");
59203b3a8eb9SGleb Smirnoff 				n->scheduler = pa.scheduler;
59213b3a8eb9SGleb Smirnoff 				n->next = NULL;
59223b3a8eb9SGleb Smirnoff 				n->tail = n;
59233b3a8eb9SGleb Smirnoff 				if (queues == NULL)
59243b3a8eb9SGleb Smirnoff 					queues = n;
59253b3a8eb9SGleb Smirnoff 				else {
59263b3a8eb9SGleb Smirnoff 					queues->tail->next = n;
59273b3a8eb9SGleb Smirnoff 					queues->tail = n;
59283b3a8eb9SGleb Smirnoff 				}
59293b3a8eb9SGleb Smirnoff 			);
59303b3a8eb9SGleb Smirnoff 		}
59313b3a8eb9SGleb Smirnoff 	);
59323b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
59330a70aaf8SLuiz Otavio O Souza 	if (nqueues)
59343b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_queue, nqueues);
59353b3a8eb9SGleb Smirnoff 
59363b3a8eb9SGleb Smirnoff 	return (errs);
59373b3a8eb9SGleb Smirnoff }
59383b3a8eb9SGleb Smirnoff 
59393b3a8eb9SGleb Smirnoff int
59403b3a8eb9SGleb Smirnoff expand_queue(struct pf_altq *a, struct node_if *interfaces,
59413b3a8eb9SGleb Smirnoff     struct node_queue *nqueues, struct node_queue_bw bwspec,
59423b3a8eb9SGleb Smirnoff     struct node_queue_opt *opts)
59433b3a8eb9SGleb Smirnoff {
59443b3a8eb9SGleb Smirnoff 	struct node_queue	*n, *nq;
59453b3a8eb9SGleb Smirnoff 	struct pf_altq		 pa;
59463b3a8eb9SGleb Smirnoff 	u_int8_t		 found = 0;
59473b3a8eb9SGleb Smirnoff 	u_int8_t		 errs = 0;
59483b3a8eb9SGleb Smirnoff 
59493b3a8eb9SGleb Smirnoff 	if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
59503b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_queue, nqueues);
59513b3a8eb9SGleb Smirnoff 		return (0);
59523b3a8eb9SGleb Smirnoff 	}
59533b3a8eb9SGleb Smirnoff 
59543b3a8eb9SGleb Smirnoff 	if (queues == NULL) {
59553b3a8eb9SGleb Smirnoff 		yyerror("queue %s has no parent", a->qname);
59563b3a8eb9SGleb Smirnoff 		FREE_LIST(struct node_queue, nqueues);
59573b3a8eb9SGleb Smirnoff 		return (1);
59583b3a8eb9SGleb Smirnoff 	}
59593b3a8eb9SGleb Smirnoff 
59603b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
59613b3a8eb9SGleb Smirnoff 		LOOP_THROUGH(struct node_queue, tqueue, queues,
59623b3a8eb9SGleb Smirnoff 			if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
59633b3a8eb9SGleb Smirnoff 			    (interface->ifname[0] == 0 ||
59643b3a8eb9SGleb Smirnoff 			    (!interface->not && !strncmp(interface->ifname,
59653b3a8eb9SGleb Smirnoff 			    tqueue->ifname, IFNAMSIZ)) ||
59663b3a8eb9SGleb Smirnoff 			    (interface->not && strncmp(interface->ifname,
59673b3a8eb9SGleb Smirnoff 			    tqueue->ifname, IFNAMSIZ)))) {
59683b3a8eb9SGleb Smirnoff 				/* found ourself in queues */
59693b3a8eb9SGleb Smirnoff 				found++;
59703b3a8eb9SGleb Smirnoff 
59713b3a8eb9SGleb Smirnoff 				memcpy(&pa, a, sizeof(struct pf_altq));
59723b3a8eb9SGleb Smirnoff 
59733b3a8eb9SGleb Smirnoff 				if (pa.scheduler != ALTQT_NONE &&
59743b3a8eb9SGleb Smirnoff 				    pa.scheduler != tqueue->scheduler) {
59753b3a8eb9SGleb Smirnoff 					yyerror("exactly one scheduler type "
59763b3a8eb9SGleb Smirnoff 					    "per interface allowed");
59773b3a8eb9SGleb Smirnoff 					return (1);
59783b3a8eb9SGleb Smirnoff 				}
59793b3a8eb9SGleb Smirnoff 				pa.scheduler = tqueue->scheduler;
59803b3a8eb9SGleb Smirnoff 
59813b3a8eb9SGleb Smirnoff 				/* scheduler dependent error checking */
59823b3a8eb9SGleb Smirnoff 				switch (pa.scheduler) {
59833b3a8eb9SGleb Smirnoff 				case ALTQT_PRIQ:
59843b3a8eb9SGleb Smirnoff 					if (nqueues != NULL) {
59853b3a8eb9SGleb Smirnoff 						yyerror("priq queues cannot "
59863b3a8eb9SGleb Smirnoff 						    "have child queues");
59873b3a8eb9SGleb Smirnoff 						return (1);
59883b3a8eb9SGleb Smirnoff 					}
59893b3a8eb9SGleb Smirnoff 					if (bwspec.bw_absolute > 0 ||
59903b3a8eb9SGleb Smirnoff 					    bwspec.bw_percent < 100) {
59913b3a8eb9SGleb Smirnoff 						yyerror("priq doesn't take "
59923b3a8eb9SGleb Smirnoff 						    "bandwidth");
59933b3a8eb9SGleb Smirnoff 						return (1);
59943b3a8eb9SGleb Smirnoff 					}
59953b3a8eb9SGleb Smirnoff 					break;
59963b3a8eb9SGleb Smirnoff 				default:
59973b3a8eb9SGleb Smirnoff 					break;
59983b3a8eb9SGleb Smirnoff 				}
59993b3a8eb9SGleb Smirnoff 
60003b3a8eb9SGleb Smirnoff 				if (strlcpy(pa.ifname, tqueue->ifname,
60013b3a8eb9SGleb Smirnoff 				    sizeof(pa.ifname)) >= sizeof(pa.ifname))
60023b3a8eb9SGleb Smirnoff 					errx(1, "expand_queue: strlcpy");
60033b3a8eb9SGleb Smirnoff 				if (strlcpy(pa.parent, tqueue->parent,
60043b3a8eb9SGleb Smirnoff 				    sizeof(pa.parent)) >= sizeof(pa.parent))
60053b3a8eb9SGleb Smirnoff 					errx(1, "expand_queue: strlcpy");
60063b3a8eb9SGleb Smirnoff 
60073b3a8eb9SGleb Smirnoff 				if (eval_pfqueue(pf, &pa, &bwspec, opts))
60083b3a8eb9SGleb Smirnoff 					errs++;
60093b3a8eb9SGleb Smirnoff 				else
60103b3a8eb9SGleb Smirnoff 					if (pfctl_add_altq(pf, &pa))
60113b3a8eb9SGleb Smirnoff 						errs++;
60123b3a8eb9SGleb Smirnoff 
60133b3a8eb9SGleb Smirnoff 				for (nq = nqueues; nq != NULL; nq = nq->next) {
60143b3a8eb9SGleb Smirnoff 					if (!strcmp(a->qname, nq->queue)) {
60153b3a8eb9SGleb Smirnoff 						yyerror("queue cannot have "
60163b3a8eb9SGleb Smirnoff 						    "itself as child");
60173b3a8eb9SGleb Smirnoff 						errs++;
60183b3a8eb9SGleb Smirnoff 						continue;
60193b3a8eb9SGleb Smirnoff 					}
60203b3a8eb9SGleb Smirnoff 					n = calloc(1,
60213b3a8eb9SGleb Smirnoff 					    sizeof(struct node_queue));
60223b3a8eb9SGleb Smirnoff 					if (n == NULL)
60233b3a8eb9SGleb Smirnoff 						err(1, "expand_queue: calloc");
60243b3a8eb9SGleb Smirnoff 					if (strlcpy(n->parent, a->qname,
60253b3a8eb9SGleb Smirnoff 					    sizeof(n->parent)) >=
60263b3a8eb9SGleb Smirnoff 					    sizeof(n->parent))
60273b3a8eb9SGleb Smirnoff 						errx(1, "expand_queue strlcpy");
60283b3a8eb9SGleb Smirnoff 					if (strlcpy(n->queue, nq->queue,
60293b3a8eb9SGleb Smirnoff 					    sizeof(n->queue)) >=
60303b3a8eb9SGleb Smirnoff 					    sizeof(n->queue))
60313b3a8eb9SGleb Smirnoff 						errx(1, "expand_queue strlcpy");
60323b3a8eb9SGleb Smirnoff 					if (strlcpy(n->ifname, tqueue->ifname,
60333b3a8eb9SGleb Smirnoff 					    sizeof(n->ifname)) >=
60343b3a8eb9SGleb Smirnoff 					    sizeof(n->ifname))
60353b3a8eb9SGleb Smirnoff 						errx(1, "expand_queue strlcpy");
60363b3a8eb9SGleb Smirnoff 					n->scheduler = tqueue->scheduler;
60373b3a8eb9SGleb Smirnoff 					n->next = NULL;
60383b3a8eb9SGleb Smirnoff 					n->tail = n;
60393b3a8eb9SGleb Smirnoff 					if (queues == NULL)
60403b3a8eb9SGleb Smirnoff 						queues = n;
60413b3a8eb9SGleb Smirnoff 					else {
60423b3a8eb9SGleb Smirnoff 						queues->tail->next = n;
60433b3a8eb9SGleb Smirnoff 						queues->tail = n;
60443b3a8eb9SGleb Smirnoff 					}
60453b3a8eb9SGleb Smirnoff 				}
60463b3a8eb9SGleb Smirnoff 				if ((pf->opts & PF_OPT_VERBOSE) && (
60473b3a8eb9SGleb Smirnoff 				    (found == 1 && interface->ifname[0] == 0) ||
60483b3a8eb9SGleb Smirnoff 				    (found > 0 && interface->ifname[0] != 0))) {
60493b3a8eb9SGleb Smirnoff 					print_queue(&pf->paltq->altq, 0,
60503b3a8eb9SGleb Smirnoff 					    &bwspec, interface->ifname[0] != 0,
60513b3a8eb9SGleb Smirnoff 					    opts);
60523b3a8eb9SGleb Smirnoff 					if (nqueues && nqueues->tail) {
60533b3a8eb9SGleb Smirnoff 						printf("{ ");
60543b3a8eb9SGleb Smirnoff 						LOOP_THROUGH(struct node_queue,
60553b3a8eb9SGleb Smirnoff 						    queue, nqueues,
60563b3a8eb9SGleb Smirnoff 							printf("%s ",
60573b3a8eb9SGleb Smirnoff 							    queue->queue);
60583b3a8eb9SGleb Smirnoff 						);
60593b3a8eb9SGleb Smirnoff 						printf("}");
60603b3a8eb9SGleb Smirnoff 					}
60613b3a8eb9SGleb Smirnoff 					printf("\n");
60623b3a8eb9SGleb Smirnoff 				}
60633b3a8eb9SGleb Smirnoff 			}
60643b3a8eb9SGleb Smirnoff 		);
60653b3a8eb9SGleb Smirnoff 	);
60663b3a8eb9SGleb Smirnoff 
60673b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_queue, nqueues);
60683b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
60693b3a8eb9SGleb Smirnoff 
60703b3a8eb9SGleb Smirnoff 	if (!found) {
60713b3a8eb9SGleb Smirnoff 		yyerror("queue %s has no parent", a->qname);
60723b3a8eb9SGleb Smirnoff 		errs++;
60733b3a8eb9SGleb Smirnoff 	}
60743b3a8eb9SGleb Smirnoff 
60753b3a8eb9SGleb Smirnoff 	if (errs)
60763b3a8eb9SGleb Smirnoff 		return (1);
60773b3a8eb9SGleb Smirnoff 	else
60783b3a8eb9SGleb Smirnoff 		return (0);
60793b3a8eb9SGleb Smirnoff }
60803b3a8eb9SGleb Smirnoff 
60818a42005dSKristof Provost static int
60828a42005dSKristof Provost pf_af_to_proto(sa_family_t af)
60838a42005dSKristof Provost {
60848a42005dSKristof Provost 	if (af == AF_INET)
60858a42005dSKristof Provost 		return (ETHERTYPE_IP);
60868a42005dSKristof Provost 	if (af == AF_INET6)
60878a42005dSKristof Provost 		return (ETHERTYPE_IPV6);
60888a42005dSKristof Provost 
60898a42005dSKristof Provost 	return (0);
60908a42005dSKristof Provost }
60918a42005dSKristof Provost 
60923b3a8eb9SGleb Smirnoff void
60932b29ceb8SKristof Provost expand_eth_rule(struct pfctl_eth_rule *r,
609487a89d6eSKristof Provost     struct node_if *interfaces, struct node_etherproto *protos,
60958a42005dSKristof Provost     struct node_mac *srcs, struct node_mac *dsts,
60968a8af942SKristof Provost     struct node_host *ipsrcs, struct node_host *ipdsts,
60978a8af942SKristof Provost     const char *bridge_to, const char *anchor_call)
60982b29ceb8SKristof Provost {
60991f61367fSKristof Provost 	char tagname[PF_TAG_NAME_SIZE];
61001f61367fSKristof Provost 	char match_tagname[PF_TAG_NAME_SIZE];
61011f61367fSKristof Provost 	char qname[PF_QNAME_SIZE];
61021f61367fSKristof Provost 
61031f61367fSKristof Provost 	if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
61041f61367fSKristof Provost 		errx(1, "expand_eth_rule: tagname");
61051f61367fSKristof Provost 	if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
61061f61367fSKristof Provost 	    sizeof(match_tagname))
61071f61367fSKristof Provost 		errx(1, "expand_eth_rule: match_tagname");
61081f61367fSKristof Provost 	if (strlcpy(qname, r->qname, sizeof(qname)) >= sizeof(qname))
61091f61367fSKristof Provost 		errx(1, "expand_eth_rule: qname");
61101f61367fSKristof Provost 
61112b29ceb8SKristof Provost 	LOOP_THROUGH(struct node_if, interface, interfaces,
61122b29ceb8SKristof Provost 	LOOP_THROUGH(struct node_etherproto, proto, protos,
611387a89d6eSKristof Provost 	LOOP_THROUGH(struct node_mac, src, srcs,
611487a89d6eSKristof Provost 	LOOP_THROUGH(struct node_mac, dst, dsts,
61158a42005dSKristof Provost 	LOOP_THROUGH(struct node_host, ipsrc, ipsrcs,
61168a42005dSKristof Provost 	LOOP_THROUGH(struct node_host, ipdst, ipdsts,
61172b29ceb8SKristof Provost 		strlcpy(r->ifname, interface->ifname,
61182b29ceb8SKristof Provost 		    sizeof(r->ifname));
61192b29ceb8SKristof Provost 		r->ifnot = interface->not;
61202b29ceb8SKristof Provost 		r->proto = proto->proto;
61218a42005dSKristof Provost 		if (!r->proto && ipsrc->af)
61228a42005dSKristof Provost 			r->proto = pf_af_to_proto(ipsrc->af);
61238a42005dSKristof Provost 		else if (!r->proto && ipdst->af)
61248a42005dSKristof Provost 			r->proto = pf_af_to_proto(ipdst->af);
612587a89d6eSKristof Provost 		bcopy(src->mac, r->src.addr, ETHER_ADDR_LEN);
6126b590f17aSKristof Provost 		bcopy(src->mask, r->src.mask, ETHER_ADDR_LEN);
612787a89d6eSKristof Provost 		r->src.neg = src->neg;
6128c32cd180SKristof Provost 		r->src.isset = src->isset;
61298a42005dSKristof Provost 		r->ipsrc.addr = ipsrc->addr;
61308a42005dSKristof Provost 		r->ipsrc.neg = ipsrc->not;
61318a42005dSKristof Provost 		r->ipdst.addr = ipdst->addr;
61328a42005dSKristof Provost 		r->ipdst.neg = ipdst->not;
613387a89d6eSKristof Provost 		bcopy(dst->mac, r->dst.addr, ETHER_ADDR_LEN);
6134b590f17aSKristof Provost 		bcopy(dst->mask, r->dst.mask, ETHER_ADDR_LEN);
613587a89d6eSKristof Provost 		r->dst.neg = dst->neg;
6136c32cd180SKristof Provost 		r->dst.isset = dst->isset;
6137c5131afeSKristof Provost 		r->nr = pf->eastack[pf->asd]->match++;
61382b29ceb8SKristof Provost 
61391f61367fSKristof Provost 		if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
61401f61367fSKristof Provost 		    sizeof(r->tagname))
61411f61367fSKristof Provost 			errx(1, "expand_eth_rule: r->tagname");
61421f61367fSKristof Provost 		if (strlcpy(r->match_tagname, match_tagname,
61431f61367fSKristof Provost 		    sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
61441f61367fSKristof Provost 			errx(1, "expand_eth_rule: r->match_tagname");
61451f61367fSKristof Provost 		if (strlcpy(r->qname, qname, sizeof(r->qname)) >= sizeof(r->qname))
61461f61367fSKristof Provost 			errx(1, "expand_eth_rule: r->qname");
61471f61367fSKristof Provost 
61488a8af942SKristof Provost 		if (bridge_to)
61498a8af942SKristof Provost 			strlcpy(r->bridge_to, bridge_to, sizeof(r->bridge_to));
61508a8af942SKristof Provost 
6151c5131afeSKristof Provost 		pfctl_append_eth_rule(pf, r, anchor_call);
61528a42005dSKristof Provost 	))))));
61532b29ceb8SKristof Provost 
61542b29ceb8SKristof Provost 	FREE_LIST(struct node_if, interfaces);
61552b29ceb8SKristof Provost 	FREE_LIST(struct node_etherproto, protos);
615687a89d6eSKristof Provost 	FREE_LIST(struct node_mac, srcs);
615787a89d6eSKristof Provost 	FREE_LIST(struct node_mac, dsts);
61588a42005dSKristof Provost 	FREE_LIST(struct node_host, ipsrcs);
61598a42005dSKristof Provost 	FREE_LIST(struct node_host, ipdsts);
61602b29ceb8SKristof Provost }
61612b29ceb8SKristof Provost 
61622b29ceb8SKristof Provost void
6163e9eb0941SKristof Provost expand_rule(struct pfctl_rule *r,
6164f88019e8SKristof Provost     struct node_if *interfaces, struct redirspec *nat,
61650972294eSKristof Provost     struct redirspec *rdr, struct redirspec *route,
61660972294eSKristof Provost     struct node_host *rdr_hosts, struct node_host *nat_hosts,
61670972294eSKristof Provost     struct node_host *route_hosts, struct node_proto *protos,
61680972294eSKristof Provost     struct node_os *src_oses, struct node_host *src_hosts,
61690972294eSKristof Provost     struct node_port *src_ports, struct node_host *dst_hosts,
61700972294eSKristof Provost     struct node_port *dst_ports, struct node_uid *uids, struct node_gid *gids,
61710972294eSKristof Provost     struct node_if *rcv, struct node_icmp *icmp_types, const char *anchor_call)
61723b3a8eb9SGleb Smirnoff {
61733b3a8eb9SGleb Smirnoff 	sa_family_t		 af = r->af;
61743b3a8eb9SGleb Smirnoff 	int			 added = 0, error = 0;
61753b3a8eb9SGleb Smirnoff 	char			 ifname[IF_NAMESIZE];
61766fcc8e04SKristof Provost 	char			 label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
61773b3a8eb9SGleb Smirnoff 	char			 tagname[PF_TAG_NAME_SIZE];
61783b3a8eb9SGleb Smirnoff 	char			 match_tagname[PF_TAG_NAME_SIZE];
61793b3a8eb9SGleb Smirnoff 	struct pf_pooladdr	*pa;
61807ce98cf2SKristof Provost 	struct node_host	*h, *osrch, *odsth;
61813b3a8eb9SGleb Smirnoff 	u_int8_t		 flags, flagset, keep_state;
61823b3a8eb9SGleb Smirnoff 
61836fcc8e04SKristof Provost 	memcpy(label, r->label, sizeof(r->label));
61846fcc8e04SKristof Provost 	assert(sizeof(r->label) == sizeof(label));
61853b3a8eb9SGleb Smirnoff 	if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
61863b3a8eb9SGleb Smirnoff 		errx(1, "expand_rule: strlcpy");
61873b3a8eb9SGleb Smirnoff 	if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
61883b3a8eb9SGleb Smirnoff 	    sizeof(match_tagname))
61893b3a8eb9SGleb Smirnoff 		errx(1, "expand_rule: strlcpy");
61903b3a8eb9SGleb Smirnoff 	flags = r->flags;
61913b3a8eb9SGleb Smirnoff 	flagset = r->flagset;
61923b3a8eb9SGleb Smirnoff 	keep_state = r->keep_state;
61933b3a8eb9SGleb Smirnoff 
61943b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
61953b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_proto, proto, protos,
61963b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
61973b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_host, src_host, src_hosts,
61983b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
6199288bec2bSKristof Provost 	LOOP_THROUGH(struct node_port, src_port, src_ports,
62003b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_port, dst_port, dst_ports,
6201288bec2bSKristof Provost 	LOOP_THROUGH(struct node_os, src_os, src_oses,
62023b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_uid, uid, uids,
62033b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_gid, gid, gids,
62043b3a8eb9SGleb Smirnoff 
62050d68985bSKristof Provost 		r->af = af;
6206f88019e8SKristof Provost 
6207f88019e8SKristof Provost 		if (r->rule_flag & PFRULE_AFTO) {
6208f88019e8SKristof Provost 			assert(nat != NULL);
6209f88019e8SKristof Provost 			r->naf = nat->af;
6210f88019e8SKristof Provost 		}
6211f88019e8SKristof Provost 
62123b3a8eb9SGleb Smirnoff 		/* for link-local IPv6 address, interface must match up */
62133b3a8eb9SGleb Smirnoff 		if ((r->af && src_host->af && r->af != src_host->af) ||
62143b3a8eb9SGleb Smirnoff 		    (r->af && dst_host->af && r->af != dst_host->af) ||
62153b3a8eb9SGleb Smirnoff 		    (src_host->af && dst_host->af &&
62163b3a8eb9SGleb Smirnoff 		    src_host->af != dst_host->af) ||
62173b3a8eb9SGleb Smirnoff 		    (src_host->ifindex && dst_host->ifindex &&
62183b3a8eb9SGleb Smirnoff 		    src_host->ifindex != dst_host->ifindex) ||
62193b3a8eb9SGleb Smirnoff 		    (src_host->ifindex && *interface->ifname &&
62207cef9d19SKristof Provost 		    src_host->ifindex != ifa_nametoindex(interface->ifname)) ||
62213b3a8eb9SGleb Smirnoff 		    (dst_host->ifindex && *interface->ifname &&
62227cef9d19SKristof Provost 		    dst_host->ifindex != ifa_nametoindex(interface->ifname)))
62233b3a8eb9SGleb Smirnoff 			continue;
62243b3a8eb9SGleb Smirnoff 		if (!r->af && src_host->af)
62253b3a8eb9SGleb Smirnoff 			r->af = src_host->af;
62263b3a8eb9SGleb Smirnoff 		else if (!r->af && dst_host->af)
62273b3a8eb9SGleb Smirnoff 			r->af = dst_host->af;
62283b3a8eb9SGleb Smirnoff 
62293b3a8eb9SGleb Smirnoff 		if (*interface->ifname)
62303b3a8eb9SGleb Smirnoff 			strlcpy(r->ifname, interface->ifname,
62313b3a8eb9SGleb Smirnoff 			    sizeof(r->ifname));
62327cef9d19SKristof Provost 		else if (ifa_indextoname(src_host->ifindex, ifname))
62333b3a8eb9SGleb Smirnoff 			strlcpy(r->ifname, ifname, sizeof(r->ifname));
62347cef9d19SKristof Provost 		else if (ifa_indextoname(dst_host->ifindex, ifname))
62353b3a8eb9SGleb Smirnoff 			strlcpy(r->ifname, ifname, sizeof(r->ifname));
62363b3a8eb9SGleb Smirnoff 		else
62373b3a8eb9SGleb Smirnoff 			memset(r->ifname, '\0', sizeof(r->ifname));
62383b3a8eb9SGleb Smirnoff 
62396fcc8e04SKristof Provost 		memcpy(r->label, label, sizeof(r->label));
62403b3a8eb9SGleb Smirnoff 		if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
62413b3a8eb9SGleb Smirnoff 		    sizeof(r->tagname))
62423b3a8eb9SGleb Smirnoff 			errx(1, "expand_rule: strlcpy");
62433b3a8eb9SGleb Smirnoff 		if (strlcpy(r->match_tagname, match_tagname,
62443b3a8eb9SGleb Smirnoff 		    sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
62453b3a8eb9SGleb Smirnoff 			errx(1, "expand_rule: strlcpy");
62463b3a8eb9SGleb Smirnoff 
62477ce98cf2SKristof Provost 		osrch = odsth = NULL;
62487ce98cf2SKristof Provost 		if (src_host->addr.type == PF_ADDR_DYNIFTL) {
62497ce98cf2SKristof Provost 			osrch = src_host;
62507ce98cf2SKristof Provost 			if ((src_host = gen_dynnode(src_host, r->af)) == NULL)
62517ce98cf2SKristof Provost 				err(1, "expand_rule: calloc");
62527ce98cf2SKristof Provost 		}
62537ce98cf2SKristof Provost 		if (dst_host->addr.type == PF_ADDR_DYNIFTL) {
62547ce98cf2SKristof Provost 			odsth = dst_host;
62557ce98cf2SKristof Provost 			if ((dst_host = gen_dynnode(dst_host, r->af)) == NULL)
62567ce98cf2SKristof Provost 				err(1, "expand_rule: calloc");
62577ce98cf2SKristof Provost 		}
62587ce98cf2SKristof Provost 
62593b3a8eb9SGleb Smirnoff 		error += check_netmask(src_host, r->af);
62603b3a8eb9SGleb Smirnoff 		error += check_netmask(dst_host, r->af);
62613b3a8eb9SGleb Smirnoff 
62623b3a8eb9SGleb Smirnoff 		r->ifnot = interface->not;
62633b3a8eb9SGleb Smirnoff 		r->proto = proto->proto;
62643b3a8eb9SGleb Smirnoff 		r->src.addr = src_host->addr;
62653b3a8eb9SGleb Smirnoff 		r->src.neg = src_host->not;
62663b3a8eb9SGleb Smirnoff 		r->src.port[0] = src_port->port[0];
62673b3a8eb9SGleb Smirnoff 		r->src.port[1] = src_port->port[1];
62683b3a8eb9SGleb Smirnoff 		r->src.port_op = src_port->op;
62693b3a8eb9SGleb Smirnoff 		r->dst.addr = dst_host->addr;
62703b3a8eb9SGleb Smirnoff 		r->dst.neg = dst_host->not;
62713b3a8eb9SGleb Smirnoff 		r->dst.port[0] = dst_port->port[0];
62723b3a8eb9SGleb Smirnoff 		r->dst.port[1] = dst_port->port[1];
62733b3a8eb9SGleb Smirnoff 		r->dst.port_op = dst_port->op;
62743b3a8eb9SGleb Smirnoff 		r->uid.op = uid->op;
62753b3a8eb9SGleb Smirnoff 		r->uid.uid[0] = uid->uid[0];
62763b3a8eb9SGleb Smirnoff 		r->uid.uid[1] = uid->uid[1];
62773b3a8eb9SGleb Smirnoff 		r->gid.op = gid->op;
62783b3a8eb9SGleb Smirnoff 		r->gid.gid[0] = gid->gid[0];
62793b3a8eb9SGleb Smirnoff 		r->gid.gid[1] = gid->gid[1];
62802339ead6SKristof Provost 		if (rcv) {
62812339ead6SKristof Provost 			strlcpy(r->rcv_ifname, rcv->ifname,
62822339ead6SKristof Provost 			    sizeof(r->rcv_ifname));
6283*71594e32SKristof Provost 			r->rcvifnot = rcv->not;
62842339ead6SKristof Provost 		}
62853b3a8eb9SGleb Smirnoff 		r->type = icmp_type->type;
62863b3a8eb9SGleb Smirnoff 		r->code = icmp_type->code;
62873b3a8eb9SGleb Smirnoff 
62883b3a8eb9SGleb Smirnoff 		if ((keep_state == PF_STATE_MODULATE ||
62893b3a8eb9SGleb Smirnoff 		    keep_state == PF_STATE_SYNPROXY) &&
62903b3a8eb9SGleb Smirnoff 		    r->proto && r->proto != IPPROTO_TCP)
62913b3a8eb9SGleb Smirnoff 			r->keep_state = PF_STATE_NORMAL;
62923b3a8eb9SGleb Smirnoff 		else
62933b3a8eb9SGleb Smirnoff 			r->keep_state = keep_state;
62943b3a8eb9SGleb Smirnoff 
62953b3a8eb9SGleb Smirnoff 		if (r->proto && r->proto != IPPROTO_TCP) {
62963b3a8eb9SGleb Smirnoff 			r->flags = 0;
62973b3a8eb9SGleb Smirnoff 			r->flagset = 0;
62983b3a8eb9SGleb Smirnoff 		} else {
62993b3a8eb9SGleb Smirnoff 			r->flags = flags;
63003b3a8eb9SGleb Smirnoff 			r->flagset = flagset;
63013b3a8eb9SGleb Smirnoff 		}
63023b3a8eb9SGleb Smirnoff 		if (icmp_type->proto && r->proto != icmp_type->proto) {
63033b3a8eb9SGleb Smirnoff 			yyerror("icmp-type mismatch");
63043b3a8eb9SGleb Smirnoff 			error++;
63053b3a8eb9SGleb Smirnoff 		}
63063b3a8eb9SGleb Smirnoff 
63073b3a8eb9SGleb Smirnoff 		if (src_os && src_os->os) {
63083b3a8eb9SGleb Smirnoff 			r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
63093b3a8eb9SGleb Smirnoff 			if ((pf->opts & PF_OPT_VERBOSE2) &&
63103b3a8eb9SGleb Smirnoff 			    r->os_fingerprint == PF_OSFP_NOMATCH)
63113b3a8eb9SGleb Smirnoff 				fprintf(stderr,
63123b3a8eb9SGleb Smirnoff 				    "warning: unknown '%s' OS fingerprint\n",
63133b3a8eb9SGleb Smirnoff 				    src_os->os);
63143b3a8eb9SGleb Smirnoff 		} else {
63153b3a8eb9SGleb Smirnoff 			r->os_fingerprint = PF_OSFP_ANY;
63163b3a8eb9SGleb Smirnoff 		}
63173b3a8eb9SGleb Smirnoff 
6318aa69fdf1SKristof Provost 		TAILQ_INIT(&r->rdr.list);
6319aa69fdf1SKristof Provost 		for (h = rdr_hosts; h != NULL; h = h->next) {
63203b3a8eb9SGleb Smirnoff 			pa = calloc(1, sizeof(struct pf_pooladdr));
63213b3a8eb9SGleb Smirnoff 			if (pa == NULL)
63223b3a8eb9SGleb Smirnoff 				err(1, "expand_rule: calloc");
63233b3a8eb9SGleb Smirnoff 			pa->addr = h->addr;
63243b3a8eb9SGleb Smirnoff 			if (h->ifname != NULL) {
63253b3a8eb9SGleb Smirnoff 				if (strlcpy(pa->ifname, h->ifname,
63263b3a8eb9SGleb Smirnoff 				    sizeof(pa->ifname)) >=
63273b3a8eb9SGleb Smirnoff 				    sizeof(pa->ifname))
63283b3a8eb9SGleb Smirnoff 					errx(1, "expand_rule: strlcpy");
63293b3a8eb9SGleb Smirnoff 			} else
63303b3a8eb9SGleb Smirnoff 				pa->ifname[0] = 0;
6331096efeb6SKristof Provost 			TAILQ_INSERT_TAIL(&r->rdr.list, pa, entries);
63323b3a8eb9SGleb Smirnoff 		}
6333aa69fdf1SKristof Provost 		TAILQ_INIT(&r->nat.list);
6334aa69fdf1SKristof Provost 		for (h = nat_hosts; h != NULL; h = h->next) {
6335aa69fdf1SKristof Provost 			pa = calloc(1, sizeof(struct pf_pooladdr));
6336aa69fdf1SKristof Provost 			if (pa == NULL)
6337aa69fdf1SKristof Provost 				err(1, "expand_rule: calloc");
6338aa69fdf1SKristof Provost 			pa->addr = h->addr;
6339aa69fdf1SKristof Provost 			if (h->ifname != NULL) {
6340aa69fdf1SKristof Provost 				if (strlcpy(pa->ifname, h->ifname,
6341aa69fdf1SKristof Provost 				    sizeof(pa->ifname)) >=
6342aa69fdf1SKristof Provost 				    sizeof(pa->ifname))
6343aa69fdf1SKristof Provost 					errx(1, "expand_rule: strlcpy");
6344aa69fdf1SKristof Provost 			} else
6345aa69fdf1SKristof Provost 				pa->ifname[0] = 0;
6346aa69fdf1SKristof Provost 			TAILQ_INSERT_TAIL(&r->nat.list, pa, entries);
6347aa69fdf1SKristof Provost 		}
63480972294eSKristof Provost 		TAILQ_INIT(&r->route.list);
63490972294eSKristof Provost 		for (h = route_hosts; h != NULL; h = h->next) {
63500972294eSKristof Provost 			pa = calloc(1, sizeof(struct pf_pooladdr));
63510972294eSKristof Provost 			if (pa == NULL)
63520972294eSKristof Provost 				err(1, "expand_rule: calloc");
63530972294eSKristof Provost 			pa->addr = h->addr;
63540972294eSKristof Provost 			if (h->ifname != NULL) {
63550972294eSKristof Provost 				if (strlcpy(pa->ifname, h->ifname,
63560972294eSKristof Provost 				    sizeof(pa->ifname)) >=
63570972294eSKristof Provost 				    sizeof(pa->ifname))
63580972294eSKristof Provost 					errx(1, "expand_rule: strlcpy");
63590972294eSKristof Provost 			} else
63600972294eSKristof Provost 				pa->ifname[0] = 0;
63610972294eSKristof Provost 			TAILQ_INSERT_TAIL(&r->route.list, pa, entries);
63620972294eSKristof Provost 		}
6363aa69fdf1SKristof Provost 
6364aa69fdf1SKristof Provost 		r->nat.proxy_port[0] = PF_NAT_PROXY_PORT_LOW;
6365aa69fdf1SKristof Provost 		r->nat.proxy_port[1] = PF_NAT_PROXY_PORT_HIGH;
63663b3a8eb9SGleb Smirnoff 
63673b3a8eb9SGleb Smirnoff 		if (rule_consistent(r, anchor_call[0]) < 0 || error)
63683b3a8eb9SGleb Smirnoff 			yyerror("skipping rule due to errors");
63693b3a8eb9SGleb Smirnoff 		else {
63703b3a8eb9SGleb Smirnoff 			r->nr = pf->astack[pf->asd]->match++;
63710d71f9f3SKristof Provost 			pfctl_append_rule(pf, r, anchor_call);
63723b3a8eb9SGleb Smirnoff 			added++;
63733b3a8eb9SGleb Smirnoff 		}
63743b3a8eb9SGleb Smirnoff 
63757ce98cf2SKristof Provost 		if (osrch && src_host->addr.type == PF_ADDR_DYNIFTL) {
63767ce98cf2SKristof Provost 			free(src_host);
63777ce98cf2SKristof Provost 			src_host = osrch;
63787ce98cf2SKristof Provost 		}
63797ce98cf2SKristof Provost 		if (odsth && dst_host->addr.type == PF_ADDR_DYNIFTL) {
63807ce98cf2SKristof Provost 			free(dst_host);
63817ce98cf2SKristof Provost 			dst_host = odsth;
63827ce98cf2SKristof Provost 		}
63837ce98cf2SKristof Provost 
63843b3a8eb9SGleb Smirnoff 	))))))))));
63853b3a8eb9SGleb Smirnoff 
63863b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
63873b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_proto, protos);
63883b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_host, src_hosts);
63893b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_port, src_ports);
63903b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_os, src_oses);
63913b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_host, dst_hosts);
63923b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_port, dst_ports);
63933b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_uid, uids);
63943b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_gid, gids);
63953b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_icmp, icmp_types);
6396aa69fdf1SKristof Provost 	FREE_LIST(struct node_host, rdr_hosts);
6397aa69fdf1SKristof Provost 	FREE_LIST(struct node_host, nat_hosts);
63983b3a8eb9SGleb Smirnoff 
63993b3a8eb9SGleb Smirnoff 	if (!added)
64003b3a8eb9SGleb Smirnoff 		yyerror("rule expands to no valid combination");
64013b3a8eb9SGleb Smirnoff }
64023b3a8eb9SGleb Smirnoff 
64033b3a8eb9SGleb Smirnoff int
64043b3a8eb9SGleb Smirnoff expand_skip_interface(struct node_if *interfaces)
64053b3a8eb9SGleb Smirnoff {
64063b3a8eb9SGleb Smirnoff 	int	errs = 0;
64073b3a8eb9SGleb Smirnoff 
64083b3a8eb9SGleb Smirnoff 	if (!interfaces || (!interfaces->next && !interfaces->not &&
64093b3a8eb9SGleb Smirnoff 	    !strcmp(interfaces->ifname, "none"))) {
64103b3a8eb9SGleb Smirnoff 		if (pf->opts & PF_OPT_VERBOSE)
64113b3a8eb9SGleb Smirnoff 			printf("set skip on none\n");
64123b3a8eb9SGleb Smirnoff 		errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
64133b3a8eb9SGleb Smirnoff 		return (errs);
64143b3a8eb9SGleb Smirnoff 	}
64153b3a8eb9SGleb Smirnoff 
64163b3a8eb9SGleb Smirnoff 	if (pf->opts & PF_OPT_VERBOSE)
64173b3a8eb9SGleb Smirnoff 		printf("set skip on {");
64183b3a8eb9SGleb Smirnoff 	LOOP_THROUGH(struct node_if, interface, interfaces,
64193b3a8eb9SGleb Smirnoff 		if (pf->opts & PF_OPT_VERBOSE)
64203b3a8eb9SGleb Smirnoff 			printf(" %s", interface->ifname);
64213b3a8eb9SGleb Smirnoff 		if (interface->not) {
64223b3a8eb9SGleb Smirnoff 			yyerror("skip on ! <interface> is not supported");
64233b3a8eb9SGleb Smirnoff 			errs++;
64243b3a8eb9SGleb Smirnoff 		} else
64253b3a8eb9SGleb Smirnoff 			errs += pfctl_set_interface_flags(pf,
64263b3a8eb9SGleb Smirnoff 			    interface->ifname, PFI_IFLAG_SKIP, 1);
64273b3a8eb9SGleb Smirnoff 	);
64283b3a8eb9SGleb Smirnoff 	if (pf->opts & PF_OPT_VERBOSE)
64293b3a8eb9SGleb Smirnoff 		printf(" }\n");
64303b3a8eb9SGleb Smirnoff 
64313b3a8eb9SGleb Smirnoff 	FREE_LIST(struct node_if, interfaces);
64323b3a8eb9SGleb Smirnoff 
64333b3a8eb9SGleb Smirnoff 	if (errs)
64343b3a8eb9SGleb Smirnoff 		return (1);
64353b3a8eb9SGleb Smirnoff 	else
64363b3a8eb9SGleb Smirnoff 		return (0);
64373b3a8eb9SGleb Smirnoff }
64383b3a8eb9SGleb Smirnoff 
6439637d81c5SKristof Provost void
6440637d81c5SKristof Provost freehostlist(struct node_host *h)
6441637d81c5SKristof Provost {
6442637d81c5SKristof Provost 	FREE_LIST(struct node_host, h);
6443637d81c5SKristof Provost }
6444637d81c5SKristof Provost 
64453b3a8eb9SGleb Smirnoff #undef FREE_LIST
64463b3a8eb9SGleb Smirnoff #undef LOOP_THROUGH
64473b3a8eb9SGleb Smirnoff 
64483b3a8eb9SGleb Smirnoff int
64493b3a8eb9SGleb Smirnoff check_rulestate(int desired_state)
64503b3a8eb9SGleb Smirnoff {
64513b3a8eb9SGleb Smirnoff 	if (require_order && (rulestate > desired_state)) {
64522b29ceb8SKristof Provost 		yyerror("Rules must be in order: options, ethernet, "
64532b29ceb8SKristof Provost 		    "normalization, queueing, translation, filtering");
64543b3a8eb9SGleb Smirnoff 		return (1);
64553b3a8eb9SGleb Smirnoff 	}
64563b3a8eb9SGleb Smirnoff 	rulestate = desired_state;
64573b3a8eb9SGleb Smirnoff 	return (0);
64583b3a8eb9SGleb Smirnoff }
64593b3a8eb9SGleb Smirnoff 
64603b3a8eb9SGleb Smirnoff int
64613b3a8eb9SGleb Smirnoff kw_cmp(const void *k, const void *e)
64623b3a8eb9SGleb Smirnoff {
64633b3a8eb9SGleb Smirnoff 	return (strcmp(k, ((const struct keywords *)e)->k_name));
64643b3a8eb9SGleb Smirnoff }
64653b3a8eb9SGleb Smirnoff 
64663b3a8eb9SGleb Smirnoff int
64673b3a8eb9SGleb Smirnoff lookup(char *s)
64683b3a8eb9SGleb Smirnoff {
64693b3a8eb9SGleb Smirnoff 	/* this has to be sorted always */
64703b3a8eb9SGleb Smirnoff 	static const struct keywords keywords[] = {
6471aa69fdf1SKristof Provost 		{ "af-to",		AFTO},
64723b3a8eb9SGleb Smirnoff 		{ "all",		ALL},
64733b3a8eb9SGleb Smirnoff 		{ "allow-opts",		ALLOWOPTS},
6474e4f2733dSKristof Provost 		{ "allow-related",	ALLOW_RELATED},
64753b3a8eb9SGleb Smirnoff 		{ "altq",		ALTQ},
64763b3a8eb9SGleb Smirnoff 		{ "anchor",		ANCHOR},
64773b3a8eb9SGleb Smirnoff 		{ "antispoof",		ANTISPOOF},
64783b3a8eb9SGleb Smirnoff 		{ "any",		ANY},
64793b3a8eb9SGleb Smirnoff 		{ "bandwidth",		BANDWIDTH},
64803b3a8eb9SGleb Smirnoff 		{ "binat",		BINAT},
64813b3a8eb9SGleb Smirnoff 		{ "binat-anchor",	BINATANCHOR},
64823b3a8eb9SGleb Smirnoff 		{ "bitmask",		BITMASK},
64833b3a8eb9SGleb Smirnoff 		{ "block",		BLOCK},
64843b3a8eb9SGleb Smirnoff 		{ "block-policy",	BLOCKPOLICY},
64858a8af942SKristof Provost 		{ "bridge-to",		BRIDGE_TO},
6486a5b789f6SErmal Luçi 		{ "buckets",		BUCKETS},
64873b3a8eb9SGleb Smirnoff 		{ "cbq",		CBQ},
64883b3a8eb9SGleb Smirnoff 		{ "code",		CODE},
64890a70aaf8SLuiz Otavio O Souza 		{ "codelq",		CODEL},
64903b3a8eb9SGleb Smirnoff 		{ "debug",		DEBUG},
64913b3a8eb9SGleb Smirnoff 		{ "divert-reply",	DIVERTREPLY},
64923b3a8eb9SGleb Smirnoff 		{ "divert-to",		DIVERTTO},
649363b3c1c7SKristof Provost 		{ "dnpipe",		DNPIPE},
649463b3c1c7SKristof Provost 		{ "dnqueue",		DNQUEUE},
64953b3a8eb9SGleb Smirnoff 		{ "drop",		DROP},
64963b3a8eb9SGleb Smirnoff 		{ "dup-to",		DUPTO},
6497390dc369STom Jones 		{ "endpoint-independent", ENDPI},
64982b29ceb8SKristof Provost 		{ "ether",		ETHER},
6499150182e3SKristof Provost 		{ "fail-policy",	FAILPOLICY},
6500a5b789f6SErmal Luçi 		{ "fairq",		FAIRQ},
65013b3a8eb9SGleb Smirnoff 		{ "fastroute",		FASTROUTE},
65023b3a8eb9SGleb Smirnoff 		{ "file",		FILENAME},
65033b3a8eb9SGleb Smirnoff 		{ "fingerprints",	FINGERPRINTS},
65043b3a8eb9SGleb Smirnoff 		{ "flags",		FLAGS},
65053b3a8eb9SGleb Smirnoff 		{ "floating",		FLOATING},
65063b3a8eb9SGleb Smirnoff 		{ "flush",		FLUSH},
65073b3a8eb9SGleb Smirnoff 		{ "for",		FOR},
65083b3a8eb9SGleb Smirnoff 		{ "fragment",		FRAGMENT},
65093b3a8eb9SGleb Smirnoff 		{ "from",		FROM},
65103b3a8eb9SGleb Smirnoff 		{ "global",		GLOBAL},
65113b3a8eb9SGleb Smirnoff 		{ "group",		GROUP},
65123b3a8eb9SGleb Smirnoff 		{ "hfsc",		HFSC},
6513a5b789f6SErmal Luçi 		{ "hogs",		HOGS},
65143b3a8eb9SGleb Smirnoff 		{ "hostid",		HOSTID},
65153b3a8eb9SGleb Smirnoff 		{ "icmp-type",		ICMPTYPE},
65163b3a8eb9SGleb Smirnoff 		{ "icmp6-type",		ICMP6TYPE},
65173b3a8eb9SGleb Smirnoff 		{ "if-bound",		IFBOUND},
65183b3a8eb9SGleb Smirnoff 		{ "in",			IN},
65193b3a8eb9SGleb Smirnoff 		{ "include",		INCLUDE},
65203b3a8eb9SGleb Smirnoff 		{ "inet",		INET},
65213b3a8eb9SGleb Smirnoff 		{ "inet6",		INET6},
65220a70aaf8SLuiz Otavio O Souza 		{ "interval",		INTERVAL},
65233b3a8eb9SGleb Smirnoff 		{ "keep",		KEEP},
652442ec75f8SKristof Provost 		{ "keepcounters",	KEEPCOUNTERS},
65258a42005dSKristof Provost 		{ "l3",			L3},
65263b3a8eb9SGleb Smirnoff 		{ "label",		LABEL},
65273b3a8eb9SGleb Smirnoff 		{ "limit",		LIMIT},
65283b3a8eb9SGleb Smirnoff 		{ "linkshare",		LINKSHARE},
65293b3a8eb9SGleb Smirnoff 		{ "load",		LOAD},
65303b3a8eb9SGleb Smirnoff 		{ "log",		LOG},
65313b3a8eb9SGleb Smirnoff 		{ "loginterface",	LOGINTERFACE},
65322aa21096SKurosawa Takahiro 		{ "map-e-portset",	MAPEPORTSET},
6533ef950daaSKristof Provost 		{ "match",		MATCH},
6534f3ab00c2SKristof Provost 		{ "matches",	MATCHES},
65353b3a8eb9SGleb Smirnoff 		{ "max",		MAXIMUM},
65363b3a8eb9SGleb Smirnoff 		{ "max-mss",		MAXMSS},
65373b3a8eb9SGleb Smirnoff 		{ "max-src-conn",	MAXSRCCONN},
65383b3a8eb9SGleb Smirnoff 		{ "max-src-conn-rate",	MAXSRCCONNRATE},
65393b3a8eb9SGleb Smirnoff 		{ "max-src-nodes",	MAXSRCNODES},
65403b3a8eb9SGleb Smirnoff 		{ "max-src-states",	MAXSRCSTATES},
65413b3a8eb9SGleb Smirnoff 		{ "min-ttl",		MINTTL},
65423b3a8eb9SGleb Smirnoff 		{ "modulate",		MODULATE},
65433b3a8eb9SGleb Smirnoff 		{ "nat",		NAT},
65443b3a8eb9SGleb Smirnoff 		{ "nat-anchor",		NATANCHOR},
65453b3a8eb9SGleb Smirnoff 		{ "no",			NO},
65463b3a8eb9SGleb Smirnoff 		{ "no-df",		NODF},
65473b3a8eb9SGleb Smirnoff 		{ "no-route",		NOROUTE},
65483b3a8eb9SGleb Smirnoff 		{ "no-sync",		NOSYNC},
65493b3a8eb9SGleb Smirnoff 		{ "on",			ON},
65503b3a8eb9SGleb Smirnoff 		{ "optimization",	OPTIMIZATION},
65513b3a8eb9SGleb Smirnoff 		{ "os",			OS},
65523b3a8eb9SGleb Smirnoff 		{ "out",		OUT},
65533b3a8eb9SGleb Smirnoff 		{ "overload",		OVERLOAD},
65543b3a8eb9SGleb Smirnoff 		{ "pass",		PASS},
6555baf9b6d0SKristof Provost 		{ "pflow",		PFLOW},
65563b3a8eb9SGleb Smirnoff 		{ "port",		PORT},
65573e248e0fSKristof Provost 		{ "prio",		PRIO},
65583b3a8eb9SGleb Smirnoff 		{ "priority",		PRIORITY},
65593b3a8eb9SGleb Smirnoff 		{ "priq",		PRIQ},
65603b3a8eb9SGleb Smirnoff 		{ "probability",	PROBABILITY},
65613b3a8eb9SGleb Smirnoff 		{ "proto",		PROTO},
65623b3a8eb9SGleb Smirnoff 		{ "qlimit",		QLIMIT},
65633b3a8eb9SGleb Smirnoff 		{ "queue",		QUEUE},
65643b3a8eb9SGleb Smirnoff 		{ "quick",		QUICK},
65653b3a8eb9SGleb Smirnoff 		{ "random",		RANDOM},
65663b3a8eb9SGleb Smirnoff 		{ "random-id",		RANDOMID},
65673b3a8eb9SGleb Smirnoff 		{ "rdr",		RDR},
65683b3a8eb9SGleb Smirnoff 		{ "rdr-anchor",		RDRANCHOR},
65693b3a8eb9SGleb Smirnoff 		{ "realtime",		REALTIME},
65703b3a8eb9SGleb Smirnoff 		{ "reassemble",		REASSEMBLE},
65712339ead6SKristof Provost 		{ "received-on",	RECEIVEDON},
65723b3a8eb9SGleb Smirnoff 		{ "reply-to",		REPLYTO},
65733b3a8eb9SGleb Smirnoff 		{ "require-order",	REQUIREORDER},
65743b3a8eb9SGleb Smirnoff 		{ "return",		RETURN},
65753b3a8eb9SGleb Smirnoff 		{ "return-icmp",	RETURNICMP},
65763b3a8eb9SGleb Smirnoff 		{ "return-icmp6",	RETURNICMP6},
65773b3a8eb9SGleb Smirnoff 		{ "return-rst",		RETURNRST},
657876c5eeccSKristof Provost 		{ "ridentifier",	RIDENTIFIER},
65793b3a8eb9SGleb Smirnoff 		{ "round-robin",	ROUNDROBIN},
65803b3a8eb9SGleb Smirnoff 		{ "route",		ROUTE},
65813b3a8eb9SGleb Smirnoff 		{ "route-to",		ROUTETO},
65823b3a8eb9SGleb Smirnoff 		{ "rtable",		RTABLE},
65833b3a8eb9SGleb Smirnoff 		{ "rule",		RULE},
65843b3a8eb9SGleb Smirnoff 		{ "ruleset-optimization",	RULESET_OPTIMIZATION},
65853b3a8eb9SGleb Smirnoff 		{ "scrub",		SCRUB},
65863b3a8eb9SGleb Smirnoff 		{ "set",		SET},
65873b3a8eb9SGleb Smirnoff 		{ "set-tos",		SETTOS},
65883b3a8eb9SGleb Smirnoff 		{ "skip",		SKIP},
65893b3a8eb9SGleb Smirnoff 		{ "sloppy",		SLOPPY},
65903b3a8eb9SGleb Smirnoff 		{ "source-hash",	SOURCEHASH},
65913b3a8eb9SGleb Smirnoff 		{ "source-track",	SOURCETRACK},
65923b3a8eb9SGleb Smirnoff 		{ "state",		STATE},
65933b3a8eb9SGleb Smirnoff 		{ "state-defaults",	STATEDEFAULTS},
65943b3a8eb9SGleb Smirnoff 		{ "state-policy",	STATEPOLICY},
65953b3a8eb9SGleb Smirnoff 		{ "static-port",	STATICPORT},
65963b3a8eb9SGleb Smirnoff 		{ "sticky-address",	STICKYADDRESS},
6597c69121c4SKristof Provost 		{ "syncookies",         SYNCOOKIES},
65983b3a8eb9SGleb Smirnoff 		{ "synproxy",		SYNPROXY},
65993b3a8eb9SGleb Smirnoff 		{ "table",		TABLE},
66003b3a8eb9SGleb Smirnoff 		{ "tag",		TAG},
66013b3a8eb9SGleb Smirnoff 		{ "tagged",		TAGGED},
66020a70aaf8SLuiz Otavio O Souza 		{ "target",		TARGET},
66033b3a8eb9SGleb Smirnoff 		{ "tbrsize",		TBRSIZE},
66043b3a8eb9SGleb Smirnoff 		{ "timeout",		TIMEOUT},
66053b3a8eb9SGleb Smirnoff 		{ "to",			TO},
66063b3a8eb9SGleb Smirnoff 		{ "tos",		TOS},
66073b3a8eb9SGleb Smirnoff 		{ "ttl",		TTL},
66083b3a8eb9SGleb Smirnoff 		{ "upperlimit",		UPPERLIMIT},
66093b3a8eb9SGleb Smirnoff 		{ "urpf-failed",	URPFFAILED},
66103b3a8eb9SGleb Smirnoff 		{ "user",		USER},
66113b3a8eb9SGleb Smirnoff 	};
66123b3a8eb9SGleb Smirnoff 	const struct keywords	*p;
66133b3a8eb9SGleb Smirnoff 
66143b3a8eb9SGleb Smirnoff 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
66153b3a8eb9SGleb Smirnoff 	    sizeof(keywords[0]), kw_cmp);
66163b3a8eb9SGleb Smirnoff 
66173b3a8eb9SGleb Smirnoff 	if (p) {
66183b3a8eb9SGleb Smirnoff 		if (debug > 1)
66193b3a8eb9SGleb Smirnoff 			fprintf(stderr, "%s: %d\n", s, p->k_val);
66203b3a8eb9SGleb Smirnoff 		return (p->k_val);
66213b3a8eb9SGleb Smirnoff 	} else {
66223b3a8eb9SGleb Smirnoff 		if (debug > 1)
66233b3a8eb9SGleb Smirnoff 			fprintf(stderr, "string: %s\n", s);
66243b3a8eb9SGleb Smirnoff 		return (STRING);
66253b3a8eb9SGleb Smirnoff 	}
66263b3a8eb9SGleb Smirnoff }
66273b3a8eb9SGleb Smirnoff 
66283b3a8eb9SGleb Smirnoff #define MAXPUSHBACK	128
66293b3a8eb9SGleb Smirnoff 
663013cfafabSKristof Provost static char	*parsebuf;
663113cfafabSKristof Provost static int	 parseindex;
663213cfafabSKristof Provost static char	 pushback_buffer[MAXPUSHBACK];
663313cfafabSKristof Provost static int	 pushback_index = 0;
66343b3a8eb9SGleb Smirnoff 
66353b3a8eb9SGleb Smirnoff int
66363b3a8eb9SGleb Smirnoff lgetc(int quotec)
66373b3a8eb9SGleb Smirnoff {
66383b3a8eb9SGleb Smirnoff 	int		c, next;
66393b3a8eb9SGleb Smirnoff 
66403b3a8eb9SGleb Smirnoff 	if (parsebuf) {
66413b3a8eb9SGleb Smirnoff 		/* Read character from the parsebuffer instead of input. */
66423b3a8eb9SGleb Smirnoff 		if (parseindex >= 0) {
66433b3a8eb9SGleb Smirnoff 			c = parsebuf[parseindex++];
66443b3a8eb9SGleb Smirnoff 			if (c != '\0')
66453b3a8eb9SGleb Smirnoff 				return (c);
66463b3a8eb9SGleb Smirnoff 			parsebuf = NULL;
66473b3a8eb9SGleb Smirnoff 		} else
66483b3a8eb9SGleb Smirnoff 			parseindex++;
66493b3a8eb9SGleb Smirnoff 	}
66503b3a8eb9SGleb Smirnoff 
66513b3a8eb9SGleb Smirnoff 	if (pushback_index)
66523b3a8eb9SGleb Smirnoff 		return (pushback_buffer[--pushback_index]);
66533b3a8eb9SGleb Smirnoff 
66543b3a8eb9SGleb Smirnoff 	if (quotec) {
66553b3a8eb9SGleb Smirnoff 		if ((c = getc(file->stream)) == EOF) {
66563b3a8eb9SGleb Smirnoff 			yyerror("reached end of file while parsing quoted string");
66573b3a8eb9SGleb Smirnoff 			if (popfile() == EOF)
66583b3a8eb9SGleb Smirnoff 				return (EOF);
66593b3a8eb9SGleb Smirnoff 			return (quotec);
66603b3a8eb9SGleb Smirnoff 		}
66613b3a8eb9SGleb Smirnoff 		return (c);
66623b3a8eb9SGleb Smirnoff 	}
66633b3a8eb9SGleb Smirnoff 
66643b3a8eb9SGleb Smirnoff 	while ((c = getc(file->stream)) == '\\') {
66653b3a8eb9SGleb Smirnoff 		next = getc(file->stream);
66663b3a8eb9SGleb Smirnoff 		if (next != '\n') {
66673b3a8eb9SGleb Smirnoff 			c = next;
66683b3a8eb9SGleb Smirnoff 			break;
66693b3a8eb9SGleb Smirnoff 		}
66703b3a8eb9SGleb Smirnoff 		yylval.lineno = file->lineno;
66713b3a8eb9SGleb Smirnoff 		file->lineno++;
66723b3a8eb9SGleb Smirnoff 	}
66733b3a8eb9SGleb Smirnoff 
66743b3a8eb9SGleb Smirnoff 	while (c == EOF) {
66753b3a8eb9SGleb Smirnoff 		if (popfile() == EOF)
66763b3a8eb9SGleb Smirnoff 			return (EOF);
66773b3a8eb9SGleb Smirnoff 		c = getc(file->stream);
66783b3a8eb9SGleb Smirnoff 	}
66793b3a8eb9SGleb Smirnoff 	return (c);
66803b3a8eb9SGleb Smirnoff }
66813b3a8eb9SGleb Smirnoff 
66823b3a8eb9SGleb Smirnoff int
66833b3a8eb9SGleb Smirnoff lungetc(int c)
66843b3a8eb9SGleb Smirnoff {
66853b3a8eb9SGleb Smirnoff 	if (c == EOF)
66863b3a8eb9SGleb Smirnoff 		return (EOF);
66873b3a8eb9SGleb Smirnoff 	if (parsebuf) {
66883b3a8eb9SGleb Smirnoff 		parseindex--;
66893b3a8eb9SGleb Smirnoff 		if (parseindex >= 0)
66903b3a8eb9SGleb Smirnoff 			return (c);
66913b3a8eb9SGleb Smirnoff 	}
66923b3a8eb9SGleb Smirnoff 	if (pushback_index < MAXPUSHBACK-1)
66933b3a8eb9SGleb Smirnoff 		return (pushback_buffer[pushback_index++] = c);
66943b3a8eb9SGleb Smirnoff 	else
66953b3a8eb9SGleb Smirnoff 		return (EOF);
66963b3a8eb9SGleb Smirnoff }
66973b3a8eb9SGleb Smirnoff 
66983b3a8eb9SGleb Smirnoff int
66993b3a8eb9SGleb Smirnoff findeol(void)
67003b3a8eb9SGleb Smirnoff {
67013b3a8eb9SGleb Smirnoff 	int	c;
67023b3a8eb9SGleb Smirnoff 
67033b3a8eb9SGleb Smirnoff 	parsebuf = NULL;
67043b3a8eb9SGleb Smirnoff 
67053b3a8eb9SGleb Smirnoff 	/* skip to either EOF or the first real EOL */
67063b3a8eb9SGleb Smirnoff 	while (1) {
67073b3a8eb9SGleb Smirnoff 		if (pushback_index)
67083b3a8eb9SGleb Smirnoff 			c = pushback_buffer[--pushback_index];
67093b3a8eb9SGleb Smirnoff 		else
67103b3a8eb9SGleb Smirnoff 			c = lgetc(0);
67113b3a8eb9SGleb Smirnoff 		if (c == '\n') {
67123b3a8eb9SGleb Smirnoff 			file->lineno++;
67133b3a8eb9SGleb Smirnoff 			break;
67143b3a8eb9SGleb Smirnoff 		}
67153b3a8eb9SGleb Smirnoff 		if (c == EOF)
67163b3a8eb9SGleb Smirnoff 			break;
67173b3a8eb9SGleb Smirnoff 	}
67183b3a8eb9SGleb Smirnoff 	return (ERROR);
67193b3a8eb9SGleb Smirnoff }
67203b3a8eb9SGleb Smirnoff 
67213b3a8eb9SGleb Smirnoff int
67223b3a8eb9SGleb Smirnoff yylex(void)
67233b3a8eb9SGleb Smirnoff {
67243b3a8eb9SGleb Smirnoff 	char	 buf[8096];
67253b3a8eb9SGleb Smirnoff 	char	*p, *val;
67263b3a8eb9SGleb Smirnoff 	int	 quotec, next, c;
67273b3a8eb9SGleb Smirnoff 	int	 token;
67283b3a8eb9SGleb Smirnoff 
67293b3a8eb9SGleb Smirnoff top:
67303b3a8eb9SGleb Smirnoff 	p = buf;
67313b3a8eb9SGleb Smirnoff 	while ((c = lgetc(0)) == ' ' || c == '\t')
67323b3a8eb9SGleb Smirnoff 		; /* nothing */
67333b3a8eb9SGleb Smirnoff 
67343b3a8eb9SGleb Smirnoff 	yylval.lineno = file->lineno;
67353b3a8eb9SGleb Smirnoff 	if (c == '#')
67363b3a8eb9SGleb Smirnoff 		while ((c = lgetc(0)) != '\n' && c != EOF)
67373b3a8eb9SGleb Smirnoff 			; /* nothing */
67383b3a8eb9SGleb Smirnoff 	if (c == '$' && parsebuf == NULL) {
67393b3a8eb9SGleb Smirnoff 		while (1) {
67403b3a8eb9SGleb Smirnoff 			if ((c = lgetc(0)) == EOF)
67413b3a8eb9SGleb Smirnoff 				return (0);
67423b3a8eb9SGleb Smirnoff 
67433b3a8eb9SGleb Smirnoff 			if (p + 1 >= buf + sizeof(buf) - 1) {
67443b3a8eb9SGleb Smirnoff 				yyerror("string too long");
67453b3a8eb9SGleb Smirnoff 				return (findeol());
67463b3a8eb9SGleb Smirnoff 			}
67473b3a8eb9SGleb Smirnoff 			if (isalnum(c) || c == '_') {
67483b3a8eb9SGleb Smirnoff 				*p++ = (char)c;
67493b3a8eb9SGleb Smirnoff 				continue;
67503b3a8eb9SGleb Smirnoff 			}
67513b3a8eb9SGleb Smirnoff 			*p = '\0';
67523b3a8eb9SGleb Smirnoff 			lungetc(c);
67533b3a8eb9SGleb Smirnoff 			break;
67543b3a8eb9SGleb Smirnoff 		}
67553b3a8eb9SGleb Smirnoff 		val = symget(buf);
67563b3a8eb9SGleb Smirnoff 		if (val == NULL) {
67573b3a8eb9SGleb Smirnoff 			yyerror("macro '%s' not defined", buf);
67583b3a8eb9SGleb Smirnoff 			return (findeol());
67593b3a8eb9SGleb Smirnoff 		}
67603b3a8eb9SGleb Smirnoff 		parsebuf = val;
67613b3a8eb9SGleb Smirnoff 		parseindex = 0;
67623b3a8eb9SGleb Smirnoff 		goto top;
67633b3a8eb9SGleb Smirnoff 	}
67643b3a8eb9SGleb Smirnoff 
67653b3a8eb9SGleb Smirnoff 	switch (c) {
67663b3a8eb9SGleb Smirnoff 	case '\'':
67673b3a8eb9SGleb Smirnoff 	case '"':
67683b3a8eb9SGleb Smirnoff 		quotec = c;
67693b3a8eb9SGleb Smirnoff 		while (1) {
67703b3a8eb9SGleb Smirnoff 			if ((c = lgetc(quotec)) == EOF)
67713b3a8eb9SGleb Smirnoff 				return (0);
67723b3a8eb9SGleb Smirnoff 			if (c == '\n') {
67733b3a8eb9SGleb Smirnoff 				file->lineno++;
67743b3a8eb9SGleb Smirnoff 				continue;
67753b3a8eb9SGleb Smirnoff 			} else if (c == '\\') {
67763b3a8eb9SGleb Smirnoff 				if ((next = lgetc(quotec)) == EOF)
67773b3a8eb9SGleb Smirnoff 					return (0);
67783b3a8eb9SGleb Smirnoff 				if (next == quotec || c == ' ' || c == '\t')
67793b3a8eb9SGleb Smirnoff 					c = next;
67804a8e4793SKristof Provost 				else if (next == '\n') {
67814a8e4793SKristof Provost 					file->lineno++;
67823b3a8eb9SGleb Smirnoff 					continue;
67834a8e4793SKristof Provost 				}
67843b3a8eb9SGleb Smirnoff 				else
67853b3a8eb9SGleb Smirnoff 					lungetc(next);
67863b3a8eb9SGleb Smirnoff 			} else if (c == quotec) {
67873b3a8eb9SGleb Smirnoff 				*p = '\0';
67883b3a8eb9SGleb Smirnoff 				break;
67893b3a8eb9SGleb Smirnoff 			}
67903b3a8eb9SGleb Smirnoff 			if (p + 1 >= buf + sizeof(buf) - 1) {
67913b3a8eb9SGleb Smirnoff 				yyerror("string too long");
67923b3a8eb9SGleb Smirnoff 				return (findeol());
67933b3a8eb9SGleb Smirnoff 			}
67943b3a8eb9SGleb Smirnoff 			*p++ = (char)c;
67953b3a8eb9SGleb Smirnoff 		}
67963b3a8eb9SGleb Smirnoff 		yylval.v.string = strdup(buf);
67973b3a8eb9SGleb Smirnoff 		if (yylval.v.string == NULL)
67983b3a8eb9SGleb Smirnoff 			err(1, "yylex: strdup");
67993b3a8eb9SGleb Smirnoff 		return (STRING);
680080eb861dSKristof Provost 		case '!':
680180eb861dSKristof Provost 			next = lgetc(0);
680280eb861dSKristof Provost 			if (next == '=')
680380eb861dSKristof Provost 				return (NE);
680480eb861dSKristof Provost 			lungetc(next);
680580eb861dSKristof Provost 		break;
68063b3a8eb9SGleb Smirnoff 	case '<':
68073b3a8eb9SGleb Smirnoff 		next = lgetc(0);
68083b3a8eb9SGleb Smirnoff 		if (next == '>') {
68093b3a8eb9SGleb Smirnoff 			yylval.v.i = PF_OP_XRG;
68103b3a8eb9SGleb Smirnoff 			return (PORTBINARY);
681180eb861dSKristof Provost 		} else if (next == '=')
681280eb861dSKristof Provost 			return (LE);
68133b3a8eb9SGleb Smirnoff 		lungetc(next);
68143b3a8eb9SGleb Smirnoff 		break;
68153b3a8eb9SGleb Smirnoff 	case '>':
68163b3a8eb9SGleb Smirnoff 		next = lgetc(0);
68173b3a8eb9SGleb Smirnoff 		if (next == '<') {
68183b3a8eb9SGleb Smirnoff 			yylval.v.i = PF_OP_IRG;
68193b3a8eb9SGleb Smirnoff 			return (PORTBINARY);
682080eb861dSKristof Provost 		} else if (next == '=')
682180eb861dSKristof Provost 			return (GE);
68223b3a8eb9SGleb Smirnoff 		lungetc(next);
68233b3a8eb9SGleb Smirnoff 		break;
68243b3a8eb9SGleb Smirnoff 	case '-':
68253b3a8eb9SGleb Smirnoff 		next = lgetc(0);
68263b3a8eb9SGleb Smirnoff 		if (next == '>')
68273b3a8eb9SGleb Smirnoff 			return (ARROW);
68283b3a8eb9SGleb Smirnoff 		lungetc(next);
68293b3a8eb9SGleb Smirnoff 		break;
68303b3a8eb9SGleb Smirnoff 	}
68313b3a8eb9SGleb Smirnoff 
68323b3a8eb9SGleb Smirnoff #define allowed_to_end_number(x) \
68333b3a8eb9SGleb Smirnoff 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
68343b3a8eb9SGleb Smirnoff 
68353b3a8eb9SGleb Smirnoff 	if (c == '-' || isdigit(c)) {
68363b3a8eb9SGleb Smirnoff 		do {
68373b3a8eb9SGleb Smirnoff 			*p++ = c;
68383b3a8eb9SGleb Smirnoff 			if ((unsigned)(p-buf) >= sizeof(buf)) {
68393b3a8eb9SGleb Smirnoff 				yyerror("string too long");
68403b3a8eb9SGleb Smirnoff 				return (findeol());
68413b3a8eb9SGleb Smirnoff 			}
68423b3a8eb9SGleb Smirnoff 		} while ((c = lgetc(0)) != EOF && isdigit(c));
68433b3a8eb9SGleb Smirnoff 		lungetc(c);
68443b3a8eb9SGleb Smirnoff 		if (p == buf + 1 && buf[0] == '-')
68453b3a8eb9SGleb Smirnoff 			goto nodigits;
68463b3a8eb9SGleb Smirnoff 		if (c == EOF || allowed_to_end_number(c)) {
68473b3a8eb9SGleb Smirnoff 			const char *errstr = NULL;
68483b3a8eb9SGleb Smirnoff 
68493b3a8eb9SGleb Smirnoff 			*p = '\0';
68503b3a8eb9SGleb Smirnoff 			yylval.v.number = strtonum(buf, LLONG_MIN,
68513b3a8eb9SGleb Smirnoff 			    LLONG_MAX, &errstr);
68523b3a8eb9SGleb Smirnoff 			if (errstr) {
68533b3a8eb9SGleb Smirnoff 				yyerror("\"%s\" invalid number: %s",
68543b3a8eb9SGleb Smirnoff 				    buf, errstr);
68553b3a8eb9SGleb Smirnoff 				return (findeol());
68563b3a8eb9SGleb Smirnoff 			}
68573b3a8eb9SGleb Smirnoff 			return (NUMBER);
68583b3a8eb9SGleb Smirnoff 		} else {
68593b3a8eb9SGleb Smirnoff nodigits:
68603b3a8eb9SGleb Smirnoff 			while (p > buf + 1)
68613b3a8eb9SGleb Smirnoff 				lungetc(*--p);
68623b3a8eb9SGleb Smirnoff 			c = *--p;
68633b3a8eb9SGleb Smirnoff 			if (c == '-')
68643b3a8eb9SGleb Smirnoff 				return (c);
68653b3a8eb9SGleb Smirnoff 		}
68663b3a8eb9SGleb Smirnoff 	}
68673b3a8eb9SGleb Smirnoff 
68683b3a8eb9SGleb Smirnoff #define allowed_in_string(x) \
68693b3a8eb9SGleb Smirnoff 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
68703b3a8eb9SGleb Smirnoff 	x != '{' && x != '}' && x != '<' && x != '>' && \
68713b3a8eb9SGleb Smirnoff 	x != '!' && x != '=' && x != '/' && x != '#' && \
68723b3a8eb9SGleb Smirnoff 	x != ','))
68733b3a8eb9SGleb Smirnoff 
68743b3a8eb9SGleb Smirnoff 	if (isalnum(c) || c == ':' || c == '_') {
68753b3a8eb9SGleb Smirnoff 		do {
68763b3a8eb9SGleb Smirnoff 			*p++ = c;
68773b3a8eb9SGleb Smirnoff 			if ((unsigned)(p-buf) >= sizeof(buf)) {
68783b3a8eb9SGleb Smirnoff 				yyerror("string too long");
68793b3a8eb9SGleb Smirnoff 				return (findeol());
68803b3a8eb9SGleb Smirnoff 			}
68813b3a8eb9SGleb Smirnoff 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
68823b3a8eb9SGleb Smirnoff 		lungetc(c);
68833b3a8eb9SGleb Smirnoff 		*p = '\0';
68843b3a8eb9SGleb Smirnoff 		if ((token = lookup(buf)) == STRING)
68853b3a8eb9SGleb Smirnoff 			if ((yylval.v.string = strdup(buf)) == NULL)
68863b3a8eb9SGleb Smirnoff 				err(1, "yylex: strdup");
68873b3a8eb9SGleb Smirnoff 		return (token);
68883b3a8eb9SGleb Smirnoff 	}
68893b3a8eb9SGleb Smirnoff 	if (c == '\n') {
68903b3a8eb9SGleb Smirnoff 		yylval.lineno = file->lineno;
68913b3a8eb9SGleb Smirnoff 		file->lineno++;
68923b3a8eb9SGleb Smirnoff 	}
68933b3a8eb9SGleb Smirnoff 	if (c == EOF)
68943b3a8eb9SGleb Smirnoff 		return (0);
68953b3a8eb9SGleb Smirnoff 	return (c);
68963b3a8eb9SGleb Smirnoff }
68973b3a8eb9SGleb Smirnoff 
68983b3a8eb9SGleb Smirnoff int
68993b3a8eb9SGleb Smirnoff check_file_secrecy(int fd, const char *fname)
69003b3a8eb9SGleb Smirnoff {
69013b3a8eb9SGleb Smirnoff 	struct stat	st;
69023b3a8eb9SGleb Smirnoff 
69033b3a8eb9SGleb Smirnoff 	if (fstat(fd, &st)) {
69043b3a8eb9SGleb Smirnoff 		warn("cannot stat %s", fname);
69053b3a8eb9SGleb Smirnoff 		return (-1);
69063b3a8eb9SGleb Smirnoff 	}
69073b3a8eb9SGleb Smirnoff 	if (st.st_uid != 0 && st.st_uid != getuid()) {
69083b3a8eb9SGleb Smirnoff 		warnx("%s: owner not root or current user", fname);
69093b3a8eb9SGleb Smirnoff 		return (-1);
69103b3a8eb9SGleb Smirnoff 	}
69113b3a8eb9SGleb Smirnoff 	if (st.st_mode & (S_IRWXG | S_IRWXO)) {
69123b3a8eb9SGleb Smirnoff 		warnx("%s: group/world readable/writeable", fname);
69133b3a8eb9SGleb Smirnoff 		return (-1);
69143b3a8eb9SGleb Smirnoff 	}
69153b3a8eb9SGleb Smirnoff 	return (0);
69163b3a8eb9SGleb Smirnoff }
69173b3a8eb9SGleb Smirnoff 
69183b3a8eb9SGleb Smirnoff struct file *
69193b3a8eb9SGleb Smirnoff pushfile(const char *name, int secret)
69203b3a8eb9SGleb Smirnoff {
69213b3a8eb9SGleb Smirnoff 	struct file	*nfile;
69223b3a8eb9SGleb Smirnoff 
69233b3a8eb9SGleb Smirnoff 	if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
69243b3a8eb9SGleb Smirnoff 	    (nfile->name = strdup(name)) == NULL) {
69253b3a8eb9SGleb Smirnoff 		warn("malloc");
69263b3a8eb9SGleb Smirnoff 		return (NULL);
69273b3a8eb9SGleb Smirnoff 	}
69283b3a8eb9SGleb Smirnoff 	if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
69293b3a8eb9SGleb Smirnoff 		nfile->stream = stdin;
69303b3a8eb9SGleb Smirnoff 		free(nfile->name);
69313b3a8eb9SGleb Smirnoff 		if ((nfile->name = strdup("stdin")) == NULL) {
69323b3a8eb9SGleb Smirnoff 			warn("strdup");
69333b3a8eb9SGleb Smirnoff 			free(nfile);
69343b3a8eb9SGleb Smirnoff 			return (NULL);
69353b3a8eb9SGleb Smirnoff 		}
69363b3a8eb9SGleb Smirnoff 	} else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
69373b3a8eb9SGleb Smirnoff 		warn("%s", nfile->name);
69383b3a8eb9SGleb Smirnoff 		free(nfile->name);
69393b3a8eb9SGleb Smirnoff 		free(nfile);
69403b3a8eb9SGleb Smirnoff 		return (NULL);
69413b3a8eb9SGleb Smirnoff 	} else if (secret &&
69423b3a8eb9SGleb Smirnoff 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
69433b3a8eb9SGleb Smirnoff 		fclose(nfile->stream);
69443b3a8eb9SGleb Smirnoff 		free(nfile->name);
69453b3a8eb9SGleb Smirnoff 		free(nfile);
69463b3a8eb9SGleb Smirnoff 		return (NULL);
69473b3a8eb9SGleb Smirnoff 	}
69483b3a8eb9SGleb Smirnoff 	nfile->lineno = 1;
69493b3a8eb9SGleb Smirnoff 	TAILQ_INSERT_TAIL(&files, nfile, entry);
69503b3a8eb9SGleb Smirnoff 	return (nfile);
69513b3a8eb9SGleb Smirnoff }
69523b3a8eb9SGleb Smirnoff 
69533b3a8eb9SGleb Smirnoff int
69543b3a8eb9SGleb Smirnoff popfile(void)
69553b3a8eb9SGleb Smirnoff {
69563b3a8eb9SGleb Smirnoff 	struct file	*prev;
69573b3a8eb9SGleb Smirnoff 
69583b3a8eb9SGleb Smirnoff 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
69593b3a8eb9SGleb Smirnoff 		prev->errors += file->errors;
69603b3a8eb9SGleb Smirnoff 		TAILQ_REMOVE(&files, file, entry);
69613b3a8eb9SGleb Smirnoff 		fclose(file->stream);
69623b3a8eb9SGleb Smirnoff 		free(file->name);
69633b3a8eb9SGleb Smirnoff 		free(file);
69643b3a8eb9SGleb Smirnoff 		file = prev;
69653b3a8eb9SGleb Smirnoff 		return (0);
69663b3a8eb9SGleb Smirnoff 	}
69673b3a8eb9SGleb Smirnoff 	return (EOF);
69683b3a8eb9SGleb Smirnoff }
69693b3a8eb9SGleb Smirnoff 
69703b3a8eb9SGleb Smirnoff int
69713b3a8eb9SGleb Smirnoff parse_config(char *filename, struct pfctl *xpf)
69723b3a8eb9SGleb Smirnoff {
69733b3a8eb9SGleb Smirnoff 	int		 errors = 0;
69743b3a8eb9SGleb Smirnoff 	struct sym	*sym;
69753b3a8eb9SGleb Smirnoff 
69763b3a8eb9SGleb Smirnoff 	pf = xpf;
69773b3a8eb9SGleb Smirnoff 	errors = 0;
69783b3a8eb9SGleb Smirnoff 	rulestate = PFCTL_STATE_NONE;
69793b3a8eb9SGleb Smirnoff 	returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
69803b3a8eb9SGleb Smirnoff 	returnicmp6default =
69813b3a8eb9SGleb Smirnoff 	    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
69823b3a8eb9SGleb Smirnoff 	blockpolicy = PFRULE_DROP;
6983150182e3SKristof Provost 	failpolicy = PFRULE_DROP;
69843b3a8eb9SGleb Smirnoff 	require_order = 1;
69853b3a8eb9SGleb Smirnoff 
69863b3a8eb9SGleb Smirnoff 	if ((file = pushfile(filename, 0)) == NULL) {
69873b3a8eb9SGleb Smirnoff 		warn("cannot open the main config file!");
69883b3a8eb9SGleb Smirnoff 		return (-1);
69893b3a8eb9SGleb Smirnoff 	}
69903b3a8eb9SGleb Smirnoff 
69913b3a8eb9SGleb Smirnoff 	yyparse();
69923b3a8eb9SGleb Smirnoff 	errors = file->errors;
69933b3a8eb9SGleb Smirnoff 	popfile();
69943b3a8eb9SGleb Smirnoff 
69953b3a8eb9SGleb Smirnoff 	/* Free macros and check which have not been used. */
69963b3a8eb9SGleb Smirnoff 	while ((sym = TAILQ_FIRST(&symhead))) {
69973b3a8eb9SGleb Smirnoff 		if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
69983b3a8eb9SGleb Smirnoff 			fprintf(stderr, "warning: macro '%s' not "
69993b3a8eb9SGleb Smirnoff 			    "used\n", sym->nam);
70003b3a8eb9SGleb Smirnoff 		free(sym->nam);
70013b3a8eb9SGleb Smirnoff 		free(sym->val);
70023b3a8eb9SGleb Smirnoff 		TAILQ_REMOVE(&symhead, sym, entry);
70033b3a8eb9SGleb Smirnoff 		free(sym);
70043b3a8eb9SGleb Smirnoff 	}
70053b3a8eb9SGleb Smirnoff 
70063b3a8eb9SGleb Smirnoff 	return (errors ? -1 : 0);
70073b3a8eb9SGleb Smirnoff }
70083b3a8eb9SGleb Smirnoff 
70093b3a8eb9SGleb Smirnoff int
70103b3a8eb9SGleb Smirnoff symset(const char *nam, const char *val, int persist)
70113b3a8eb9SGleb Smirnoff {
70123b3a8eb9SGleb Smirnoff 	struct sym	*sym;
70133b3a8eb9SGleb Smirnoff 
70143b3a8eb9SGleb Smirnoff 	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
70153b3a8eb9SGleb Smirnoff 	    sym = TAILQ_NEXT(sym, entry))
70163b3a8eb9SGleb Smirnoff 		;	/* nothing */
70173b3a8eb9SGleb Smirnoff 
70183b3a8eb9SGleb Smirnoff 	if (sym != NULL) {
70193b3a8eb9SGleb Smirnoff 		if (sym->persist == 1)
70203b3a8eb9SGleb Smirnoff 			return (0);
70213b3a8eb9SGleb Smirnoff 		else {
70223b3a8eb9SGleb Smirnoff 			free(sym->nam);
70233b3a8eb9SGleb Smirnoff 			free(sym->val);
70243b3a8eb9SGleb Smirnoff 			TAILQ_REMOVE(&symhead, sym, entry);
70253b3a8eb9SGleb Smirnoff 			free(sym);
70263b3a8eb9SGleb Smirnoff 		}
70273b3a8eb9SGleb Smirnoff 	}
70283b3a8eb9SGleb Smirnoff 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
70293b3a8eb9SGleb Smirnoff 		return (-1);
70303b3a8eb9SGleb Smirnoff 
70313b3a8eb9SGleb Smirnoff 	sym->nam = strdup(nam);
70323b3a8eb9SGleb Smirnoff 	if (sym->nam == NULL) {
70333b3a8eb9SGleb Smirnoff 		free(sym);
70343b3a8eb9SGleb Smirnoff 		return (-1);
70353b3a8eb9SGleb Smirnoff 	}
70363b3a8eb9SGleb Smirnoff 	sym->val = strdup(val);
70373b3a8eb9SGleb Smirnoff 	if (sym->val == NULL) {
70383b3a8eb9SGleb Smirnoff 		free(sym->nam);
70393b3a8eb9SGleb Smirnoff 		free(sym);
70403b3a8eb9SGleb Smirnoff 		return (-1);
70413b3a8eb9SGleb Smirnoff 	}
70423b3a8eb9SGleb Smirnoff 	sym->used = 0;
70433b3a8eb9SGleb Smirnoff 	sym->persist = persist;
70443b3a8eb9SGleb Smirnoff 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
70453b3a8eb9SGleb Smirnoff 	return (0);
70463b3a8eb9SGleb Smirnoff }
70473b3a8eb9SGleb Smirnoff 
70483b3a8eb9SGleb Smirnoff int
70493b3a8eb9SGleb Smirnoff pfctl_cmdline_symset(char *s)
70503b3a8eb9SGleb Smirnoff {
70513b3a8eb9SGleb Smirnoff 	char	*sym, *val;
70523b3a8eb9SGleb Smirnoff 	int	 ret;
70533b3a8eb9SGleb Smirnoff 
70543b3a8eb9SGleb Smirnoff 	if ((val = strrchr(s, '=')) == NULL)
70553b3a8eb9SGleb Smirnoff 		return (-1);
70563b3a8eb9SGleb Smirnoff 
70573b3a8eb9SGleb Smirnoff 	if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
70583b3a8eb9SGleb Smirnoff 		err(1, "pfctl_cmdline_symset: malloc");
70593b3a8eb9SGleb Smirnoff 
70603b3a8eb9SGleb Smirnoff 	strlcpy(sym, s, strlen(s) - strlen(val) + 1);
70613b3a8eb9SGleb Smirnoff 
70623b3a8eb9SGleb Smirnoff 	ret = symset(sym, val + 1, 1);
70633b3a8eb9SGleb Smirnoff 	free(sym);
70643b3a8eb9SGleb Smirnoff 
70653b3a8eb9SGleb Smirnoff 	return (ret);
70663b3a8eb9SGleb Smirnoff }
70673b3a8eb9SGleb Smirnoff 
70683b3a8eb9SGleb Smirnoff char *
70693b3a8eb9SGleb Smirnoff symget(const char *nam)
70703b3a8eb9SGleb Smirnoff {
70713b3a8eb9SGleb Smirnoff 	struct sym	*sym;
70723b3a8eb9SGleb Smirnoff 
70733b3a8eb9SGleb Smirnoff 	TAILQ_FOREACH(sym, &symhead, entry)
70743b3a8eb9SGleb Smirnoff 		if (strcmp(nam, sym->nam) == 0) {
70753b3a8eb9SGleb Smirnoff 			sym->used = 1;
70763b3a8eb9SGleb Smirnoff 			return (sym->val);
70773b3a8eb9SGleb Smirnoff 		}
70783b3a8eb9SGleb Smirnoff 	return (NULL);
70793b3a8eb9SGleb Smirnoff }
70803b3a8eb9SGleb Smirnoff 
70813b3a8eb9SGleb Smirnoff void
7082e9eb0941SKristof Provost mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst)
70833b3a8eb9SGleb Smirnoff {
70843b3a8eb9SGleb Smirnoff 	int i;
7085e9eb0941SKristof Provost 	struct pfctl_rule *r;
70863b3a8eb9SGleb Smirnoff 
70873b3a8eb9SGleb Smirnoff 	for (i = 0; i < PF_RULESET_MAX; ++i) {
70883b3a8eb9SGleb Smirnoff 		while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
70893b3a8eb9SGleb Smirnoff 		    != NULL) {
70903b3a8eb9SGleb Smirnoff 			TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
70913b3a8eb9SGleb Smirnoff 			TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
70923b3a8eb9SGleb Smirnoff 			dst->anchor->match++;
70933b3a8eb9SGleb Smirnoff 		}
70943b3a8eb9SGleb Smirnoff 		src->anchor->match = 0;
70953b3a8eb9SGleb Smirnoff 		while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
70963b3a8eb9SGleb Smirnoff 		    != NULL) {
70973b3a8eb9SGleb Smirnoff 			TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
70983b3a8eb9SGleb Smirnoff 			TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
70993b3a8eb9SGleb Smirnoff 				r, entries);
71003b3a8eb9SGleb Smirnoff 		}
71013b3a8eb9SGleb Smirnoff 	}
71023b3a8eb9SGleb Smirnoff }
71033b3a8eb9SGleb Smirnoff 
71043b3a8eb9SGleb Smirnoff void
7105c5131afeSKristof Provost mv_eth_rules(struct pfctl_eth_ruleset *src, struct pfctl_eth_ruleset *dst)
7106c5131afeSKristof Provost {
7107c5131afeSKristof Provost 	struct pfctl_eth_rule *r;
7108c5131afeSKristof Provost 
7109c5131afeSKristof Provost 	while ((r = TAILQ_FIRST(&src->rules)) != NULL) {
7110c5131afeSKristof Provost 		TAILQ_REMOVE(&src->rules, r, entries);
7111c5131afeSKristof Provost 		TAILQ_INSERT_TAIL(&dst->rules, r, entries);
7112c5131afeSKristof Provost 		dst->anchor->match++;
7113c5131afeSKristof Provost 	}
7114c5131afeSKristof Provost 	src->anchor->match = 0;
7115c5131afeSKristof Provost }
7116c5131afeSKristof Provost 
7117c5131afeSKristof Provost void
71183b3a8eb9SGleb Smirnoff decide_address_family(struct node_host *n, sa_family_t *af)
71193b3a8eb9SGleb Smirnoff {
71203b3a8eb9SGleb Smirnoff 	if (*af != 0 || n == NULL)
71213b3a8eb9SGleb Smirnoff 		return;
71223b3a8eb9SGleb Smirnoff 	*af = n->af;
71233b3a8eb9SGleb Smirnoff 	while ((n = n->next) != NULL) {
71243b3a8eb9SGleb Smirnoff 		if (n->af != *af) {
71253b3a8eb9SGleb Smirnoff 			*af = 0;
71263b3a8eb9SGleb Smirnoff 			return;
71273b3a8eb9SGleb Smirnoff 		}
71283b3a8eb9SGleb Smirnoff 	}
71293b3a8eb9SGleb Smirnoff }
71303b3a8eb9SGleb Smirnoff 
71313b3a8eb9SGleb Smirnoff void
71323b3a8eb9SGleb Smirnoff remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
71333b3a8eb9SGleb Smirnoff {
71343b3a8eb9SGleb Smirnoff 	struct node_host	*n = *nh, *prev = NULL;
71353b3a8eb9SGleb Smirnoff 
71363b3a8eb9SGleb Smirnoff 	while (n != NULL) {
71373b3a8eb9SGleb Smirnoff 		if (*af && n->af && n->af != *af) {
71383b3a8eb9SGleb Smirnoff 			/* unlink and free n */
71393b3a8eb9SGleb Smirnoff 			struct node_host *next = n->next;
71403b3a8eb9SGleb Smirnoff 
71413b3a8eb9SGleb Smirnoff 			/* adjust tail pointer */
71423b3a8eb9SGleb Smirnoff 			if (n == (*nh)->tail)
71433b3a8eb9SGleb Smirnoff 				(*nh)->tail = prev;
71443b3a8eb9SGleb Smirnoff 			/* adjust previous node's next pointer */
71453b3a8eb9SGleb Smirnoff 			if (prev == NULL)
71463b3a8eb9SGleb Smirnoff 				*nh = next;
71473b3a8eb9SGleb Smirnoff 			else
71483b3a8eb9SGleb Smirnoff 				prev->next = next;
71493b3a8eb9SGleb Smirnoff 			/* free node */
71503b3a8eb9SGleb Smirnoff 			if (n->ifname != NULL)
71513b3a8eb9SGleb Smirnoff 				free(n->ifname);
71523b3a8eb9SGleb Smirnoff 			free(n);
71533b3a8eb9SGleb Smirnoff 			n = next;
71543b3a8eb9SGleb Smirnoff 		} else {
71553b3a8eb9SGleb Smirnoff 			if (n->af && !*af)
71563b3a8eb9SGleb Smirnoff 				*af = n->af;
71573b3a8eb9SGleb Smirnoff 			prev = n;
71583b3a8eb9SGleb Smirnoff 			n = n->next;
71593b3a8eb9SGleb Smirnoff 		}
71603b3a8eb9SGleb Smirnoff 	}
71613b3a8eb9SGleb Smirnoff }
71623b3a8eb9SGleb Smirnoff 
71633b3a8eb9SGleb Smirnoff int
71643b3a8eb9SGleb Smirnoff invalid_redirect(struct node_host *nh, sa_family_t af)
71653b3a8eb9SGleb Smirnoff {
71663b3a8eb9SGleb Smirnoff 	if (!af) {
71673b3a8eb9SGleb Smirnoff 		struct node_host *n;
71683b3a8eb9SGleb Smirnoff 
71693b3a8eb9SGleb Smirnoff 		/* tables and dyniftl are ok without an address family */
71703b3a8eb9SGleb Smirnoff 		for (n = nh; n != NULL; n = n->next) {
71713b3a8eb9SGleb Smirnoff 			if (n->addr.type != PF_ADDR_TABLE &&
71723b3a8eb9SGleb Smirnoff 			    n->addr.type != PF_ADDR_DYNIFTL) {
71733b3a8eb9SGleb Smirnoff 				yyerror("address family not given and "
71743b3a8eb9SGleb Smirnoff 				    "translation address expands to multiple "
71753b3a8eb9SGleb Smirnoff 				    "address families");
71763b3a8eb9SGleb Smirnoff 				return (1);
71773b3a8eb9SGleb Smirnoff 			}
71783b3a8eb9SGleb Smirnoff 		}
71793b3a8eb9SGleb Smirnoff 	}
71803b3a8eb9SGleb Smirnoff 	if (nh == NULL) {
71813b3a8eb9SGleb Smirnoff 		yyerror("no translation address with matching address family "
71823b3a8eb9SGleb Smirnoff 		    "found.");
71833b3a8eb9SGleb Smirnoff 		return (1);
71843b3a8eb9SGleb Smirnoff 	}
71853b3a8eb9SGleb Smirnoff 	return (0);
71863b3a8eb9SGleb Smirnoff }
71873b3a8eb9SGleb Smirnoff 
71883b3a8eb9SGleb Smirnoff int
71893b3a8eb9SGleb Smirnoff atoul(char *s, u_long *ulvalp)
71903b3a8eb9SGleb Smirnoff {
71913b3a8eb9SGleb Smirnoff 	u_long	 ulval;
71923b3a8eb9SGleb Smirnoff 	char	*ep;
71933b3a8eb9SGleb Smirnoff 
71943b3a8eb9SGleb Smirnoff 	errno = 0;
71953b3a8eb9SGleb Smirnoff 	ulval = strtoul(s, &ep, 0);
71963b3a8eb9SGleb Smirnoff 	if (s[0] == '\0' || *ep != '\0')
71973b3a8eb9SGleb Smirnoff 		return (-1);
71983b3a8eb9SGleb Smirnoff 	if (errno == ERANGE && ulval == ULONG_MAX)
71993b3a8eb9SGleb Smirnoff 		return (-1);
72003b3a8eb9SGleb Smirnoff 	*ulvalp = ulval;
72013b3a8eb9SGleb Smirnoff 	return (0);
72023b3a8eb9SGleb Smirnoff }
72033b3a8eb9SGleb Smirnoff 
72043b3a8eb9SGleb Smirnoff int
72053b3a8eb9SGleb Smirnoff getservice(char *n)
72063b3a8eb9SGleb Smirnoff {
72073b3a8eb9SGleb Smirnoff 	struct servent	*s;
72083b3a8eb9SGleb Smirnoff 	u_long		 ulval;
72093b3a8eb9SGleb Smirnoff 
72103b3a8eb9SGleb Smirnoff 	if (atoul(n, &ulval) == 0) {
72113b3a8eb9SGleb Smirnoff 		if (ulval > 65535) {
72123b3a8eb9SGleb Smirnoff 			yyerror("illegal port value %lu", ulval);
72133b3a8eb9SGleb Smirnoff 			return (-1);
72143b3a8eb9SGleb Smirnoff 		}
72153b3a8eb9SGleb Smirnoff 		return (htons(ulval));
72163b3a8eb9SGleb Smirnoff 	} else {
72173b3a8eb9SGleb Smirnoff 		s = getservbyname(n, "tcp");
72183b3a8eb9SGleb Smirnoff 		if (s == NULL)
72193b3a8eb9SGleb Smirnoff 			s = getservbyname(n, "udp");
72200bd4a683SKristof Provost 		if (s == NULL)
72210bd4a683SKristof Provost 			s = getservbyname(n, "sctp");
72223b3a8eb9SGleb Smirnoff 		if (s == NULL) {
72233b3a8eb9SGleb Smirnoff 			yyerror("unknown port %s", n);
72243b3a8eb9SGleb Smirnoff 			return (-1);
72253b3a8eb9SGleb Smirnoff 		}
72263b3a8eb9SGleb Smirnoff 		return (s->s_port);
72273b3a8eb9SGleb Smirnoff 	}
72283b3a8eb9SGleb Smirnoff }
72293b3a8eb9SGleb Smirnoff 
72303b3a8eb9SGleb Smirnoff int
72316fcc8e04SKristof Provost rule_label(struct pfctl_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT])
72323b3a8eb9SGleb Smirnoff {
72336fcc8e04SKristof Provost 	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
72346fcc8e04SKristof Provost 		if (s[i] == NULL)
72356fcc8e04SKristof Provost 			return (0);
72366fcc8e04SKristof Provost 
72376fcc8e04SKristof Provost 		if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >=
72386fcc8e04SKristof Provost 		    sizeof(r->label[0])) {
72393b3a8eb9SGleb Smirnoff 			yyerror("rule label too long (max %d chars)",
72406fcc8e04SKristof Provost 			    sizeof(r->label[0])-1);
72413b3a8eb9SGleb Smirnoff 			return (-1);
72423b3a8eb9SGleb Smirnoff 		}
72433b3a8eb9SGleb Smirnoff 	}
72443b3a8eb9SGleb Smirnoff 	return (0);
72453b3a8eb9SGleb Smirnoff }
72463b3a8eb9SGleb Smirnoff 
7247ef661d4aSChristian McDonald int
7248ef661d4aSChristian McDonald eth_rule_label(struct pfctl_eth_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT])
7249ef661d4aSChristian McDonald {
7250ef661d4aSChristian McDonald 	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
7251ef661d4aSChristian McDonald 		if (s[i] == NULL)
7252ef661d4aSChristian McDonald 			return (0);
7253ef661d4aSChristian McDonald 
7254ef661d4aSChristian McDonald 		if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >=
7255ef661d4aSChristian McDonald 		    sizeof(r->label[0])) {
7256ef661d4aSChristian McDonald 			yyerror("rule label too long (max %d chars)",
7257ef661d4aSChristian McDonald 			    sizeof(r->label[0])-1);
7258ef661d4aSChristian McDonald 			return (-1);
7259ef661d4aSChristian McDonald 		}
7260ef661d4aSChristian McDonald 	}
7261ef661d4aSChristian McDonald 	return (0);
7262ef661d4aSChristian McDonald }
7263ef661d4aSChristian McDonald 
72643b3a8eb9SGleb Smirnoff u_int16_t
72653b3a8eb9SGleb Smirnoff parseicmpspec(char *w, sa_family_t af)
72663b3a8eb9SGleb Smirnoff {
72673b3a8eb9SGleb Smirnoff 	const struct icmpcodeent	*p;
72683b3a8eb9SGleb Smirnoff 	u_long				 ulval;
72693b3a8eb9SGleb Smirnoff 	u_int8_t			 icmptype;
72703b3a8eb9SGleb Smirnoff 
72713b3a8eb9SGleb Smirnoff 	if (af == AF_INET)
72723b3a8eb9SGleb Smirnoff 		icmptype = returnicmpdefault >> 8;
72733b3a8eb9SGleb Smirnoff 	else
72743b3a8eb9SGleb Smirnoff 		icmptype = returnicmp6default >> 8;
72753b3a8eb9SGleb Smirnoff 
72763b3a8eb9SGleb Smirnoff 	if (atoul(w, &ulval) == -1) {
72773b3a8eb9SGleb Smirnoff 		if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
72783b3a8eb9SGleb Smirnoff 			yyerror("unknown icmp code %s", w);
72793b3a8eb9SGleb Smirnoff 			return (0);
72803b3a8eb9SGleb Smirnoff 		}
72813b3a8eb9SGleb Smirnoff 		ulval = p->code;
72823b3a8eb9SGleb Smirnoff 	}
72833b3a8eb9SGleb Smirnoff 	if (ulval > 255) {
72843b3a8eb9SGleb Smirnoff 		yyerror("invalid icmp code %lu", ulval);
72853b3a8eb9SGleb Smirnoff 		return (0);
72863b3a8eb9SGleb Smirnoff 	}
72873b3a8eb9SGleb Smirnoff 	return (icmptype << 8 | ulval);
72883b3a8eb9SGleb Smirnoff }
72893b3a8eb9SGleb Smirnoff 
72903b3a8eb9SGleb Smirnoff int
72913b3a8eb9SGleb Smirnoff parseport(char *port, struct range *r, int extensions)
72923b3a8eb9SGleb Smirnoff {
72933b3a8eb9SGleb Smirnoff 	char	*p = strchr(port, ':');
72943b3a8eb9SGleb Smirnoff 
72953b3a8eb9SGleb Smirnoff 	if (p == NULL) {
72963b3a8eb9SGleb Smirnoff 		if ((r->a = getservice(port)) == -1)
72973b3a8eb9SGleb Smirnoff 			return (-1);
72983b3a8eb9SGleb Smirnoff 		r->b = 0;
72993b3a8eb9SGleb Smirnoff 		r->t = PF_OP_NONE;
73003b3a8eb9SGleb Smirnoff 		return (0);
73013b3a8eb9SGleb Smirnoff 	}
73023b3a8eb9SGleb Smirnoff 	if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
73033b3a8eb9SGleb Smirnoff 		*p = 0;
73043b3a8eb9SGleb Smirnoff 		if ((r->a = getservice(port)) == -1)
73053b3a8eb9SGleb Smirnoff 			return (-1);
73063b3a8eb9SGleb Smirnoff 		r->b = 0;
73073b3a8eb9SGleb Smirnoff 		r->t = PF_OP_IRG;
73083b3a8eb9SGleb Smirnoff 		return (0);
73093b3a8eb9SGleb Smirnoff 	}
73103b3a8eb9SGleb Smirnoff 	if ((extensions & PPORT_RANGE)) {
73113b3a8eb9SGleb Smirnoff 		*p++ = 0;
73123b3a8eb9SGleb Smirnoff 		if ((r->a = getservice(port)) == -1 ||
73133b3a8eb9SGleb Smirnoff 		    (r->b = getservice(p)) == -1)
73143b3a8eb9SGleb Smirnoff 			return (-1);
73153b3a8eb9SGleb Smirnoff 		if (r->a == r->b) {
73163b3a8eb9SGleb Smirnoff 			r->b = 0;
73173b3a8eb9SGleb Smirnoff 			r->t = PF_OP_NONE;
73183b3a8eb9SGleb Smirnoff 		} else
73193b3a8eb9SGleb Smirnoff 			r->t = PF_OP_RRG;
73203b3a8eb9SGleb Smirnoff 		return (0);
73213b3a8eb9SGleb Smirnoff 	}
73223b3a8eb9SGleb Smirnoff 	return (-1);
73233b3a8eb9SGleb Smirnoff }
73243b3a8eb9SGleb Smirnoff 
73253b3a8eb9SGleb Smirnoff int
73263b3a8eb9SGleb Smirnoff pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
73273b3a8eb9SGleb Smirnoff {
73283b3a8eb9SGleb Smirnoff 	struct loadanchors	*la;
73293b3a8eb9SGleb Smirnoff 
73303b3a8eb9SGleb Smirnoff 	TAILQ_FOREACH(la, &loadanchorshead, entries) {
73313b3a8eb9SGleb Smirnoff 		if (pf->opts & PF_OPT_VERBOSE)
73323b3a8eb9SGleb Smirnoff 			fprintf(stderr, "\nLoading anchor %s from %s\n",
73333b3a8eb9SGleb Smirnoff 			    la->anchorname, la->filename);
73343b3a8eb9SGleb Smirnoff 		if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
73353b3a8eb9SGleb Smirnoff 		    la->anchorname, trans) == -1)
73363b3a8eb9SGleb Smirnoff 			return (-1);
73373b3a8eb9SGleb Smirnoff 	}
73383b3a8eb9SGleb Smirnoff 
73393b3a8eb9SGleb Smirnoff 	return (0);
73403b3a8eb9SGleb Smirnoff }
73413b3a8eb9SGleb Smirnoff 
73423b3a8eb9SGleb Smirnoff int
73431f495578SKristof Provost kw_casecmp(const void *k, const void *e)
73441f495578SKristof Provost {
73451f495578SKristof Provost 	return (strcasecmp(k, ((const struct keywords *)e)->k_name));
73461f495578SKristof Provost }
73471f495578SKristof Provost 
73481f495578SKristof Provost int
73491f495578SKristof Provost map_tos(char *s, int *val)
73501f495578SKristof Provost {
73511f495578SKristof Provost 	/* DiffServ Codepoints and other TOS mappings */
73521f495578SKristof Provost 	const struct keywords	 toswords[] = {
73531f495578SKristof Provost 		{ "af11",		IPTOS_DSCP_AF11 },
73541f495578SKristof Provost 		{ "af12",		IPTOS_DSCP_AF12 },
73551f495578SKristof Provost 		{ "af13",		IPTOS_DSCP_AF13 },
73561f495578SKristof Provost 		{ "af21",		IPTOS_DSCP_AF21 },
73571f495578SKristof Provost 		{ "af22",		IPTOS_DSCP_AF22 },
73581f495578SKristof Provost 		{ "af23",		IPTOS_DSCP_AF23 },
73591f495578SKristof Provost 		{ "af31",		IPTOS_DSCP_AF31 },
73601f495578SKristof Provost 		{ "af32",		IPTOS_DSCP_AF32 },
73611f495578SKristof Provost 		{ "af33",		IPTOS_DSCP_AF33 },
73621f495578SKristof Provost 		{ "af41",		IPTOS_DSCP_AF41 },
73631f495578SKristof Provost 		{ "af42",		IPTOS_DSCP_AF42 },
73641f495578SKristof Provost 		{ "af43",		IPTOS_DSCP_AF43 },
73651f495578SKristof Provost 		{ "critical",		IPTOS_PREC_CRITIC_ECP },
73661f495578SKristof Provost 		{ "cs0",		IPTOS_DSCP_CS0 },
73671f495578SKristof Provost 		{ "cs1",		IPTOS_DSCP_CS1 },
73681f495578SKristof Provost 		{ "cs2",		IPTOS_DSCP_CS2 },
73691f495578SKristof Provost 		{ "cs3",		IPTOS_DSCP_CS3 },
73701f495578SKristof Provost 		{ "cs4",		IPTOS_DSCP_CS4 },
73711f495578SKristof Provost 		{ "cs5",		IPTOS_DSCP_CS5 },
73721f495578SKristof Provost 		{ "cs6",		IPTOS_DSCP_CS6 },
73731f495578SKristof Provost 		{ "cs7",		IPTOS_DSCP_CS7 },
73741f495578SKristof Provost 		{ "ef",			IPTOS_DSCP_EF },
73751f495578SKristof Provost 		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
73761f495578SKristof Provost 		{ "lowdelay",		IPTOS_LOWDELAY },
73771f495578SKristof Provost 		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
73781f495578SKristof Provost 		{ "reliability",	IPTOS_RELIABILITY },
7379b4e3f3c2SKristof Provost 		{ "throughput",		IPTOS_THROUGHPUT },
7380b4e3f3c2SKristof Provost 		{ "va",			IPTOS_DSCP_VA }
73811f495578SKristof Provost 	};
73821f495578SKristof Provost 	const struct keywords	*p;
73831f495578SKristof Provost 
73841f495578SKristof Provost 	p = bsearch(s, toswords, sizeof(toswords)/sizeof(toswords[0]),
73851f495578SKristof Provost 	    sizeof(toswords[0]), kw_casecmp);
73861f495578SKristof Provost 
73871f495578SKristof Provost 	if (p) {
73881f495578SKristof Provost 		*val = p->k_val;
73891f495578SKristof Provost 		return (1);
73901f495578SKristof Provost 	}
73911f495578SKristof Provost 	return (0);
73921f495578SKristof Provost }
73931f495578SKristof Provost 
73941f495578SKristof Provost int
73953b3a8eb9SGleb Smirnoff rt_tableid_max(void)
73963b3a8eb9SGleb Smirnoff {
73973b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
73983b3a8eb9SGleb Smirnoff 	int fibs;
73993b3a8eb9SGleb Smirnoff 	size_t l = sizeof(fibs);
74003b3a8eb9SGleb Smirnoff 
74013b3a8eb9SGleb Smirnoff         if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
74023b3a8eb9SGleb Smirnoff 		fibs = 16;	/* XXX RT_MAXFIBS, at least limit it some. */
74033b3a8eb9SGleb Smirnoff 	/*
74043b3a8eb9SGleb Smirnoff 	 * As the OpenBSD code only compares > and not >= we need to adjust
74053b3a8eb9SGleb Smirnoff 	 * here given we only accept values of 0..n and want to avoid #ifdefs
7406b68ac800SPedro F. Giffuni 	 * in the grammar.
74073b3a8eb9SGleb Smirnoff 	 */
74083b3a8eb9SGleb Smirnoff 	return (fibs - 1);
74093b3a8eb9SGleb Smirnoff #else
74103b3a8eb9SGleb Smirnoff 	return (RT_TABLEID_MAX);
74113b3a8eb9SGleb Smirnoff #endif
74123b3a8eb9SGleb Smirnoff }
7413b590f17aSKristof Provost 
7414b590f17aSKristof Provost struct node_mac*
7415b590f17aSKristof Provost node_mac_from_string(const char *str)
7416b590f17aSKristof Provost {
7417b590f17aSKristof Provost 	struct node_mac *m;
7418b590f17aSKristof Provost 
7419b590f17aSKristof Provost 	m = calloc(1, sizeof(struct node_mac));
7420b590f17aSKristof Provost 	if (m == NULL)
7421b590f17aSKristof Provost 		err(1, "mac: calloc");
7422b590f17aSKristof Provost 
7423b590f17aSKristof Provost 	if (sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
7424b590f17aSKristof Provost 	    &m->mac[0], &m->mac[1], &m->mac[2], &m->mac[3], &m->mac[4],
7425b590f17aSKristof Provost 	    &m->mac[5]) != 6) {
7426b590f17aSKristof Provost 		free(m);
7427b590f17aSKristof Provost 		yyerror("invalid MAC address");
7428b590f17aSKristof Provost 		return (NULL);
7429b590f17aSKristof Provost 	}
7430b590f17aSKristof Provost 
7431b590f17aSKristof Provost 	memset(m->mask, 0xff, ETHER_ADDR_LEN);
7432c32cd180SKristof Provost 	m->isset = true;
7433b590f17aSKristof Provost 	m->next = NULL;
7434b590f17aSKristof Provost 	m->tail = m;
7435b590f17aSKristof Provost 
7436b590f17aSKristof Provost 	return (m);
7437b590f17aSKristof Provost }
7438b590f17aSKristof Provost 
7439b590f17aSKristof Provost struct node_mac*
7440b590f17aSKristof Provost node_mac_from_string_masklen(const char *str, int masklen)
7441b590f17aSKristof Provost {
7442b590f17aSKristof Provost 	struct node_mac *m;
7443b590f17aSKristof Provost 
7444b590f17aSKristof Provost 	if (masklen < 0 || masklen > (ETHER_ADDR_LEN * 8)) {
7445b590f17aSKristof Provost 		yyerror("invalid MAC mask length");
7446b590f17aSKristof Provost 		return (NULL);
7447b590f17aSKristof Provost 	}
7448b590f17aSKristof Provost 
7449b590f17aSKristof Provost 	m = node_mac_from_string(str);
7450b590f17aSKristof Provost 	if (m == NULL)
7451b590f17aSKristof Provost 		return (NULL);
7452b590f17aSKristof Provost 
7453b590f17aSKristof Provost 	memset(m->mask, 0, ETHER_ADDR_LEN);
7454b590f17aSKristof Provost 	for (int i = 0; i < masklen; i++)
7455b590f17aSKristof Provost 		m->mask[i / 8] |= 1 << (i % 8);
7456b590f17aSKristof Provost 
7457b590f17aSKristof Provost 	return (m);
7458b590f17aSKristof Provost }
7459b590f17aSKristof Provost 
7460b590f17aSKristof Provost struct node_mac*
7461b590f17aSKristof Provost node_mac_from_string_mask(const char *str, const char *mask)
7462b590f17aSKristof Provost {
7463b590f17aSKristof Provost 	struct node_mac *m;
7464b590f17aSKristof Provost 
7465b590f17aSKristof Provost 	m = node_mac_from_string(str);
7466b590f17aSKristof Provost 	if (m == NULL)
7467b590f17aSKristof Provost 		return (NULL);
7468b590f17aSKristof Provost 
7469b590f17aSKristof Provost 	if (sscanf(mask, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
7470b590f17aSKristof Provost 	    &m->mask[0], &m->mask[1], &m->mask[2], &m->mask[3], &m->mask[4],
7471b590f17aSKristof Provost 	    &m->mask[5]) != 6) {
7472b590f17aSKristof Provost 		free(m);
7473b590f17aSKristof Provost 		yyerror("invalid MAC mask");
7474b590f17aSKristof Provost 		return (NULL);
7475b590f17aSKristof Provost 	}
7476b590f17aSKristof Provost 
7477b590f17aSKristof Provost 	return (m);
7478b590f17aSKristof Provost }
7479